2012-12-21 04:13:19 +07:00
|
|
|
/*
|
2014-08-06 14:31:51 +07:00
|
|
|
* Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
|
2012-12-21 04:13:19 +07:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2014-08-06 14:31:58 +07:00
|
|
|
#include <linux/moduleparam.h>
|
2012-12-21 04:13:19 +07:00
|
|
|
#include <linux/etherdevice.h>
|
2013-01-28 23:30:59 +07:00
|
|
|
#include <linux/if_arp.h>
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
#include "wil6210.h"
|
2013-01-28 23:30:59 +07:00
|
|
|
#include "txrx.h"
|
2012-12-21 04:13:19 +07:00
|
|
|
#include "wmi.h"
|
2013-05-12 18:43:35 +07:00
|
|
|
#include "trace.h"
|
2012-12-21 04:13:19 +07:00
|
|
|
|
2014-12-23 14:47:13 +07:00
|
|
|
static uint max_assoc_sta = WIL6210_MAX_CID;
|
2014-08-06 14:31:58 +07:00
|
|
|
module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
|
|
|
|
MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
|
|
|
|
|
2014-12-23 14:47:05 +07:00
|
|
|
int agg_wsize; /* = 0; */
|
|
|
|
module_param(agg_wsize, int, S_IRUGO | S_IWUSR);
|
|
|
|
MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
|
|
|
|
" 0 - use default; < 0 - don't auto-establish");
|
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
/**
|
|
|
|
* WMI event receiving - theory of operations
|
|
|
|
*
|
|
|
|
* When firmware about to report WMI event, it fills memory area
|
|
|
|
* in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for
|
|
|
|
* the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler.
|
|
|
|
*
|
|
|
|
* @wmi_recv_cmd reads event, allocates memory chunk and attaches it to the
|
|
|
|
* event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up
|
|
|
|
* and handles events within the @wmi_event_worker. Every event get detached
|
|
|
|
* from list, processed and deleted.
|
|
|
|
*
|
|
|
|
* Purpose for this mechanism is to release IRQ thread; otherwise,
|
|
|
|
* if WMI event handling involves another WMI command flow, this 2-nd flow
|
|
|
|
* won't be completed because of blocked IRQ thread.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Addressing - theory of operations
|
|
|
|
*
|
|
|
|
* There are several buses present on the WIL6210 card.
|
|
|
|
* Same memory areas are visible at different address on
|
|
|
|
* the different busses. There are 3 main bus masters:
|
|
|
|
* - MAC CPU (ucode)
|
|
|
|
* - User CPU (firmware)
|
|
|
|
* - AHB (host)
|
|
|
|
*
|
|
|
|
* On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
|
|
|
|
* AHB addresses starting from 0x880000
|
|
|
|
*
|
|
|
|
* Internally, firmware uses addresses that allows faster access but
|
|
|
|
* are invisible from the host. To read from these addresses, alternative
|
|
|
|
* AHB address must be used.
|
|
|
|
*
|
|
|
|
* Memory mapping
|
|
|
|
* Linker address PCI/Host address
|
|
|
|
* 0x880000 .. 0xa80000 2Mb BAR0
|
|
|
|
* 0x800000 .. 0x807000 0x900000 .. 0x907000 28k DCCM
|
|
|
|
* 0x840000 .. 0x857000 0x908000 .. 0x91f000 92k PERIPH
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @fw_mapping provides memory remapping table
|
2014-07-14 13:49:41 +07:00
|
|
|
*
|
|
|
|
* array size should be in sync with the declaration in the wil6210.h
|
2012-12-21 04:13:19 +07:00
|
|
|
*/
|
2014-07-14 13:49:41 +07:00
|
|
|
const struct fw_map fw_mapping[] = {
|
|
|
|
{0x000000, 0x040000, 0x8c0000, "fw_code"}, /* FW code RAM 256k */
|
|
|
|
{0x800000, 0x808000, 0x900000, "fw_data"}, /* FW data RAM 32k */
|
|
|
|
{0x840000, 0x860000, 0x908000, "fw_peri"}, /* periph. data RAM 128k */
|
|
|
|
{0x880000, 0x88a000, 0x880000, "rgf"}, /* various RGF 40k */
|
2014-07-14 13:49:43 +07:00
|
|
|
{0x88a000, 0x88b000, 0x88a000, "AGC_tbl"}, /* AGC table 4k */
|
2014-07-14 13:49:41 +07:00
|
|
|
{0x88b000, 0x88c000, 0x88b000, "rgf_ext"}, /* Pcie_ext_rgf 4k */
|
|
|
|
{0x8c0000, 0x949000, 0x8c0000, "upper"}, /* upper area 548k */
|
2012-12-21 04:13:19 +07:00
|
|
|
/*
|
|
|
|
* 920000..930000 ucode code RAM
|
|
|
|
* 930000..932000 ucode data RAM
|
2013-06-09 13:12:51 +07:00
|
|
|
* 932000..949000 back-door debug data
|
2012-12-21 04:13:19 +07:00
|
|
|
*/
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* return AHB address for given firmware/ucode internal (linker) address
|
|
|
|
* @x - internal address
|
|
|
|
* If address have no valid AHB mapping, return 0
|
|
|
|
*/
|
|
|
|
static u32 wmi_addr_remap(u32 x)
|
|
|
|
{
|
|
|
|
uint i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
|
|
|
|
if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to))
|
|
|
|
return x + fw_mapping[i].host - fw_mapping[i].from;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check address validity for WMI buffer; remap if needed
|
|
|
|
* @ptr - internal (linker) fw/ucode address
|
|
|
|
*
|
|
|
|
* Valid buffer should be DWORD aligned
|
|
|
|
*
|
|
|
|
* return address for accessing buffer from the host;
|
|
|
|
* if buffer is not valid, return NULL.
|
|
|
|
*/
|
|
|
|
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
|
|
|
|
{
|
|
|
|
u32 off;
|
|
|
|
u32 ptr = le32_to_cpu(ptr_);
|
|
|
|
|
|
|
|
if (ptr % 4)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ptr = wmi_addr_remap(ptr);
|
|
|
|
if (ptr < WIL6210_FW_HOST_OFF)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
off = HOSTADDR(ptr);
|
|
|
|
if (off > WIL6210_MEM_SIZE - 4)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return wil->csr + off;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check address validity
|
|
|
|
*/
|
|
|
|
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
|
|
|
|
{
|
|
|
|
u32 off;
|
|
|
|
|
|
|
|
if (ptr % 4)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (ptr < WIL6210_FW_HOST_OFF)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
off = HOSTADDR(ptr);
|
|
|
|
if (off > WIL6210_MEM_SIZE - 4)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return wil->csr + off;
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
|
|
|
|
struct wil6210_mbox_hdr *hdr)
|
|
|
|
{
|
|
|
|
void __iomem *src = wmi_buffer(wil, ptr);
|
2014-09-10 20:34:34 +07:00
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
if (!src)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|
|
|
{
|
|
|
|
struct {
|
|
|
|
struct wil6210_mbox_hdr hdr;
|
|
|
|
struct wil6210_mbox_hdr_wmi wmi;
|
|
|
|
} __packed cmd = {
|
|
|
|
.hdr = {
|
|
|
|
.type = WIL_MBOX_HDR_TYPE_WMI,
|
|
|
|
.flags = 0,
|
|
|
|
.len = cpu_to_le16(sizeof(cmd.wmi) + len),
|
|
|
|
},
|
|
|
|
.wmi = {
|
2013-07-11 22:03:37 +07:00
|
|
|
.mid = 0,
|
2012-12-21 04:13:19 +07:00
|
|
|
.id = cpu_to_le16(cmdid),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
|
|
|
|
struct wil6210_mbox_ring_desc d_head;
|
|
|
|
u32 next_head;
|
|
|
|
void __iomem *dst;
|
|
|
|
void __iomem *head = wmi_addr(wil, r->head);
|
|
|
|
uint retry;
|
|
|
|
|
|
|
|
if (sizeof(cmd) + len > r->entry_size) {
|
|
|
|
wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
|
|
|
|
(int)(sizeof(cmd) + len), r->entry_size);
|
|
|
|
return -ERANGE;
|
|
|
|
}
|
|
|
|
|
|
|
|
might_sleep();
|
|
|
|
|
2014-12-23 14:47:14 +07:00
|
|
|
if (!test_bit(wil_status_fwready, wil->status)) {
|
2014-04-08 15:36:16 +07:00
|
|
|
wil_err(wil, "WMI: cannot send command while FW not ready\n");
|
2012-12-21 04:13:19 +07:00
|
|
|
return -EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!head) {
|
|
|
|
wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
/* read Tx head till it is not busy */
|
|
|
|
for (retry = 5; retry > 0; retry--) {
|
|
|
|
wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
|
|
|
|
if (d_head.sync == 0)
|
|
|
|
break;
|
|
|
|
msleep(20);
|
|
|
|
}
|
|
|
|
if (d_head.sync != 0) {
|
|
|
|
wil_err(wil, "WMI head busy\n");
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
/* next head */
|
|
|
|
next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
|
2012-12-21 04:13:19 +07:00
|
|
|
/* wait till FW finish with previous command */
|
|
|
|
for (retry = 5; retry > 0; retry--) {
|
|
|
|
r->tail = ioread32(wil->csr + HOST_MBOX +
|
|
|
|
offsetof(struct wil6210_mbox_ctl, tx.tail));
|
|
|
|
if (next_head != r->tail)
|
|
|
|
break;
|
|
|
|
msleep(20);
|
|
|
|
}
|
|
|
|
if (next_head == r->tail) {
|
|
|
|
wil_err(wil, "WMI ring full\n");
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
dst = wmi_buffer(wil, d_head.addr);
|
|
|
|
if (!dst) {
|
|
|
|
wil_err(wil, "invalid WMI buffer: 0x%08x\n",
|
|
|
|
le32_to_cpu(d_head.addr));
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
|
|
|
|
/* set command */
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
|
|
|
|
wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
|
2012-12-21 04:13:19 +07:00
|
|
|
sizeof(cmd), true);
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
|
2012-12-21 04:13:19 +07:00
|
|
|
len, true);
|
|
|
|
wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
|
|
|
|
wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
|
|
|
|
/* mark entry as full */
|
|
|
|
iowrite32(1, wil->csr + HOSTADDR(r->head) +
|
|
|
|
offsetof(struct wil6210_mbox_ring_desc, sync));
|
|
|
|
/* advance next ptr */
|
|
|
|
iowrite32(r->head = next_head, wil->csr + HOST_MBOX +
|
|
|
|
offsetof(struct wil6210_mbox_ctl, tx.head));
|
|
|
|
|
2013-07-11 22:03:37 +07:00
|
|
|
trace_wil6210_wmi_cmd(&cmd.wmi, buf, len);
|
2013-05-12 18:43:35 +07:00
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
/* interrupt to FW */
|
|
|
|
iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
mutex_lock(&wil->wmi_mutex);
|
|
|
|
rc = __wmi_send(wil, cmdid, buf, len);
|
|
|
|
mutex_unlock(&wil->wmi_mutex);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=== Event handlers ===*/
|
|
|
|
static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
|
|
|
|
{
|
|
|
|
struct net_device *ndev = wil_to_ndev(wil);
|
|
|
|
struct wireless_dev *wdev = wil->wdev;
|
|
|
|
struct wmi_ready_event *evt = d;
|
2014-09-10 20:34:34 +07:00
|
|
|
|
2013-03-13 19:12:50 +07:00
|
|
|
wil->fw_version = le32_to_cpu(evt->sw_version);
|
|
|
|
wil->n_mids = evt->numof_additional_mids;
|
2012-12-21 04:13:19 +07:00
|
|
|
|
2014-04-08 15:36:16 +07:00
|
|
|
wil_info(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version,
|
|
|
|
evt->mac, wil->n_mids);
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
if (!is_valid_ether_addr(ndev->dev_addr)) {
|
|
|
|
memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
|
|
|
|
memcpy(ndev->perm_addr, evt->mac, ETH_ALEN);
|
|
|
|
}
|
|
|
|
snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version),
|
2013-03-13 19:12:50 +07:00
|
|
|
"%d", wil->fw_version);
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
|
|
|
|
int len)
|
|
|
|
{
|
2014-04-08 15:36:16 +07:00
|
|
|
wil_dbg_wmi(wil, "WMI: got FW ready event\n");
|
2012-12-21 04:13:19 +07:00
|
|
|
|
2014-10-01 19:05:24 +07:00
|
|
|
wil_set_recovery_state(wil, fw_recovery_idle);
|
2014-12-23 14:47:14 +07:00
|
|
|
set_bit(wil_status_fwready, wil->status);
|
2014-09-10 20:34:46 +07:00
|
|
|
/* let the reset sequence continue */
|
2012-12-21 04:13:19 +07:00
|
|
|
complete(&wil->wmi_ready);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
|
|
|
|
{
|
|
|
|
struct wmi_rx_mgmt_packet_event *data = d;
|
|
|
|
struct wiphy *wiphy = wil_to_wiphy(wil);
|
|
|
|
struct ieee80211_mgmt *rx_mgmt_frame =
|
|
|
|
(struct ieee80211_mgmt *)data->payload;
|
|
|
|
int ch_no = data->info.channel+1;
|
|
|
|
u32 freq = ieee80211_channel_to_frequency(ch_no,
|
|
|
|
IEEE80211_BAND_60GHZ);
|
|
|
|
struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq);
|
2014-02-27 21:20:52 +07:00
|
|
|
s32 signal = data->info.sqi;
|
2012-12-21 04:13:19 +07:00
|
|
|
__le16 fc = rx_mgmt_frame->frame_control;
|
|
|
|
u32 d_len = le32_to_cpu(data->info.len);
|
|
|
|
u16 d_status = le16_to_cpu(data->info.status);
|
|
|
|
|
2014-02-27 21:20:52 +07:00
|
|
|
wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n",
|
|
|
|
data->info.channel, data->info.mcs, data->info.snr,
|
|
|
|
data->info.sqi);
|
2013-06-09 13:12:52 +07:00
|
|
|
wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
|
|
|
|
le16_to_cpu(fc));
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
|
2012-12-21 04:13:19 +07:00
|
|
|
data->info.qid, data->info.mid, data->info.cid);
|
|
|
|
|
|
|
|
if (!channel) {
|
|
|
|
wil_err(wil, "Frame on unsupported channel\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
|
|
|
|
struct cfg80211_bss *bss;
|
2014-06-16 23:37:03 +07:00
|
|
|
u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
|
|
|
|
u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
|
|
|
|
u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
|
|
|
|
const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
|
|
|
|
size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
|
|
|
|
u.beacon.variable);
|
|
|
|
wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
|
|
|
|
wil_dbg_wmi(wil, "TSF : 0x%016llx\n", tsf);
|
|
|
|
wil_dbg_wmi(wil, "Beacon interval : %d\n", bi);
|
|
|
|
wil_hex_dump_wmi("IE ", DUMP_PREFIX_OFFSET, 16, 1, ie_buf,
|
|
|
|
ie_len, true);
|
2013-03-13 19:12:44 +07:00
|
|
|
|
|
|
|
bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
|
|
|
|
d_len, signal, GFP_KERNEL);
|
2012-12-21 04:13:19 +07:00
|
|
|
if (bss) {
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "Added BSS %pM\n",
|
2012-12-21 04:13:19 +07:00
|
|
|
rx_mgmt_frame->bssid);
|
2013-02-01 07:49:58 +07:00
|
|
|
cfg80211_put_bss(wiphy, bss);
|
2012-12-21 04:13:19 +07:00
|
|
|
} else {
|
2014-08-13 02:01:28 +07:00
|
|
|
wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
2013-03-13 19:12:45 +07:00
|
|
|
} else {
|
|
|
|
cfg80211_rx_mgmt(wil->wdev, freq, signal,
|
2014-08-11 17:29:57 +07:00
|
|
|
(void *)rx_mgmt_frame, d_len, 0);
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
|
|
|
|
void *d, int len)
|
|
|
|
{
|
|
|
|
if (wil->scan_request) {
|
|
|
|
struct wmi_scan_complete_event *data = d;
|
2014-04-08 15:36:17 +07:00
|
|
|
bool aborted = (data->status != WMI_SCAN_SUCCESS);
|
2012-12-21 04:13:19 +07:00
|
|
|
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
|
2014-06-16 23:37:11 +07:00
|
|
|
wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
|
|
|
|
wil->scan_request, aborted);
|
|
|
|
|
2014-05-27 18:45:48 +07:00
|
|
|
del_timer_sync(&wil->scan_timer);
|
2012-12-21 04:13:19 +07:00
|
|
|
cfg80211_scan_done(wil->scan_request, aborted);
|
|
|
|
wil->scan_request = NULL;
|
|
|
|
} else {
|
|
|
|
wil_err(wil, "SCAN_COMPLETE while not scanning\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
|
|
|
{
|
|
|
|
struct net_device *ndev = wil_to_ndev(wil);
|
|
|
|
struct wireless_dev *wdev = wil->wdev;
|
|
|
|
struct wmi_connect_event *evt = d;
|
|
|
|
int ch; /* channel number */
|
|
|
|
struct station_info sinfo;
|
|
|
|
u8 *assoc_req_ie, *assoc_resp_ie;
|
|
|
|
size_t assoc_req_ielen, assoc_resp_ielen;
|
|
|
|
/* capinfo(u16) + listen_interval(u16) + IEs */
|
|
|
|
const size_t assoc_req_ie_offset = sizeof(u16) * 2;
|
|
|
|
/* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
|
|
|
|
const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
|
|
|
|
|
|
|
|
if (len < sizeof(*evt)) {
|
|
|
|
wil_err(wil, "Connect event too short : %d bytes\n", len);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len +
|
|
|
|
evt->assoc_resp_len) {
|
|
|
|
wil_err(wil,
|
|
|
|
"Connect event corrupted : %d != %d + %d + %d + %d\n",
|
|
|
|
len, (int)sizeof(*evt), evt->beacon_ie_len,
|
|
|
|
evt->assoc_req_len, evt->assoc_resp_len);
|
|
|
|
return;
|
|
|
|
}
|
2014-02-27 21:20:43 +07:00
|
|
|
if (evt->cid >= WIL6210_MAX_CID) {
|
|
|
|
wil_err(wil, "Connect CID invalid : %d\n", evt->cid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
ch = evt->channel + 1;
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
|
2012-12-21 04:13:19 +07:00
|
|
|
evt->bssid, ch, evt->cid);
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
|
2012-12-21 04:13:19 +07:00
|
|
|
evt->assoc_info, len - sizeof(*evt), true);
|
|
|
|
|
|
|
|
/* figure out IE's */
|
|
|
|
assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len +
|
|
|
|
assoc_req_ie_offset];
|
|
|
|
assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset;
|
|
|
|
if (evt->assoc_req_len <= assoc_req_ie_offset) {
|
|
|
|
assoc_req_ie = NULL;
|
|
|
|
assoc_req_ielen = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len +
|
|
|
|
evt->assoc_req_len +
|
|
|
|
assoc_resp_ie_offset];
|
|
|
|
assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset;
|
|
|
|
if (evt->assoc_resp_len <= assoc_resp_ie_offset) {
|
|
|
|
assoc_resp_ie = NULL;
|
|
|
|
assoc_resp_ielen = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
|
|
|
|
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
|
2014-12-23 14:47:14 +07:00
|
|
|
if (!test_bit(wil_status_fwconnecting, wil->status)) {
|
2012-12-21 04:13:19 +07:00
|
|
|
wil_err(wil, "Not in connecting state\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
del_timer_sync(&wil->connect_timer);
|
|
|
|
cfg80211_connect_result(ndev, evt->bssid,
|
|
|
|
assoc_req_ie, assoc_req_ielen,
|
|
|
|
assoc_resp_ie, assoc_resp_ielen,
|
|
|
|
WLAN_STATUS_SUCCESS, GFP_KERNEL);
|
|
|
|
|
|
|
|
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
|
|
|
|
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
|
|
|
|
memset(&sinfo, 0, sizeof(sinfo));
|
|
|
|
|
|
|
|
sinfo.generation = wil->sinfo_gen++;
|
|
|
|
|
|
|
|
if (assoc_req_ie) {
|
|
|
|
sinfo.assoc_req_ies = assoc_req_ie;
|
|
|
|
sinfo.assoc_req_ies_len = assoc_req_ielen;
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
|
|
|
|
}
|
2014-12-23 14:47:14 +07:00
|
|
|
clear_bit(wil_status_fwconnecting, wil->status);
|
|
|
|
set_bit(wil_status_fwconnected, wil->status);
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
/* FIXME FW can transmit only ucast frames to peer */
|
|
|
|
/* FIXME real ring_id instead of hard coded 0 */
|
2014-02-27 21:20:43 +07:00
|
|
|
memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN);
|
|
|
|
wil->sta[evt->cid].status = wil_sta_conn_pending;
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
wil->pending_connect_cid = evt->cid;
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
queue_work(wil->wq_service, &wil->connect_worker);
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
|
|
|
|
void *d, int len)
|
|
|
|
{
|
|
|
|
struct wmi_disconnect_event *evt = d;
|
2014-12-01 20:33:15 +07:00
|
|
|
u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
|
2012-12-21 04:13:19 +07:00
|
|
|
|
2014-12-01 20:33:15 +07:00
|
|
|
wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
|
|
|
|
evt->bssid, reason_code, evt->disconnect_reason);
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
wil->sinfo_gen++;
|
|
|
|
|
2014-03-17 20:34:25 +07:00
|
|
|
mutex_lock(&wil->mutex);
|
2014-12-01 20:33:15 +07:00
|
|
|
wil6210_disconnect(wil, evt->bssid, reason_code, true);
|
2014-03-17 20:34:25 +07:00
|
|
|
mutex_unlock(&wil->mutex);
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Firmware reports EAPOL frame using WME event.
|
|
|
|
* Reconstruct Ethernet frame and deliver it via normal Rx
|
|
|
|
*/
|
|
|
|
static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
|
|
|
|
void *d, int len)
|
|
|
|
{
|
|
|
|
struct net_device *ndev = wil_to_ndev(wil);
|
|
|
|
struct wmi_eapol_rx_event *evt = d;
|
|
|
|
u16 eapol_len = le16_to_cpu(evt->eapol_len);
|
|
|
|
int sz = eapol_len + ETH_HLEN;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
struct ethhdr *eth;
|
2014-02-27 21:20:49 +07:00
|
|
|
int cid;
|
|
|
|
struct wil_net_stats *stats = NULL;
|
2012-12-21 04:13:19 +07:00
|
|
|
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len,
|
2012-12-21 04:13:19 +07:00
|
|
|
evt->src_mac);
|
|
|
|
|
2014-02-27 21:20:49 +07:00
|
|
|
cid = wil_find_cid(wil, evt->src_mac);
|
|
|
|
if (cid >= 0)
|
|
|
|
stats = &wil->sta[cid].stats;
|
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
if (eapol_len > 196) { /* TODO: revisit size limit */
|
|
|
|
wil_err(wil, "EAPOL too large\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
skb = alloc_skb(sz, GFP_KERNEL);
|
|
|
|
if (!skb) {
|
|
|
|
wil_err(wil, "Failed to allocate skb\n");
|
|
|
|
return;
|
|
|
|
}
|
2014-02-27 21:20:49 +07:00
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);
|
|
|
|
memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);
|
|
|
|
memcpy(eth->h_source, evt->src_mac, ETH_ALEN);
|
|
|
|
eth->h_proto = cpu_to_be16(ETH_P_PAE);
|
|
|
|
memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len);
|
|
|
|
skb->protocol = eth_type_trans(skb, ndev);
|
|
|
|
if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
|
|
|
|
ndev->stats.rx_packets++;
|
2014-02-27 21:20:49 +07:00
|
|
|
ndev->stats.rx_bytes += sz;
|
|
|
|
if (stats) {
|
|
|
|
stats->rx_packets++;
|
|
|
|
stats->rx_bytes += sz;
|
|
|
|
}
|
2012-12-21 04:13:19 +07:00
|
|
|
} else {
|
|
|
|
ndev->stats.rx_dropped++;
|
2014-02-27 21:20:49 +07:00
|
|
|
if (stats)
|
|
|
|
stats->rx_dropped++;
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-23 14:47:05 +07:00
|
|
|
static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize)
|
2014-12-23 14:47:04 +07:00
|
|
|
{
|
|
|
|
struct vring_tx_data *t;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
|
|
|
if (cid != wil->vring2cid_tid[i][0])
|
|
|
|
continue;
|
|
|
|
t = &wil->vring_tx_data[i];
|
|
|
|
if (!t->enabled)
|
|
|
|
continue;
|
|
|
|
|
2014-12-23 14:47:05 +07:00
|
|
|
wil_addba_tx_request(wil, i, wsize);
|
2014-12-23 14:47:04 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-13 19:12:39 +07:00
|
|
|
static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
|
|
|
|
{
|
|
|
|
struct net_device *ndev = wil_to_ndev(wil);
|
|
|
|
struct wmi_data_port_open_event *evt = d;
|
2014-03-17 20:34:06 +07:00
|
|
|
u8 cid = evt->cid;
|
2013-03-13 19:12:39 +07:00
|
|
|
|
2014-03-17 20:34:06 +07:00
|
|
|
wil_dbg_wmi(wil, "Link UP for CID %d\n", cid);
|
2013-03-13 19:12:39 +07:00
|
|
|
|
2014-03-17 20:34:06 +07:00
|
|
|
if (cid >= ARRAY_SIZE(wil->sta)) {
|
|
|
|
wil_err(wil, "Link UP for invalid CID %d\n", cid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
wil->sta[cid].data_port_open = true;
|
2014-12-23 14:47:05 +07:00
|
|
|
if (agg_wsize >= 0)
|
|
|
|
wil_addba_tx_cid(wil, cid, agg_wsize);
|
2013-03-13 19:12:39 +07:00
|
|
|
netif_carrier_on(ndev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
|
|
|
|
{
|
|
|
|
struct net_device *ndev = wil_to_ndev(wil);
|
|
|
|
struct wmi_wbe_link_down_event *evt = d;
|
2014-03-17 20:34:06 +07:00
|
|
|
u8 cid = evt->cid;
|
2013-03-13 19:12:39 +07:00
|
|
|
|
|
|
|
wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n",
|
2014-03-17 20:34:06 +07:00
|
|
|
cid, le32_to_cpu(evt->reason));
|
|
|
|
|
|
|
|
if (cid >= ARRAY_SIZE(wil->sta)) {
|
|
|
|
wil_err(wil, "Link DOWN for invalid CID %d\n", cid);
|
|
|
|
return;
|
|
|
|
}
|
2013-03-13 19:12:39 +07:00
|
|
|
|
2014-03-17 20:34:06 +07:00
|
|
|
wil->sta[cid].data_port_open = false;
|
2013-03-13 19:12:39 +07:00
|
|
|
netif_carrier_off(ndev);
|
|
|
|
}
|
|
|
|
|
2013-03-13 19:12:40 +07:00
|
|
|
static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
|
|
|
|
int len)
|
|
|
|
{
|
|
|
|
struct wmi_vring_ba_status_event *evt = d;
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
struct vring_tx_data *txdata;
|
2013-03-13 19:12:40 +07:00
|
|
|
|
2014-12-23 14:47:09 +07:00
|
|
|
wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
|
2014-02-27 21:20:47 +07:00
|
|
|
evt->ringid,
|
|
|
|
evt->status == WMI_BA_AGREED ? "OK" : "N/A",
|
2014-12-23 14:47:09 +07:00
|
|
|
evt->agg_wsize, __le16_to_cpu(evt->ba_timeout),
|
|
|
|
evt->amsdu ? "+" : "-");
|
2014-02-27 21:20:47 +07:00
|
|
|
|
|
|
|
if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
|
|
|
|
wil_err(wil, "invalid ring id %d\n", evt->ringid);
|
|
|
|
return;
|
2014-02-27 21:20:44 +07:00
|
|
|
}
|
|
|
|
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
if (evt->status != WMI_BA_AGREED) {
|
|
|
|
evt->ba_timeout = 0;
|
|
|
|
evt->agg_wsize = 0;
|
2014-12-23 14:47:09 +07:00
|
|
|
evt->amsdu = 0;
|
2014-02-27 21:20:47 +07:00
|
|
|
}
|
|
|
|
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
txdata = &wil->vring_tx_data[evt->ringid];
|
2014-09-10 20:34:42 +07:00
|
|
|
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
|
|
|
|
txdata->agg_wsize = evt->agg_wsize;
|
2014-12-23 14:47:09 +07:00
|
|
|
txdata->agg_amsdu = evt->amsdu;
|
2014-12-23 14:47:04 +07:00
|
|
|
txdata->addba_in_progress = false;
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
}
|
2014-09-10 20:34:42 +07:00
|
|
|
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
|
|
|
|
int len)
|
|
|
|
{
|
|
|
|
struct wmi_rcp_addba_req_event *evt = d;
|
2014-09-10 20:34:42 +07:00
|
|
|
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token,
|
|
|
|
evt->ba_param_set, evt->ba_timeout,
|
|
|
|
evt->ba_seq_ctrl);
|
|
|
|
}
|
2014-09-10 20:34:42 +07:00
|
|
|
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
|
2014-12-23 14:47:24 +07:00
|
|
|
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
{
|
|
|
|
struct wmi_delba_event *evt = d;
|
|
|
|
u8 cid, tid;
|
|
|
|
u16 reason = __le16_to_cpu(evt->reason);
|
|
|
|
struct wil_sta_info *sta;
|
|
|
|
struct wil_tid_ampdu_rx *r;
|
|
|
|
|
2014-12-23 14:47:24 +07:00
|
|
|
might_sleep();
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
parse_cidxtid(evt->cidxtid, &cid, &tid);
|
|
|
|
wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n",
|
|
|
|
cid, tid,
|
|
|
|
evt->from_initiator ? "originator" : "recipient",
|
|
|
|
reason);
|
|
|
|
if (!evt->from_initiator) {
|
|
|
|
int i;
|
|
|
|
/* find Tx vring it belongs to */
|
|
|
|
for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
|
|
|
|
if ((wil->vring2cid_tid[i][0] == cid) &&
|
|
|
|
(wil->vring2cid_tid[i][1] == tid)) {
|
|
|
|
struct vring_tx_data *txdata =
|
|
|
|
&wil->vring_tx_data[i];
|
|
|
|
|
|
|
|
wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
|
|
|
|
txdata->agg_timeout = 0;
|
|
|
|
txdata->agg_wsize = 0;
|
2014-12-23 14:47:04 +07:00
|
|
|
txdata->addba_in_progress = false;
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
|
|
|
|
break; /* max. 1 matching ring */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= ARRAY_SIZE(wil->vring2cid_tid))
|
|
|
|
wil_err(wil, "DELBA: unable to find Tx vring\n");
|
|
|
|
return;
|
2014-02-27 21:20:47 +07:00
|
|
|
}
|
2014-09-10 20:34:40 +07:00
|
|
|
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
sta = &wil->sta[cid];
|
|
|
|
|
2014-12-23 14:47:24 +07:00
|
|
|
spin_lock_bh(&sta->tid_rx_lock);
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
|
|
|
|
r = sta->tid_rx[tid];
|
|
|
|
sta->tid_rx[tid] = NULL;
|
|
|
|
wil_tid_ampdu_rx_free(wil, r);
|
|
|
|
|
2014-12-23 14:47:24 +07:00
|
|
|
spin_unlock_bh(&sta->tid_rx_lock);
|
2013-03-13 19:12:40 +07:00
|
|
|
}
|
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
static const struct {
|
|
|
|
int eventid;
|
|
|
|
void (*handler)(struct wil6210_priv *wil, int eventid,
|
|
|
|
void *data, int data_len);
|
|
|
|
} wmi_evt_handlers[] = {
|
|
|
|
{WMI_READY_EVENTID, wmi_evt_ready},
|
|
|
|
{WMI_FW_READY_EVENTID, wmi_evt_fw_ready},
|
|
|
|
{WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt},
|
|
|
|
{WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete},
|
|
|
|
{WMI_CONNECT_EVENTID, wmi_evt_connect},
|
|
|
|
{WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
|
|
|
|
{WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
|
2013-03-13 19:12:39 +07:00
|
|
|
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
|
|
|
|
{WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
|
2013-03-13 19:12:40 +07:00
|
|
|
{WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
{WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
|
|
|
|
{WMI_DELBA_EVENTID, wmi_evt_delba},
|
2012-12-21 04:13:19 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run in IRQ context
|
|
|
|
* Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev
|
|
|
|
* that will be eventually handled by the @wmi_event_worker in the thread
|
|
|
|
* context of thread "wil6210_wmi"
|
|
|
|
*/
|
|
|
|
void wmi_recv_cmd(struct wil6210_priv *wil)
|
|
|
|
{
|
|
|
|
struct wil6210_mbox_ring_desc d_tail;
|
|
|
|
struct wil6210_mbox_hdr hdr;
|
|
|
|
struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
|
|
|
|
struct pending_wmi_event *evt;
|
|
|
|
u8 *cmd;
|
|
|
|
void __iomem *src;
|
|
|
|
ulong flags;
|
2014-05-29 22:37:52 +07:00
|
|
|
unsigned n;
|
2012-12-21 04:13:19 +07:00
|
|
|
|
2014-12-23 14:47:14 +07:00
|
|
|
if (!test_bit(wil_status_reset_done, wil->status)) {
|
2014-09-10 20:34:41 +07:00
|
|
|
wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
|
2013-03-13 19:12:49 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-29 22:37:52 +07:00
|
|
|
for (n = 0;; n++) {
|
2012-12-21 04:13:19 +07:00
|
|
|
u16 len;
|
wil6210: fix for unreachable code in wmi_recv_cmd
As reported by Dan Carpenter <dan.carpenter@oracle.com>:
The patch a715c7ddd65a: "wil6210: improve debug for WMI receive" from
May 29, 2014, leads to the following static checker warning:
drivers/net/wireless/ath/wil6210/wmi.c:746 wmi_recv_cmd()
info: ignoring unreachable code.
drivers/net/wireless/ath/wil6210/wmi.c
739 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
740 {
741 int q = queue_work(wil->wmi_wq,
742 &wil->wmi_event_worker);
743 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
744 }
745 }
746 if (n > 1)
^^^^^^^^^^
We never reach this if statemtent.
747 wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n);
748 }
Exit loop with "break", not "return".
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2014-06-16 23:37:19 +07:00
|
|
|
bool q;
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
r->head = ioread32(wil->csr + HOST_MBOX +
|
|
|
|
offsetof(struct wil6210_mbox_ctl, rx.head));
|
wil6210: fix for unreachable code in wmi_recv_cmd
As reported by Dan Carpenter <dan.carpenter@oracle.com>:
The patch a715c7ddd65a: "wil6210: improve debug for WMI receive" from
May 29, 2014, leads to the following static checker warning:
drivers/net/wireless/ath/wil6210/wmi.c:746 wmi_recv_cmd()
info: ignoring unreachable code.
drivers/net/wireless/ath/wil6210/wmi.c
739 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
740 {
741 int q = queue_work(wil->wmi_wq,
742 &wil->wmi_event_worker);
743 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
744 }
745 }
746 if (n > 1)
^^^^^^^^^^
We never reach this if statemtent.
747 wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n);
748 }
Exit loop with "break", not "return".
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2014-06-16 23:37:19 +07:00
|
|
|
if (r->tail == r->head)
|
|
|
|
break;
|
2012-12-21 04:13:19 +07:00
|
|
|
|
2014-05-29 22:37:52 +07:00
|
|
|
wil_dbg_wmi(wil, "Mbox head %08x tail %08x\n",
|
|
|
|
r->head, r->tail);
|
|
|
|
/* read cmd descriptor from tail */
|
2012-12-21 04:13:19 +07:00
|
|
|
wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),
|
|
|
|
sizeof(struct wil6210_mbox_ring_desc));
|
|
|
|
if (d_tail.sync == 0) {
|
|
|
|
wil_err(wil, "Mbox evt not owned by FW?\n");
|
wil6210: fix for unreachable code in wmi_recv_cmd
As reported by Dan Carpenter <dan.carpenter@oracle.com>:
The patch a715c7ddd65a: "wil6210: improve debug for WMI receive" from
May 29, 2014, leads to the following static checker warning:
drivers/net/wireless/ath/wil6210/wmi.c:746 wmi_recv_cmd()
info: ignoring unreachable code.
drivers/net/wireless/ath/wil6210/wmi.c
739 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
740 {
741 int q = queue_work(wil->wmi_wq,
742 &wil->wmi_event_worker);
743 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
744 }
745 }
746 if (n > 1)
^^^^^^^^^^
We never reach this if statemtent.
747 wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n);
748 }
Exit loop with "break", not "return".
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2014-06-16 23:37:19 +07:00
|
|
|
break;
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
|
|
|
|
2014-05-29 22:37:52 +07:00
|
|
|
/* read cmd header from descriptor */
|
2012-12-21 04:13:19 +07:00
|
|
|
if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
|
|
|
|
wil_err(wil, "Mbox evt at 0x%08x?\n",
|
|
|
|
le32_to_cpu(d_tail.addr));
|
wil6210: fix for unreachable code in wmi_recv_cmd
As reported by Dan Carpenter <dan.carpenter@oracle.com>:
The patch a715c7ddd65a: "wil6210: improve debug for WMI receive" from
May 29, 2014, leads to the following static checker warning:
drivers/net/wireless/ath/wil6210/wmi.c:746 wmi_recv_cmd()
info: ignoring unreachable code.
drivers/net/wireless/ath/wil6210/wmi.c
739 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
740 {
741 int q = queue_work(wil->wmi_wq,
742 &wil->wmi_event_worker);
743 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
744 }
745 }
746 if (n > 1)
^^^^^^^^^^
We never reach this if statemtent.
747 wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n);
748 }
Exit loop with "break", not "return".
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2014-06-16 23:37:19 +07:00
|
|
|
break;
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
|
|
|
len = le16_to_cpu(hdr.len);
|
2014-05-29 22:37:52 +07:00
|
|
|
wil_dbg_wmi(wil, "Mbox evt %04x %04x %04x %02x\n",
|
|
|
|
le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
|
|
|
|
hdr.flags);
|
|
|
|
|
|
|
|
/* read cmd buffer from descriptor */
|
2012-12-21 04:13:19 +07:00
|
|
|
src = wmi_buffer(wil, d_tail.addr) +
|
|
|
|
sizeof(struct wil6210_mbox_hdr);
|
|
|
|
evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
|
|
|
|
event.wmi) + len, 4),
|
|
|
|
GFP_KERNEL);
|
2013-02-07 18:46:27 +07:00
|
|
|
if (!evt)
|
wil6210: fix for unreachable code in wmi_recv_cmd
As reported by Dan Carpenter <dan.carpenter@oracle.com>:
The patch a715c7ddd65a: "wil6210: improve debug for WMI receive" from
May 29, 2014, leads to the following static checker warning:
drivers/net/wireless/ath/wil6210/wmi.c:746 wmi_recv_cmd()
info: ignoring unreachable code.
drivers/net/wireless/ath/wil6210/wmi.c
739 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
740 {
741 int q = queue_work(wil->wmi_wq,
742 &wil->wmi_event_worker);
743 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
744 }
745 }
746 if (n > 1)
^^^^^^^^^^
We never reach this if statemtent.
747 wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n);
748 }
Exit loop with "break", not "return".
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2014-06-16 23:37:19 +07:00
|
|
|
break;
|
2013-02-07 18:46:27 +07:00
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
evt->event.hdr = hdr;
|
|
|
|
cmd = (void *)&evt->event.wmi;
|
|
|
|
wil_memcpy_fromio_32(cmd, src, len);
|
|
|
|
/* mark entry as empty */
|
|
|
|
iowrite32(0, wil->csr + HOSTADDR(r->tail) +
|
|
|
|
offsetof(struct wil6210_mbox_ring_desc, sync));
|
|
|
|
/* indicate */
|
|
|
|
if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
|
|
|
|
(len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
|
2013-07-11 22:03:37 +07:00
|
|
|
struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
|
|
|
|
u16 id = le16_to_cpu(wmi->id);
|
|
|
|
u32 tstamp = le32_to_cpu(wmi->timestamp);
|
2014-09-10 20:34:34 +07:00
|
|
|
|
2013-07-11 22:03:37 +07:00
|
|
|
wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
|
|
|
|
id, wmi->mid, tstamp);
|
|
|
|
trace_wil6210_wmi_event(wmi, &wmi[1],
|
|
|
|
len - sizeof(*wmi));
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1,
|
2012-12-21 04:13:19 +07:00
|
|
|
&evt->event.hdr, sizeof(hdr) + len, true);
|
|
|
|
|
|
|
|
/* advance tail */
|
|
|
|
r->tail = r->base + ((r->tail - r->base +
|
|
|
|
sizeof(struct wil6210_mbox_ring_desc)) % r->size);
|
|
|
|
iowrite32(r->tail, wil->csr + HOST_MBOX +
|
|
|
|
offsetof(struct wil6210_mbox_ctl, rx.tail));
|
|
|
|
|
|
|
|
/* add to the pending list */
|
|
|
|
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
|
|
|
list_add_tail(&evt->list, &wil->pending_wmi_ev);
|
|
|
|
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
wil6210: fix for unreachable code in wmi_recv_cmd
As reported by Dan Carpenter <dan.carpenter@oracle.com>:
The patch a715c7ddd65a: "wil6210: improve debug for WMI receive" from
May 29, 2014, leads to the following static checker warning:
drivers/net/wireless/ath/wil6210/wmi.c:746 wmi_recv_cmd()
info: ignoring unreachable code.
drivers/net/wireless/ath/wil6210/wmi.c
739 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
740 {
741 int q = queue_work(wil->wmi_wq,
742 &wil->wmi_event_worker);
743 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
744 }
745 }
746 if (n > 1)
^^^^^^^^^^
We never reach this if statemtent.
747 wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n);
748 }
Exit loop with "break", not "return".
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2014-06-16 23:37:19 +07:00
|
|
|
q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
|
|
|
|
wil_dbg_wmi(wil, "queue_work -> %d\n", q);
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
wil6210: fix for unreachable code in wmi_recv_cmd
As reported by Dan Carpenter <dan.carpenter@oracle.com>:
The patch a715c7ddd65a: "wil6210: improve debug for WMI receive" from
May 29, 2014, leads to the following static checker warning:
drivers/net/wireless/ath/wil6210/wmi.c:746 wmi_recv_cmd()
info: ignoring unreachable code.
drivers/net/wireless/ath/wil6210/wmi.c
739 spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
740 {
741 int q = queue_work(wil->wmi_wq,
742 &wil->wmi_event_worker);
743 wil_dbg_wmi(wil, "queue_work -> %d\n", q);
744 }
745 }
746 if (n > 1)
^^^^^^^^^^
We never reach this if statemtent.
747 wil_dbg_wmi(wil, "%s -> %d events processed\n", __func__, n);
748 }
Exit loop with "break", not "return".
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2014-06-16 23:37:19 +07:00
|
|
|
/* normally, 1 event per IRQ should be processed */
|
|
|
|
wil_dbg_wmi(wil, "%s -> %d events queued\n", __func__, n);
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
|
|
|
|
u16 reply_id, void *reply, u8 reply_size, int to_msec)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
int remain;
|
|
|
|
|
|
|
|
mutex_lock(&wil->wmi_mutex);
|
|
|
|
|
|
|
|
rc = __wmi_send(wil, cmdid, buf, len);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
wil->reply_id = reply_id;
|
|
|
|
wil->reply_buf = reply;
|
|
|
|
wil->reply_size = reply_size;
|
2014-09-10 20:34:46 +07:00
|
|
|
remain = wait_for_completion_timeout(&wil->wmi_call,
|
|
|
|
msecs_to_jiffies(to_msec));
|
2012-12-21 04:13:19 +07:00
|
|
|
if (0 == remain) {
|
|
|
|
wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
|
|
|
|
cmdid, reply_id, to_msec);
|
|
|
|
rc = -ETIME;
|
|
|
|
} else {
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil,
|
2012-12-21 04:13:19 +07:00
|
|
|
"wmi_call(0x%04x->0x%04x) completed in %d msec\n",
|
|
|
|
cmdid, reply_id,
|
|
|
|
to_msec - jiffies_to_msecs(remain));
|
|
|
|
}
|
|
|
|
wil->reply_id = 0;
|
|
|
|
wil->reply_buf = NULL;
|
|
|
|
wil->reply_size = 0;
|
|
|
|
out:
|
|
|
|
mutex_unlock(&wil->wmi_mutex);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_echo(struct wil6210_priv *wil)
|
|
|
|
{
|
|
|
|
struct wmi_echo_cmd cmd = {
|
|
|
|
.value = cpu_to_le32(0x12345678),
|
|
|
|
};
|
|
|
|
|
|
|
|
return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
|
|
|
|
WMI_ECHO_RSP_EVENTID, NULL, 0, 20);
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
|
|
|
|
{
|
|
|
|
struct wmi_set_mac_address_cmd cmd;
|
|
|
|
|
|
|
|
memcpy(cmd.mac, addr, ETH_ALEN);
|
|
|
|
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "Set MAC %pM\n", addr);
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
2013-03-13 19:12:50 +07:00
|
|
|
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
|
2012-12-21 04:13:19 +07:00
|
|
|
{
|
2013-03-13 19:12:50 +07:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
struct wmi_pcp_start_cmd cmd = {
|
2012-12-21 04:13:19 +07:00
|
|
|
.bcon_interval = cpu_to_le16(bi),
|
|
|
|
.network_type = wmi_nettype,
|
|
|
|
.disable_sec_offload = 1,
|
2013-05-28 19:17:52 +07:00
|
|
|
.channel = chan - 1,
|
2014-08-06 14:31:58 +07:00
|
|
|
.pcp_max_assoc_sta = max_assoc_sta,
|
2012-12-21 04:13:19 +07:00
|
|
|
};
|
2013-03-13 19:12:50 +07:00
|
|
|
struct {
|
|
|
|
struct wil6210_mbox_hdr_wmi wmi;
|
|
|
|
struct wmi_pcp_started_event evt;
|
|
|
|
} __packed reply;
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
if (!wil->secure_pcp)
|
|
|
|
cmd.disable_sec = 1;
|
|
|
|
|
2014-08-06 14:31:58 +07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-06-09 13:12:50 +07:00
|
|
|
/*
|
|
|
|
* Processing time may be huge, in case of secure AP it takes about
|
|
|
|
* 3500ms for FW to start AP
|
|
|
|
*/
|
2013-03-13 19:12:50 +07:00
|
|
|
rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
|
2013-06-09 13:12:50 +07:00
|
|
|
WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000);
|
2013-03-13 19:12:50 +07:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
|
|
|
|
rc = -EINVAL;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_pcp_stop(struct wil6210_priv *wil)
|
|
|
|
{
|
|
|
|
return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
|
|
|
|
WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
|
|
|
|
{
|
|
|
|
struct wmi_set_ssid_cmd cmd = {
|
|
|
|
.ssid_len = cpu_to_le32(ssid_len),
|
|
|
|
};
|
|
|
|
|
|
|
|
if (ssid_len > sizeof(cmd.ssid))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
memcpy(cmd.ssid, ssid, ssid_len);
|
|
|
|
|
|
|
|
return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct {
|
|
|
|
struct wil6210_mbox_hdr_wmi wmi;
|
|
|
|
struct wmi_set_ssid_cmd cmd;
|
|
|
|
} __packed reply;
|
|
|
|
int len; /* reply.cmd.ssid_len in CPU order */
|
|
|
|
|
|
|
|
rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
|
|
|
|
&reply, sizeof(reply), 20);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
len = le32_to_cpu(reply.cmd.ssid_len);
|
|
|
|
if (len > sizeof(reply.cmd.ssid))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
*ssid_len = len;
|
|
|
|
memcpy(ssid, reply.cmd.ssid, len);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_set_channel(struct wil6210_priv *wil, int channel)
|
|
|
|
{
|
|
|
|
struct wmi_set_pcp_channel_cmd cmd = {
|
|
|
|
.channel = channel - 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_get_channel(struct wil6210_priv *wil, int *channel)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct {
|
|
|
|
struct wil6210_mbox_hdr_wmi wmi;
|
|
|
|
struct wmi_set_pcp_channel_cmd cmd;
|
|
|
|
} __packed reply;
|
|
|
|
|
|
|
|
rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
|
|
|
|
WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (reply.cmd.channel > 3)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
*channel = reply.cmd.channel + 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-13 19:12:50 +07:00
|
|
|
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
|
|
|
|
{
|
|
|
|
struct wmi_p2p_cfg_cmd cmd = {
|
|
|
|
.discovery_mode = WMI_DISCOVERY_MODE_NON_OFFLOAD,
|
|
|
|
.channel = channel - 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
return wmi_send(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
|
|
|
const void *mac_addr)
|
|
|
|
{
|
|
|
|
struct wmi_delete_cipher_key_cmd cmd = {
|
|
|
|
.key_index = key_index,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (mac_addr)
|
|
|
|
memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
|
|
|
|
|
|
|
|
return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
|
|
|
const void *mac_addr, int key_len, const void *key)
|
|
|
|
{
|
|
|
|
struct wmi_add_cipher_key_cmd cmd = {
|
|
|
|
.key_index = key_index,
|
|
|
|
.key_usage = WMI_KEY_USE_PAIRWISE,
|
|
|
|
.key_len = key_len,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!key || (key_len > sizeof(cmd.key)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
memcpy(cmd.key, key, key_len);
|
|
|
|
if (mac_addr)
|
|
|
|
memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
|
|
|
|
|
|
|
|
return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
|
|
|
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
|
|
|
|
struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
|
2014-09-10 20:34:34 +07:00
|
|
|
|
2013-02-07 18:46:27 +07:00
|
|
|
if (!cmd)
|
2012-12-21 04:13:19 +07:00
|
|
|
return -ENOMEM;
|
2014-09-10 20:34:43 +07:00
|
|
|
if (!ie)
|
|
|
|
ie_len = 0;
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
cmd->mgmt_frm_type = type;
|
|
|
|
/* BUG: FW API define ieLen as u8. Will fix FW */
|
|
|
|
cmd->ie_len = cpu_to_le16(ie_len);
|
|
|
|
memcpy(cmd->ie_info, ie, ie_len);
|
2013-03-13 19:12:42 +07:00
|
|
|
rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);
|
2012-12-21 04:13:19 +07:00
|
|
|
kfree(cmd);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-02-27 21:20:40 +07:00
|
|
|
/**
|
|
|
|
* wmi_rxon - turn radio on/off
|
|
|
|
* @on: turn on if true, off otherwise
|
|
|
|
*
|
|
|
|
* Only switch radio. Channel should be set separately.
|
|
|
|
* No timeout for rxon - radio turned on forever unless some other call
|
|
|
|
* turns it off
|
|
|
|
*/
|
|
|
|
int wmi_rxon(struct wil6210_priv *wil, bool on)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct {
|
|
|
|
struct wil6210_mbox_hdr_wmi wmi;
|
|
|
|
struct wmi_listen_started_event evt;
|
|
|
|
} __packed reply;
|
|
|
|
|
|
|
|
wil_info(wil, "%s(%s)\n", __func__, on ? "on" : "off");
|
|
|
|
|
|
|
|
if (on) {
|
|
|
|
rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0,
|
|
|
|
WMI_LISTEN_STARTED_EVENTID,
|
|
|
|
&reply, sizeof(reply), 100);
|
|
|
|
if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS))
|
|
|
|
rc = -EINVAL;
|
|
|
|
} else {
|
|
|
|
rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0,
|
|
|
|
WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-01-28 23:30:59 +07:00
|
|
|
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
|
|
|
|
{
|
|
|
|
struct wireless_dev *wdev = wil->wdev;
|
|
|
|
struct net_device *ndev = wil_to_ndev(wil);
|
|
|
|
struct wmi_cfg_rx_chain_cmd cmd = {
|
|
|
|
.action = WMI_RX_CHAIN_ADD,
|
|
|
|
.rx_sw_ring = {
|
2014-12-23 14:47:11 +07:00
|
|
|
.max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)),
|
2013-01-28 23:30:59 +07:00
|
|
|
.ring_mem_base = cpu_to_le64(vring->pa),
|
|
|
|
.ring_size = cpu_to_le16(vring->size),
|
|
|
|
},
|
|
|
|
.mid = 0, /* TODO - what is it? */
|
|
|
|
.decap_trans_type = WMI_DECAP_TYPE_802_3,
|
2014-02-27 21:20:44 +07:00
|
|
|
.reorder_type = WMI_RX_SW_REORDER,
|
2014-12-23 14:47:20 +07:00
|
|
|
.host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
|
2013-01-28 23:30:59 +07:00
|
|
|
};
|
|
|
|
struct {
|
|
|
|
struct wil6210_mbox_hdr_wmi wmi;
|
|
|
|
struct wmi_cfg_rx_chain_done_event evt;
|
|
|
|
} __packed evt;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
|
|
|
|
struct ieee80211_channel *ch = wdev->preset_chandef.chan;
|
|
|
|
|
|
|
|
cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
|
|
|
|
if (ch)
|
|
|
|
cmd.sniffer_cfg.channel = ch->hw_value - 1;
|
|
|
|
cmd.sniffer_cfg.phy_info_mode =
|
|
|
|
cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
|
|
|
|
cmd.sniffer_cfg.phy_support =
|
|
|
|
cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
|
|
|
|
? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
|
2013-07-21 15:34:37 +07:00
|
|
|
} else {
|
|
|
|
/* Initialize offload (in non-sniffer mode).
|
|
|
|
* Linux IP stack always calculates IP checksum
|
|
|
|
* HW always calculate TCP/UDP checksum
|
|
|
|
*/
|
|
|
|
cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS);
|
2013-01-28 23:30:59 +07:00
|
|
|
}
|
|
|
|
/* typical time for secure PCP is 840ms */
|
|
|
|
rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
|
|
|
|
WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
|
|
|
|
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_misc(wil, "Rx init: status %d tail 0x%08x\n",
|
2013-01-28 23:30:59 +07:00
|
|
|
le32_to_cpu(evt.evt.status), vring->hwtail);
|
|
|
|
|
|
|
|
if (le32_to_cpu(evt.evt.status) != WMI_CFG_RX_CHAIN_SUCCESS)
|
|
|
|
rc = -EINVAL;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-03-13 19:12:51 +07:00
|
|
|
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct wmi_temp_sense_cmd cmd = {
|
|
|
|
.measure_marlon_m_en = cpu_to_le32(!!t_m),
|
|
|
|
.measure_marlon_r_en = cpu_to_le32(!!t_r),
|
|
|
|
};
|
|
|
|
struct {
|
|
|
|
struct wil6210_mbox_hdr_wmi wmi;
|
|
|
|
struct wmi_temp_sense_done_event evt;
|
|
|
|
} __packed reply;
|
|
|
|
|
|
|
|
rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd),
|
|
|
|
WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (t_m)
|
|
|
|
*t_m = le32_to_cpu(reply.evt.marlon_m_t1000);
|
|
|
|
if (t_r)
|
|
|
|
*t_r = le32_to_cpu(reply.evt.marlon_r_t1000);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-27 21:20:54 +07:00
|
|
|
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
|
|
|
|
{
|
|
|
|
struct wmi_disconnect_sta_cmd cmd = {
|
|
|
|
.disconnect_reason = cpu_to_le16(reason),
|
|
|
|
};
|
|
|
|
memcpy(cmd.dst_mac, mac, ETH_ALEN);
|
|
|
|
|
|
|
|
wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason);
|
|
|
|
|
|
|
|
return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
|
|
|
|
{
|
|
|
|
struct wmi_vring_ba_en_cmd cmd = {
|
|
|
|
.ringid = ringid,
|
|
|
|
.agg_max_wsize = size,
|
|
|
|
.ba_timeout = cpu_to_le16(timeout),
|
2014-12-23 14:47:09 +07:00
|
|
|
.amsdu = 0,
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
wil_dbg_wmi(wil, "%s(ring %d size %d timeout %d)\n", __func__,
|
|
|
|
ringid, size, timeout);
|
|
|
|
|
|
|
|
return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
2014-12-23 14:47:10 +07:00
|
|
|
int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
{
|
|
|
|
struct wmi_vring_ba_dis_cmd cmd = {
|
|
|
|
.ringid = ringid,
|
|
|
|
.reason = cpu_to_le16(reason),
|
|
|
|
};
|
|
|
|
|
|
|
|
wil_dbg_wmi(wil, "%s(ring %d reason %d)\n", __func__,
|
|
|
|
ringid, reason);
|
|
|
|
|
|
|
|
return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
2014-12-23 14:47:10 +07:00
|
|
|
int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
|
|
|
|
{
|
|
|
|
struct wmi_rcp_delba_cmd cmd = {
|
|
|
|
.cidxtid = cidxtid,
|
|
|
|
.reason = cpu_to_le16(reason),
|
|
|
|
};
|
|
|
|
|
|
|
|
wil_dbg_wmi(wil, "%s(CID %d TID %d reason %d)\n", __func__,
|
|
|
|
cidxtid & 0xf, (cidxtid >> 4) & 0xf, reason);
|
|
|
|
|
|
|
|
return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
|
|
|
|
}
|
|
|
|
|
wil6210: ADDBA/DELBA flows
Introduce BACK establishment procedures; decision logic is not implemented
yet; debugfs entry 'addba' used to manually trigger addba/delba for ringid 0.
debugfs usage:
to establish BACK with agg_wsize 16:
echo 16 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to delete BACK:
echo 0 > /sys/kernel/debug/ieee80211/phy0/wil6210/addba
to change agg_wsize, one need to delete BACK and establish it anew
ADDBA flow for:
- originator
Tx side (initiator) sends WMI_VRING_BA_EN_CMDID providing
agg_wsize and timeout parameters.
Eventually, it gets event confirming BACK agreement - WMI_BA_STATUS_EVENTID
with negotiated parameters. On this event, update Tx vring data
(struct vring_tx_data) and display BACK parameters on debugfs
- recipient
Rx side (recipient) firmware informs driver about ADDBA with
WMI_RCP_ADDBA_REQ_EVENTID, driver process it in service work
queue wq_service. It adjusts parameters and sends response
with WMI_RCP_ADDBA_RESP_CMDID, and final confirmation provided
by firmware with WMI_ADDBA_RESP_SENT_EVENTID. In case of success,
driver updates Rx BACK reorder buffer.
policy for BACK parameters:
- aggregation size (agg_wsize * MPDUsize)) to not exceed 64Kbytes
DELBA flow for:
- originator
driver decides to terminate BACK, it sends WMI_VRING_BA_DIS_CMDID
and updates struct vring_tx_data associated with vring; ignore
WMI_DELBA_EVENTID.
- recipient
firmware informs driver with WMI_DELBA_EVENTID,
driver deletes correspondent reorder buffer
ADDBA request processing requires sending WMI command, therefore
it is processed in work queue context. Same work queue used as for
connect, it get renamed to wq_service
Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2014-12-23 14:47:03 +07:00
|
|
|
int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
|
|
|
|
u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct wmi_rcp_addba_resp_cmd cmd = {
|
|
|
|
.cidxtid = mk_cidxtid(cid, tid),
|
|
|
|
.dialog_token = token,
|
|
|
|
.status_code = cpu_to_le16(status),
|
|
|
|
/* bit 0: A-MSDU supported
|
|
|
|
* bit 1: policy (should be 0 for us)
|
|
|
|
* bits 2..5: TID
|
|
|
|
* bits 6..15: buffer size
|
|
|
|
*/
|
|
|
|
.ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
|
|
|
|
(agg_wsize << 6)),
|
|
|
|
.ba_timeout = cpu_to_le16(timeout),
|
|
|
|
};
|
|
|
|
struct {
|
|
|
|
struct wil6210_mbox_hdr_wmi wmi;
|
|
|
|
struct wmi_rcp_addba_resp_sent_event evt;
|
|
|
|
} __packed reply;
|
|
|
|
|
|
|
|
wil_dbg_wmi(wil,
|
|
|
|
"ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
|
|
|
|
cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
|
|
|
|
|
|
|
|
rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
|
|
|
|
WMI_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), 100);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (reply.evt.status) {
|
|
|
|
wil_err(wil, "ADDBA response failed with status %d\n",
|
|
|
|
le16_to_cpu(reply.evt.status));
|
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-12-21 04:13:19 +07:00
|
|
|
void wmi_event_flush(struct wil6210_priv *wil)
|
|
|
|
{
|
|
|
|
struct pending_wmi_event *evt, *t;
|
|
|
|
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "%s()\n", __func__);
|
2012-12-21 04:13:19 +07:00
|
|
|
|
|
|
|
list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
|
|
|
|
list_del(&evt->list);
|
|
|
|
kfree(evt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
|
|
|
|
void *d, int len)
|
|
|
|
{
|
|
|
|
uint i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
|
|
|
|
if (wmi_evt_handlers[i].eventid == id) {
|
|
|
|
wmi_evt_handlers[i].handler(wil, id, d, len);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wmi_event_handle(struct wil6210_priv *wil,
|
|
|
|
struct wil6210_mbox_hdr *hdr)
|
|
|
|
{
|
|
|
|
u16 len = le16_to_cpu(hdr->len);
|
|
|
|
|
|
|
|
if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
|
|
|
|
(len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
|
|
|
|
struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
|
|
|
|
void *evt_data = (void *)(&wmi[1]);
|
|
|
|
u16 id = le16_to_cpu(wmi->id);
|
2014-09-10 20:34:33 +07:00
|
|
|
|
|
|
|
wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n",
|
|
|
|
id, wil->reply_id);
|
2012-12-21 04:13:19 +07:00
|
|
|
/* check if someone waits for this event */
|
|
|
|
if (wil->reply_id && wil->reply_id == id) {
|
|
|
|
if (wil->reply_buf) {
|
|
|
|
memcpy(wil->reply_buf, wmi,
|
|
|
|
min(len, wil->reply_size));
|
|
|
|
} else {
|
|
|
|
wmi_evt_call_handler(wil, id, evt_data,
|
|
|
|
len - sizeof(*wmi));
|
|
|
|
}
|
2013-01-28 23:31:06 +07:00
|
|
|
wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
|
2014-09-10 20:34:46 +07:00
|
|
|
complete(&wil->wmi_call);
|
2012-12-21 04:13:19 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* unsolicited event */
|
|
|
|
/* search for handler */
|
|
|
|
if (!wmi_evt_call_handler(wil, id, evt_data,
|
|
|
|
len - sizeof(*wmi))) {
|
|
|
|
wil_err(wil, "Unhandled event 0x%04x\n", id);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
wil_err(wil, "Unknown event type\n");
|
|
|
|
print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
|
|
|
|
hdr, sizeof(*hdr) + len, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve next WMI event from the pending list
|
|
|
|
*/
|
|
|
|
static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
|
|
|
|
{
|
|
|
|
ulong flags;
|
|
|
|
struct list_head *ret = NULL;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
|
|
|
|
|
|
|
if (!list_empty(&wil->pending_wmi_ev)) {
|
|
|
|
ret = wil->pending_wmi_ev.next;
|
|
|
|
list_del(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handler for the WMI events
|
|
|
|
*/
|
|
|
|
void wmi_event_worker(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
|
|
|
wmi_event_worker);
|
|
|
|
struct pending_wmi_event *evt;
|
|
|
|
struct list_head *lh;
|
|
|
|
|
2014-09-10 20:34:33 +07:00
|
|
|
wil_dbg_wmi(wil, "Start %s\n", __func__);
|
2012-12-21 04:13:19 +07:00
|
|
|
while ((lh = next_wmi_ev(wil)) != NULL) {
|
|
|
|
evt = list_entry(lh, struct pending_wmi_event, list);
|
|
|
|
wmi_event_handle(wil, &evt->event.hdr);
|
|
|
|
kfree(evt);
|
|
|
|
}
|
2014-09-10 20:34:33 +07:00
|
|
|
wil_dbg_wmi(wil, "Finished %s\n", __func__);
|
2012-12-21 04:13:19 +07:00
|
|
|
}
|