summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/wil6210
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/wil6210')
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c331
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c30
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c7
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c16
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h2
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h17
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c49
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h4
12 files changed, 328 insertions, 147 deletions
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 4ac2c208c9ba..a00f31881df9 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
@@ -311,8 +311,10 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
- if (rc)
+ if (rc) {
+ del_timer_sync(&wil->scan_timer);
wil->scan_request = NULL;
+ }
return rc;
}
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 8f66186adb8c..b1c6a7293390 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
@@ -22,6 +22,7 @@
#include <linux/power_supply.h>
#include "wil6210.h"
+#include "wmi.h"
#include "txrx.h"
/* Nasty hack. Better have per device instances */
@@ -29,6 +30,21 @@ static u32 mem_addr;
static u32 dbg_txdesc_index;
static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
+enum dbg_off_type {
+ doff_u32 = 0,
+ doff_x32 = 1,
+ doff_ulong = 2,
+ doff_io32 = 3,
+};
+
+/* offset to "wil" */
+struct dbg_off {
+ const char *name;
+ umode_t mode;
+ ulong off;
+ enum dbg_off_type type;
+};
+
static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
const char *name, struct vring *vring,
char _s, char _h)
@@ -244,9 +260,9 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
umode_t mode,
struct dentry *parent,
- void __iomem *value)
+ void *value)
{
- return debugfs_create_file(name, mode, parent, (void * __force)value,
+ return debugfs_create_file(name, mode, parent, value,
&fops_iomem_x32);
}
@@ -270,6 +286,59 @@ static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
}
+/**
+ * wil6210_debugfs_init_offset - create set of debugfs files
+ * @wil - driver's context, used for printing
+ * @dbg - directory on the debugfs, where files will be created
+ * @base - base address used in address calculation
+ * @tbl - table with file descriptions. Should be terminated with empty element.
+ *
+ * Creates files accordingly to the @tbl.
+ */
+static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
+ struct dentry *dbg, void *base,
+ const struct dbg_off * const tbl)
+{
+ int i;
+
+ for (i = 0; tbl[i].name; i++) {
+ struct dentry *f = NULL;
+
+ switch (tbl[i].type) {
+ case doff_u32:
+ f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
+ base + tbl[i].off);
+ break;
+ case doff_x32:
+ f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
+ base + tbl[i].off);
+ break;
+ case doff_ulong:
+ f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
+ dbg, base + tbl[i].off);
+ break;
+ case doff_io32:
+ f = wil_debugfs_create_iomem_x32(tbl[i].name,
+ tbl[i].mode, dbg,
+ base + tbl[i].off);
+ break;
+ }
+ if (IS_ERR_OR_NULL(f))
+ wil_err(wil, "Create file \"%s\": err %ld\n",
+ tbl[i].name, PTR_ERR(f));
+ }
+}
+
+static const struct dbg_off isr_off[] = {
+ {"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
+ {"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
+ {"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
+ {"ICS", S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
+ {"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
+ {"IMS", S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
+ {"IMC", S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
+ {},
+};
static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
const char *name,
struct dentry *parent, u32 off)
@@ -279,24 +348,19 @@ static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
if (IS_ERR_OR_NULL(d))
return -ENODEV;
- wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d,
- wil->csr + off);
- wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d,
- wil->csr + off + 4);
- wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d,
- wil->csr + off + 8);
- wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d,
- wil->csr + off + 12);
- wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d,
- wil->csr + off + 16);
- wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d,
- wil->csr + off + 20);
- wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d,
- wil->csr + off + 24);
+ wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
+ isr_off);
return 0;
}
+static const struct dbg_off pseudo_isr_off[] = {
+ {"CAUSE", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
+ {"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
+ {"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
struct dentry *parent)
{
@@ -305,16 +369,19 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
if (IS_ERR_OR_NULL(d))
return -ENODEV;
- wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr +
- HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
- wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr +
- HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
- wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr +
- HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW));
+ wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+ pseudo_isr_off);
return 0;
}
+static const struct dbg_off itr_cnt_off[] = {
+ {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
+ {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
+ {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
struct dentry *parent)
{
@@ -323,12 +390,8 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
if (IS_ERR_OR_NULL(d))
return -ENODEV;
- wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr +
- HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
- wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr +
- HOSTADDR(RGF_DMA_ITR_CNT_DATA));
- wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr +
- HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+ wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+ itr_cnt_off);
return 0;
}
@@ -666,16 +729,79 @@ static const struct file_operations fops_txdesc = {
};
/*---------beamforming------------*/
+static char *wil_bfstatus_str(u32 status)
+{
+ switch (status) {
+ case 0:
+ return "Failed";
+ case 1:
+ return "OK";
+ case 2:
+ return "Retrying";
+ default:
+ return "??";
+ }
+}
+
+static bool is_all_zeros(void * const x_, size_t sz)
+{
+ /* if reply is all-0, ignore this CID */
+ u32 *x = x_;
+ int n;
+
+ for (n = 0; n < sz / sizeof(*x); n++)
+ if (x[n])
+ return false;
+
+ return true;
+}
+
static int wil_bf_debugfs_show(struct seq_file *s, void *data)
{
+ int rc;
+ int i;
struct wil6210_priv *wil = s->private;
- seq_printf(s,
- "TSF : 0x%016llx\n"
- "TxMCS : %d\n"
- "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n",
- wil->stats.tsf, wil->stats.bf_mcs,
- wil->stats.my_rx_sector, wil->stats.my_tx_sector,
- wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
+ struct wmi_notify_req_cmd cmd = {
+ .interval_usec = 0,
+ };
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_notify_req_done_event evt;
+ } __packed reply;
+
+ for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+ u32 status;
+
+ cmd.cid = i;
+ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
+ WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
+ sizeof(reply), 20);
+ /* if reply is all-0, ignore this CID */
+ if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
+ continue;
+
+ status = le32_to_cpu(reply.evt.status);
+ seq_printf(s, "CID %d {\n"
+ " TSF = 0x%016llx\n"
+ " TxMCS = %2d TxTpt = %4d\n"
+ " SQI = %4d\n"
+ " Status = 0x%08x %s\n"
+ " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
+ " Goodput(rx:tx) %4d:%4d\n"
+ "}\n",
+ i,
+ le64_to_cpu(reply.evt.tsf),
+ le16_to_cpu(reply.evt.bf_mcs),
+ le32_to_cpu(reply.evt.tx_tpt),
+ reply.evt.sqi,
+ status, wil_bfstatus_str(status),
+ le16_to_cpu(reply.evt.my_rx_sector),
+ le16_to_cpu(reply.evt.my_tx_sector),
+ le16_to_cpu(reply.evt.other_rx_sector),
+ le16_to_cpu(reply.evt.other_tx_sector),
+ le32_to_cpu(reply.evt.rx_goodput),
+ le32_to_cpu(reply.evt.tx_goodput));
+ }
return 0;
}
@@ -985,6 +1111,87 @@ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
}
}
+/* misc files */
+static const struct {
+ const char *name;
+ umode_t mode;
+ const struct file_operations *fops;
+} dbg_files[] = {
+ {"mbox", S_IRUGO, &fops_mbox},
+ {"vrings", S_IRUGO, &fops_vring},
+ {"stations", S_IRUGO, &fops_sta},
+ {"desc", S_IRUGO, &fops_txdesc},
+ {"bf", S_IRUGO, &fops_bf},
+ {"ssid", S_IRUGO | S_IWUSR, &fops_ssid},
+ {"mem_val", S_IRUGO, &fops_memread},
+ {"reset", S_IWUSR, &fops_reset},
+ {"rxon", S_IWUSR, &fops_rxon},
+ {"tx_mgmt", S_IWUSR, &fops_txmgmt},
+ {"wmi_send", S_IWUSR, &fops_wmi},
+ {"temp", S_IRUGO, &fops_temp},
+ {"freq", S_IRUGO, &fops_freq},
+ {"link", S_IRUGO, &fops_link},
+ {"info", S_IRUGO, &fops_info},
+};
+
+static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
+ struct dentry *dbg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
+ debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
+ wil, dbg_files[i].fops);
+}
+
+/* interrupt control blocks */
+static const struct {
+ const char *name;
+ u32 icr_off;
+} dbg_icr[] = {
+ {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR)},
+ {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR)},
+ {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR)},
+ {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR)},
+};
+
+static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
+ struct dentry *dbg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
+ wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
+ dbg_icr[i].icr_off);
+}
+
+#define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
+ offsetof(struct wil6210_priv, name), type}
+
+/* fields in struct wil6210_priv */
+static const struct dbg_off dbg_wil_off[] = {
+ WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32),
+ WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong),
+ WIL_FIELD(fw_version, S_IRUGO, doff_u32),
+ WIL_FIELD(hw_version, S_IRUGO, doff_x32),
+ {},
+};
+
+static const struct dbg_off dbg_wil_regs[] = {
+ {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
+ doff_io32},
+ {"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
+ {},
+};
+
+/* static parameters */
+static const struct dbg_off dbg_statics[] = {
+ {"desc_index", S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
+ {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
+ {"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
+ {},
+};
+
int wil6210_debugfs_init(struct wil6210_priv *wil)
{
struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
@@ -993,51 +1200,17 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
if (IS_ERR_OR_NULL(dbg))
return -ENODEV;
- debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
- debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
- debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
- debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
- debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
- &dbg_txdesc_index);
- debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg,
- &dbg_vring_index);
-
- debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
- debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
- debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
- &wil->secure_pcp);
- wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg,
- &wil->status);
- debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version);
- debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version);
-
- wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
- HOSTADDR(RGF_USER_USER_ICR));
- wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg,
- HOSTADDR(RGF_DMA_EP_TX_ICR));
- wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg,
- HOSTADDR(RGF_DMA_EP_RX_ICR));
- wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg,
- HOSTADDR(RGF_DMA_EP_MISC_ICR));
- wil6210_debugfs_create_pseudo_ISR(wil, dbg);
- wil6210_debugfs_create_ITR_CNT(wil, dbg);
+ wil6210_debugfs_init_files(wil, dbg);
+ wil6210_debugfs_init_isr(wil, dbg);
+ wil6210_debugfs_init_blobs(wil, dbg);
+ wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
+ wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
+ dbg_wil_regs);
+ wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
- wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg,
- wil->csr +
- HOSTADDR(RGF_USER_USAGE_1));
- debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr);
- debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
-
- debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
- debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon);
- debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt);
- debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi);
- debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp);
- debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq);
- debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link);
- debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info);
+ wil6210_debugfs_create_pseudo_ISR(wil, dbg);
- wil6210_debugfs_init_blobs(wil, dbg);
+ wil6210_debugfs_create_ITR_CNT(wil, dbg);
return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 67f1002a03a1..98bfbb6390b7 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 3704d2a434f3..b69d90f0716f 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
@@ -25,6 +25,9 @@ static bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
+#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
+#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
+
/*
* Due to a hardware issue,
* one has to read/write to/from NIC in 32-bit chunks;
@@ -309,7 +312,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
destroy_workqueue(wil->wmi_wq);
}
-static void wil_target_reset(struct wil6210_priv *wil)
+static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
u32 hw_state;
@@ -327,6 +330,8 @@ static void wil_target_reset(struct wil6210_priv *wil)
/* register clear = read, AND with inverted, write */
#define C(a, v) W(a, R(a) & ~v)
+ wmb(); /* If host reorder writes here -> race in NIC */
+ W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
wil->hw_version = R(RGF_USER_FW_REV_ID);
rev_id = wil->hw_version & 0xff;
@@ -343,8 +348,9 @@ static void wil_target_reset(struct wil6210_priv *wil)
wmb(); /* order is important here */
}
- W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
+ wmb(); /* If host reorder writes here -> race in NIC */
+ W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
wmb(); /* order is important here */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
@@ -385,14 +391,14 @@ static void wil_target_reset(struct wil6210_priv *wil)
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
wmb(); /* order is important here */
- /* wait until device ready */
+ /* wait until device ready. typical time is 200..250 msec */
do {
- msleep(1);
+ msleep(RST_DELAY);
hw_state = R(RGF_USER_HW_MACHINE_STATE);
- if (delay++ > 100) {
+ if (delay++ > RST_COUNT) {
wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
hw_state);
- return;
+ return -ETIME;
}
} while (hw_state != HW_MACHINE_BOOT_DONE);
@@ -403,7 +409,8 @@ static void wil_target_reset(struct wil6210_priv *wil)
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
wmb(); /* order is important here */
- wil_dbg_misc(wil, "Reset completed in %d ms\n", delay);
+ wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
+ return 0;
#undef R
#undef W
@@ -468,10 +475,11 @@ int wil_reset(struct wil6210_priv *wil)
flush_workqueue(wil->wmi_wq_conn);
flush_workqueue(wil->wmi_wq);
- /* TODO: put MAC in reset */
- wil_target_reset(wil);
-
+ rc = wil_target_reset(wil);
wil_rx_fini(wil);
+ if (rc)
+ return rc;
+
/* init after reset */
wil->pending_connect_cid = -1;
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 7afce6e8c507..a44c2b61be08 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
@@ -168,11 +168,15 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
void wil_if_free(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
+
if (!ndev)
return;
- free_netdev(ndev);
wil_priv_deinit(wil);
+
+ wil_to_ndev(wil) = NULL;
+ free_netdev(ndev);
+
wil_wdev_free(wil);
}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index d3fbfa28db62..38dcbea49d44 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
@@ -218,12 +218,13 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
static void wil_pcie_remove(struct pci_dev *pdev)
{
struct wil6210_priv *wil = pci_get_drvdata(pdev);
+ void __iomem *csr = wil->csr;
wil6210_debugfs_remove(wil);
wil_if_pcie_disable(wil);
wil_if_remove(wil);
wil_if_free(wil);
- pci_iounmap(pdev, wil->csr);
+ pci_iounmap(pdev, csr);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
}
@@ -243,6 +244,8 @@ static const struct pci_device_id wil6210_pcie_ids[] = {
.driver_data = (kernel_ulong_t)&wil_board_marlon },
{ PCI_DEVICE(0x1ae9, 0x0310),
.driver_data = (kernel_ulong_t)&wil_board_sparrow },
+ { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
+ .driver_data = (kernel_ulong_t)&wil_board_sparrow },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 180ca4793904..97c6a24716a1 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2014 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 "wil6210.h"
#include "txrx.h"
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index d3467943d39d..9bd920d272bb 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
@@ -414,7 +414,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
cid = wil_rxdesc_cid(d);
stats = &wil->sta[cid].stats;
stats->last_mcs_rx = wil_rxdesc_mcs(d);
- wil->stats.last_mcs_rx = stats->last_mcs_rx;
/* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index bc5706a4f007..a1ac4f87d47b 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 67e9624f7111..f8718fe547c4 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
@@ -133,6 +133,9 @@ struct RGF_ICR {
#define RGF_HP_CTRL (0x88265c)
#define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4)
+/* MAC timer, usec, for packet lifetime */
+#define RGF_MAC_MTRL_COUNTER_0 (0x886aa8)
+
/* popular locations */
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@ -327,17 +330,6 @@ struct wil_tid_ampdu_rx {
bool first_time; /* is it 1-st time this buffer used? */
};
-struct wil6210_stats {
- u64 tsf;
- u32 snr;
- u16 last_mcs_rx;
- u16 bf_mcs; /* last BF, used for Tx */
- u16 my_rx_sector;
- u16 my_tx_sector;
- u16 peer_rx_sector;
- u16 peer_tx_sector;
-};
-
enum wil_sta_status {
wil_sta_unused = 0,
wil_sta_conn_pending = 1,
@@ -430,7 +422,6 @@ struct wil6210_priv {
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
/* statistics */
- struct wil6210_stats stats;
atomic_t isr_count_rx, isr_count_tx;
/* debugfs */
struct dentry *debug;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 1d1d0afdd2e1..b1aaaee997d5 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 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
@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/moduleparam.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
@@ -22,6 +23,10 @@
#include "wmi.h"
#include "trace.h"
+static uint max_assoc_sta = 1;
+module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
+
/**
* WMI event receiving - theory of operations
*
@@ -346,11 +351,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
rx_mgmt_frame->bssid);
cfg80211_put_bss(wiphy, bss);
} else {
- wil_err(wil, "cfg80211_inform_bss() failed\n");
+ wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
}
} else {
cfg80211_rx_mgmt(wil->wdev, freq, signal,
- (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL);
+ (void *)rx_mgmt_frame, d_len, 0);
}
}
@@ -482,33 +487,6 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
mutex_unlock(&wil->mutex);
}
-static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
-{
- struct wmi_notify_req_done_event *evt = d;
-
- if (len < sizeof(*evt)) {
- wil_err(wil, "Short NOTIFY event\n");
- return;
- }
-
- wil->stats.tsf = le64_to_cpu(evt->tsf);
- wil->stats.snr = le32_to_cpu(evt->snr_val);
- wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs);
- wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector);
- wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
- wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
- wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
- wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
- "BF status 0x%08x SNR 0x%08x SQI %d%%\n"
- "Tx Tpt %d goodput %d Rx goodput %d\n"
- "Sectors(rx:tx) my %d:%d peer %d:%d\n",
- wil->stats.bf_mcs, wil->stats.tsf, evt->status,
- wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt),
- le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
- wil->stats.my_rx_sector, wil->stats.my_tx_sector,
- wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
-}
-
/*
* Firmware reports EAPOL frame using WME event.
* Reconstruct Ethernet frame and deliver it via normal Rx
@@ -651,7 +629,6 @@ static const struct {
{WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
{WMI_CONNECT_EVENTID, wmi_evt_connect},
{WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
- {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify},
{WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
{WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
@@ -822,7 +799,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
.network_type = wmi_nettype,
.disable_sec_offload = 1,
.channel = chan - 1,
- .pcp_max_assoc_sta = WIL6210_MAX_CID,
+ .pcp_max_assoc_sta = max_assoc_sta,
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -832,6 +809,14 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
if (!wil->secure_pcp)
cmd.disable_sec = 1;
+ if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
+ (cmd.pcp_max_assoc_sta <= 0)) {
+ wil_info(wil,
+ "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
+ max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID);
+ cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
+ }
+
/*
* Processing time may be huge, in case of secure AP it takes about
* 3500ms for FW to start AP
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 17334c852866..061618cee9f6 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
* Copyright (c) 2006-2012 Wilocity .
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -980,7 +980,7 @@ struct wmi_ready_event {
* WMI_NOTIFY_REQ_DONE_EVENTID
*/
struct wmi_notify_req_done_event {
- __le32 status;
+ __le32 status; /* beamforming status, 0: fail; 1: OK; 2: retrying */
__le64 tsf;
__le32 snr_val;
__le32 tx_tpt;