Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: 1) Seccomp BPF filters can now be JIT'd, from Alexei Starovoitov. 2) Multiqueue support in xen-netback and xen-netfront, from Andrew J Benniston. 3) Allow tweaking of aggregation settings in cdc_ncm driver, from Bjørn Mork. 4) BPF now has a "random" opcode, from Chema Gonzalez. 5) Add more BPF documentation and improve test framework, from Daniel Borkmann. 6) Support TCP fastopen over ipv6, from Daniel Lee. 7) Add software TSO helper functions and use them to support software TSO in mvneta and mv643xx_eth drivers. From Ezequiel Garcia. 8) Support software TSO in fec driver too, from Nimrod Andy. 9) Add Broadcom SYSTEMPORT driver, from Florian Fainelli. 10) Handle broadcasts more gracefully over macvlan when there are large numbers of interfaces configured, from Herbert Xu. 11) Allow more control over fwmark used for non-socket based responses, from Lorenzo Colitti. 12) Do TCP congestion window limiting based upon measurements, from Neal Cardwell. 13) Support busy polling in SCTP, from Neal Horman. 14) Allow RSS key to be configured via ethtool, from Venkata Duvvuru. 15) Bridge promisc mode handling improvements from Vlad Yasevich. 16) Don't use inetpeer entries to implement ID generation any more, it performs poorly, from Eric Dumazet. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1522 commits) rtnetlink: fix userspace API breakage for iproute2 < v3.9.0 tcp: fixing TLP's FIN recovery net: fec: Add software TSO support net: fec: Add Scatter/gather support net: fec: Increase buffer descriptor entry number net: fec: Factorize feature setting net: fec: Enable IP header hardware checksum net: fec: Factorize the .xmit transmit function bridge: fix compile error when compiling without IPv6 support bridge: fix smatch warning / potential null pointer dereference via-rhine: fix full-duplex with autoneg disable bnx2x: Enlarge the dorq threshold for VFs bnx2x: Check for UNDI in uncommon branch bnx2x: Fix 1G-baseT link bnx2x: Fix link for KR with swapped polarity lane sctp: Fix sk_ack_backlog wrap-around problem net/core: Add VF link state control policy net/fsl: xgmac_mdio is dependent on OF_MDIO net/fsl: Make xgmac_mdio read error message useful net_sched: drr: warn when qdisc is not work conserving ...
This commit is contained in:
@@ -175,7 +175,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
|
||||
int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
@@ -184,7 +184,7 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
|
||||
address, *param);
|
||||
address, param);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn("command disallowed\n");
|
||||
@@ -193,7 +193,7 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_EXECUTE);
|
||||
cmd.execute.addr = __cpu_to_le32(address);
|
||||
cmd.execute.param = __cpu_to_le32(*param);
|
||||
cmd.execute.param = __cpu_to_le32(param);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
|
||||
if (ret) {
|
||||
@@ -204,10 +204,13 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
|
||||
if (resplen < sizeof(resp.execute)) {
|
||||
ath10k_warn("invalid execute response length (%d)\n",
|
||||
resplen);
|
||||
return ret;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*param = __le32_to_cpu(resp.execute.result);
|
||||
*result = __le32_to_cpu(resp.execute.result);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -201,7 +201,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
|
||||
\
|
||||
addr = host_interest_item_address(HI_ITEM(item)); \
|
||||
ret = ath10k_bmi_read_memory(ar, addr, (u8 *)&tmp, 4); \
|
||||
*val = __le32_to_cpu(tmp); \
|
||||
if (!ret) \
|
||||
*val = __le32_to_cpu(tmp); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
@@ -217,7 +218,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
|
||||
ret; \
|
||||
})
|
||||
|
||||
int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param);
|
||||
int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result);
|
||||
int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address);
|
||||
int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length);
|
||||
int ath10k_bmi_fast_download(struct ath10k *ar, u32 address,
|
||||
|
@@ -329,6 +329,33 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe)
|
||||
{
|
||||
struct ath10k *ar = pipe->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_ring *src_ring = pipe->src_ring;
|
||||
u32 ctrl_addr = pipe->ctrl_addr;
|
||||
|
||||
lockdep_assert_held(&ar_pci->ce_lock);
|
||||
|
||||
/*
|
||||
* This function must be called only if there is an incomplete
|
||||
* scatter-gather transfer (before index register is updated)
|
||||
* that needs to be cleaned up.
|
||||
*/
|
||||
if (WARN_ON_ONCE(src_ring->write_index == src_ring->sw_index))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(src_ring->write_index ==
|
||||
ath10k_ce_src_ring_write_index_get(ar, ctrl_addr)))
|
||||
return;
|
||||
|
||||
src_ring->write_index--;
|
||||
src_ring->write_index &= src_ring->nentries_mask;
|
||||
|
||||
src_ring->per_transfer_context[src_ring->write_index] = NULL;
|
||||
}
|
||||
|
||||
int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_context,
|
||||
u32 buffer,
|
||||
@@ -840,35 +867,17 @@ void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
|
||||
|
||||
static int ath10k_ce_init_src_ring(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
struct ath10k_ce_pipe *ce_state,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_ring *src_ring;
|
||||
unsigned int nentries = attr->src_nentries;
|
||||
unsigned int ce_nbytes;
|
||||
u32 ctrl_addr = ath10k_ce_base_address(ce_id);
|
||||
dma_addr_t base_addr;
|
||||
char *ptr;
|
||||
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
|
||||
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
|
||||
u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id);
|
||||
|
||||
nentries = roundup_pow_of_two(nentries);
|
||||
nentries = roundup_pow_of_two(attr->src_nentries);
|
||||
|
||||
if (ce_state->src_ring) {
|
||||
WARN_ON(ce_state->src_ring->nentries != nentries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *));
|
||||
ptr = kzalloc(ce_nbytes, GFP_KERNEL);
|
||||
if (ptr == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ce_state->src_ring = (struct ath10k_ce_ring *)ptr;
|
||||
src_ring = ce_state->src_ring;
|
||||
|
||||
ptr += sizeof(struct ath10k_ce_ring);
|
||||
src_ring->nentries = nentries;
|
||||
src_ring->nentries_mask = nentries - 1;
|
||||
memset(src_ring->per_transfer_context, 0,
|
||||
nentries * sizeof(*src_ring->per_transfer_context));
|
||||
|
||||
src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
|
||||
src_ring->sw_index &= src_ring->nentries_mask;
|
||||
@@ -878,21 +887,87 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
|
||||
ath10k_ce_src_ring_write_index_get(ar, ctrl_addr);
|
||||
src_ring->write_index &= src_ring->nentries_mask;
|
||||
|
||||
src_ring->per_transfer_context = (void **)ptr;
|
||||
ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr,
|
||||
src_ring->base_addr_ce_space);
|
||||
ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries);
|
||||
ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max);
|
||||
ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT,
|
||||
"boot init ce src ring id %d entries %d base_addr %p\n",
|
||||
ce_id, nentries, src_ring->base_addr_owner_space);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_ce_init_dest_ring(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
|
||||
struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
|
||||
u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id);
|
||||
|
||||
nentries = roundup_pow_of_two(attr->dest_nentries);
|
||||
|
||||
memset(dest_ring->per_transfer_context, 0,
|
||||
nentries * sizeof(*dest_ring->per_transfer_context));
|
||||
|
||||
dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr);
|
||||
dest_ring->sw_index &= dest_ring->nentries_mask;
|
||||
dest_ring->write_index =
|
||||
ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr);
|
||||
dest_ring->write_index &= dest_ring->nentries_mask;
|
||||
|
||||
ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr,
|
||||
dest_ring->base_addr_ce_space);
|
||||
ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries);
|
||||
ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT,
|
||||
"boot ce dest ring id %d entries %d base_addr %p\n",
|
||||
ce_id, nentries, dest_ring->base_addr_owner_space);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ath10k_ce_ring *
|
||||
ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k_ce_ring *src_ring;
|
||||
u32 nentries = attr->src_nentries;
|
||||
dma_addr_t base_addr;
|
||||
|
||||
nentries = roundup_pow_of_two(nentries);
|
||||
|
||||
src_ring = kzalloc(sizeof(*src_ring) +
|
||||
(nentries *
|
||||
sizeof(*src_ring->per_transfer_context)),
|
||||
GFP_KERNEL);
|
||||
if (src_ring == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
src_ring->nentries = nentries;
|
||||
src_ring->nentries_mask = nentries - 1;
|
||||
|
||||
/*
|
||||
* Legacy platforms that do not support cache
|
||||
* coherent DMA are unsupported
|
||||
*/
|
||||
src_ring->base_addr_owner_space_unaligned =
|
||||
pci_alloc_consistent(ar_pci->pdev,
|
||||
(nentries * sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
&base_addr);
|
||||
dma_alloc_coherent(ar->dev,
|
||||
(nentries * sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
&base_addr, GFP_KERNEL);
|
||||
if (!src_ring->base_addr_owner_space_unaligned) {
|
||||
kfree(ce_state->src_ring);
|
||||
ce_state->src_ring = NULL;
|
||||
return -ENOMEM;
|
||||
kfree(src_ring);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
src_ring->base_addr_ce_space_unaligned = base_addr;
|
||||
@@ -912,88 +987,54 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
|
||||
kmalloc((nentries * sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN), GFP_KERNEL);
|
||||
if (!src_ring->shadow_base_unaligned) {
|
||||
pci_free_consistent(ar_pci->pdev,
|
||||
(nentries * sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
src_ring->base_addr_owner_space,
|
||||
src_ring->base_addr_ce_space);
|
||||
kfree(ce_state->src_ring);
|
||||
ce_state->src_ring = NULL;
|
||||
return -ENOMEM;
|
||||
dma_free_coherent(ar->dev,
|
||||
(nentries * sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
src_ring->base_addr_owner_space,
|
||||
src_ring->base_addr_ce_space);
|
||||
kfree(src_ring);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
src_ring->shadow_base = PTR_ALIGN(
|
||||
src_ring->shadow_base_unaligned,
|
||||
CE_DESC_RING_ALIGN);
|
||||
|
||||
ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr,
|
||||
src_ring->base_addr_ce_space);
|
||||
ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries);
|
||||
ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, attr->src_sz_max);
|
||||
ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT,
|
||||
"boot ce src ring id %d entries %d base_addr %p\n",
|
||||
ce_id, nentries, src_ring->base_addr_owner_space);
|
||||
|
||||
return 0;
|
||||
return src_ring;
|
||||
}
|
||||
|
||||
static int ath10k_ce_init_dest_ring(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
struct ath10k_ce_pipe *ce_state,
|
||||
const struct ce_attr *attr)
|
||||
static struct ath10k_ce_ring *
|
||||
ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_ring *dest_ring;
|
||||
unsigned int nentries = attr->dest_nentries;
|
||||
unsigned int ce_nbytes;
|
||||
u32 ctrl_addr = ath10k_ce_base_address(ce_id);
|
||||
u32 nentries;
|
||||
dma_addr_t base_addr;
|
||||
char *ptr;
|
||||
|
||||
nentries = roundup_pow_of_two(nentries);
|
||||
nentries = roundup_pow_of_two(attr->dest_nentries);
|
||||
|
||||
if (ce_state->dest_ring) {
|
||||
WARN_ON(ce_state->dest_ring->nentries != nentries);
|
||||
return 0;
|
||||
}
|
||||
dest_ring = kzalloc(sizeof(*dest_ring) +
|
||||
(nentries *
|
||||
sizeof(*dest_ring->per_transfer_context)),
|
||||
GFP_KERNEL);
|
||||
if (dest_ring == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *));
|
||||
ptr = kzalloc(ce_nbytes, GFP_KERNEL);
|
||||
if (ptr == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ce_state->dest_ring = (struct ath10k_ce_ring *)ptr;
|
||||
dest_ring = ce_state->dest_ring;
|
||||
|
||||
ptr += sizeof(struct ath10k_ce_ring);
|
||||
dest_ring->nentries = nentries;
|
||||
dest_ring->nentries_mask = nentries - 1;
|
||||
|
||||
dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr);
|
||||
dest_ring->sw_index &= dest_ring->nentries_mask;
|
||||
dest_ring->write_index =
|
||||
ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr);
|
||||
dest_ring->write_index &= dest_ring->nentries_mask;
|
||||
|
||||
dest_ring->per_transfer_context = (void **)ptr;
|
||||
|
||||
/*
|
||||
* Legacy platforms that do not support cache
|
||||
* coherent DMA are unsupported
|
||||
*/
|
||||
dest_ring->base_addr_owner_space_unaligned =
|
||||
pci_alloc_consistent(ar_pci->pdev,
|
||||
(nentries * sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
&base_addr);
|
||||
dma_alloc_coherent(ar->dev,
|
||||
(nentries * sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
&base_addr, GFP_KERNEL);
|
||||
if (!dest_ring->base_addr_owner_space_unaligned) {
|
||||
kfree(ce_state->dest_ring);
|
||||
ce_state->dest_ring = NULL;
|
||||
return -ENOMEM;
|
||||
kfree(dest_ring);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
dest_ring->base_addr_ce_space_unaligned = base_addr;
|
||||
@@ -1012,39 +1053,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
|
||||
dest_ring->base_addr_ce_space_unaligned,
|
||||
CE_DESC_RING_ALIGN);
|
||||
|
||||
ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr,
|
||||
dest_ring->base_addr_ce_space);
|
||||
ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries);
|
||||
ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT,
|
||||
"boot ce dest ring id %d entries %d base_addr %p\n",
|
||||
ce_id, nentries, dest_ring->base_addr_owner_space);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ath10k_ce_pipe *ath10k_ce_init_state(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
|
||||
u32 ctrl_addr = ath10k_ce_base_address(ce_id);
|
||||
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
|
||||
ce_state->ar = ar;
|
||||
ce_state->id = ce_id;
|
||||
ce_state->ctrl_addr = ctrl_addr;
|
||||
ce_state->attr_flags = attr->flags;
|
||||
ce_state->src_sz_max = attr->src_sz_max;
|
||||
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
|
||||
return ce_state;
|
||||
return dest_ring;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1054,11 +1063,11 @@ static struct ath10k_ce_pipe *ath10k_ce_init_state(struct ath10k *ar,
|
||||
* initialization. It may be that only one side or the other is
|
||||
* initialized by software/firmware.
|
||||
*/
|
||||
struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
const struct ce_attr *attr)
|
||||
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k_ce_pipe *ce_state;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -1074,64 +1083,128 @@ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
return NULL;
|
||||
return ret;
|
||||
|
||||
ce_state = ath10k_ce_init_state(ar, ce_id, attr);
|
||||
if (!ce_state) {
|
||||
ath10k_err("Failed to initialize CE state for ID: %d\n", ce_id);
|
||||
goto out;
|
||||
}
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
ce_state->ar = ar;
|
||||
ce_state->id = ce_id;
|
||||
ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
|
||||
ce_state->attr_flags = attr->flags;
|
||||
ce_state->src_sz_max = attr->src_sz_max;
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
|
||||
if (attr->src_nentries) {
|
||||
ret = ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr);
|
||||
ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
|
||||
if (ret) {
|
||||
ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
|
||||
ce_id, ret);
|
||||
ath10k_ce_deinit(ce_state);
|
||||
ce_state = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr->dest_nentries) {
|
||||
ret = ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr);
|
||||
ret = ath10k_ce_init_dest_ring(ar, ce_id, attr);
|
||||
if (ret) {
|
||||
ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
|
||||
ce_id, ret);
|
||||
ath10k_ce_deinit(ce_state);
|
||||
ce_state = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
ath10k_pci_sleep(ar);
|
||||
return ce_state;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state)
|
||||
static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id)
|
||||
{
|
||||
u32 ctrl_addr = ath10k_ce_base_address(ce_id);
|
||||
|
||||
ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_src_ring_dmax_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, 0);
|
||||
}
|
||||
|
||||
static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id)
|
||||
{
|
||||
u32 ctrl_addr = ath10k_ce_base_address(ce_id);
|
||||
|
||||
ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0);
|
||||
ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, 0);
|
||||
}
|
||||
|
||||
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
ath10k_ce_deinit_src_ring(ar, ce_id);
|
||||
ath10k_ce_deinit_dest_ring(ar, ce_id);
|
||||
|
||||
ath10k_pci_sleep(ar);
|
||||
}
|
||||
|
||||
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
|
||||
int ret;
|
||||
|
||||
if (attr->src_nentries) {
|
||||
ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
|
||||
if (IS_ERR(ce_state->src_ring)) {
|
||||
ret = PTR_ERR(ce_state->src_ring);
|
||||
ath10k_err("failed to allocate copy engine source ring %d: %d\n",
|
||||
ce_id, ret);
|
||||
ce_state->src_ring = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr->dest_nentries) {
|
||||
ce_state->dest_ring = ath10k_ce_alloc_dest_ring(ar, ce_id,
|
||||
attr);
|
||||
if (IS_ERR(ce_state->dest_ring)) {
|
||||
ret = PTR_ERR(ce_state->dest_ring);
|
||||
ath10k_err("failed to allocate copy engine destination ring %d: %d\n",
|
||||
ce_id, ret);
|
||||
ce_state->dest_ring = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
|
||||
|
||||
if (ce_state->src_ring) {
|
||||
kfree(ce_state->src_ring->shadow_base_unaligned);
|
||||
pci_free_consistent(ar_pci->pdev,
|
||||
(ce_state->src_ring->nentries *
|
||||
sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
ce_state->src_ring->base_addr_owner_space,
|
||||
ce_state->src_ring->base_addr_ce_space);
|
||||
dma_free_coherent(ar->dev,
|
||||
(ce_state->src_ring->nentries *
|
||||
sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
ce_state->src_ring->base_addr_owner_space,
|
||||
ce_state->src_ring->base_addr_ce_space);
|
||||
kfree(ce_state->src_ring);
|
||||
}
|
||||
|
||||
if (ce_state->dest_ring) {
|
||||
pci_free_consistent(ar_pci->pdev,
|
||||
(ce_state->dest_ring->nentries *
|
||||
sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
ce_state->dest_ring->base_addr_owner_space,
|
||||
ce_state->dest_ring->base_addr_ce_space);
|
||||
dma_free_coherent(ar->dev,
|
||||
(ce_state->dest_ring->nentries *
|
||||
sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
ce_state->dest_ring->base_addr_owner_space,
|
||||
ce_state->dest_ring->base_addr_ce_space);
|
||||
kfree(ce_state->dest_ring);
|
||||
}
|
||||
|
||||
|
@@ -104,7 +104,8 @@ struct ath10k_ce_ring {
|
||||
void *shadow_base_unaligned;
|
||||
struct ce_desc *shadow_base;
|
||||
|
||||
void **per_transfer_context;
|
||||
/* keep last */
|
||||
void *per_transfer_context[0];
|
||||
};
|
||||
|
||||
struct ath10k_ce_pipe {
|
||||
@@ -159,6 +160,8 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
unsigned int transfer_id,
|
||||
unsigned int flags);
|
||||
|
||||
void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe);
|
||||
|
||||
void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
|
||||
void (*send_cb)(struct ath10k_ce_pipe *),
|
||||
int disable_interrupts);
|
||||
@@ -210,10 +213,12 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
|
||||
|
||||
/*==================CE Engine Initialization=======================*/
|
||||
|
||||
/* Initialize an instance of a CE */
|
||||
struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
const struct ce_attr *attr);
|
||||
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
|
||||
const struct ce_attr *attr);
|
||||
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
|
||||
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
|
||||
const struct ce_attr *attr);
|
||||
void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
|
||||
|
||||
/*==================CE Engine Shutdown=======================*/
|
||||
/*
|
||||
@@ -236,8 +241,6 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp);
|
||||
|
||||
void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state);
|
||||
|
||||
/*==================CE Interrupt Handlers====================*/
|
||||
void ath10k_ce_per_engine_service_any(struct ath10k *ar);
|
||||
void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
|
||||
|
@@ -58,36 +58,6 @@ static void ath10k_send_suspend_complete(struct ath10k *ar)
|
||||
complete(&ar->target_suspend);
|
||||
}
|
||||
|
||||
static int ath10k_init_connect_htc(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = ath10k_wmi_connect_htc_service(ar);
|
||||
if (status)
|
||||
goto conn_fail;
|
||||
|
||||
/* Start HTC */
|
||||
status = ath10k_htc_start(&ar->htc);
|
||||
if (status)
|
||||
goto conn_fail;
|
||||
|
||||
/* Wait for WMI event to be ready */
|
||||
status = ath10k_wmi_wait_for_service_ready(ar);
|
||||
if (status <= 0) {
|
||||
ath10k_warn("wmi service ready event not received");
|
||||
status = -ETIMEDOUT;
|
||||
goto timeout;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot wmi ready\n");
|
||||
return 0;
|
||||
|
||||
timeout:
|
||||
ath10k_htc_stop(&ar->htc);
|
||||
conn_fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ath10k_init_configure_target(struct ath10k *ar)
|
||||
{
|
||||
u32 param_host;
|
||||
@@ -249,30 +219,40 @@ exit:
|
||||
|
||||
static int ath10k_download_and_run_otp(struct ath10k *ar)
|
||||
{
|
||||
u32 address = ar->hw_params.patch_load_addr;
|
||||
u32 exec_param;
|
||||
u32 result, address = ar->hw_params.patch_load_addr;
|
||||
int ret;
|
||||
|
||||
/* OTP is optional */
|
||||
|
||||
if (!ar->otp_data || !ar->otp_len)
|
||||
if (!ar->otp_data || !ar->otp_len) {
|
||||
ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
|
||||
ar->otp_data, ar->otp_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
|
||||
address, ar->otp_len);
|
||||
|
||||
ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
|
||||
if (ret) {
|
||||
ath10k_err("could not write otp (%d)\n", ret);
|
||||
goto exit;
|
||||
return ret;
|
||||
}
|
||||
|
||||
exec_param = 0;
|
||||
ret = ath10k_bmi_execute(ar, address, &exec_param);
|
||||
ret = ath10k_bmi_execute(ar, address, 0, &result);
|
||||
if (ret) {
|
||||
ath10k_err("could not execute otp (%d)\n", ret);
|
||||
goto exit;
|
||||
return ret;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
|
||||
|
||||
if (result != 0) {
|
||||
ath10k_err("otp calibration failed: %d", result);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_download_fw(struct ath10k *ar)
|
||||
@@ -389,8 +369,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
|
||||
/* first fetch the firmware file (firmware-*.bin) */
|
||||
ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
|
||||
if (IS_ERR(ar->firmware)) {
|
||||
ath10k_err("Could not fetch firmware file '%s': %ld\n",
|
||||
name, PTR_ERR(ar->firmware));
|
||||
ath10k_err("could not fetch firmware file '%s/%s': %ld\n",
|
||||
ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware));
|
||||
return PTR_ERR(ar->firmware);
|
||||
}
|
||||
|
||||
@@ -401,14 +381,14 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
|
||||
magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
|
||||
|
||||
if (len < magic_len) {
|
||||
ath10k_err("firmware image too small to contain magic: %zu\n",
|
||||
len);
|
||||
ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n",
|
||||
ar->hw_params.fw.dir, name, len);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
|
||||
ath10k_err("Invalid firmware magic\n");
|
||||
ath10k_err("invalid firmware magic\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
@@ -430,7 +410,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
|
||||
data += sizeof(*hdr);
|
||||
|
||||
if (len < ie_len) {
|
||||
ath10k_err("Invalid length for FW IE %d (%zu < %zu)\n",
|
||||
ath10k_err("invalid length for FW IE %d (%zu < %zu)\n",
|
||||
ie_id, len, ie_len);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
@@ -513,8 +493,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
|
||||
}
|
||||
|
||||
if (!ar->firmware_data || !ar->firmware_len) {
|
||||
ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from %s, skipping\n",
|
||||
name);
|
||||
ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
|
||||
ar->hw_params.fw.dir, name);
|
||||
ret = -ENOMEDIUM;
|
||||
goto err;
|
||||
}
|
||||
@@ -531,7 +511,9 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
|
||||
ar->hw_params.fw.board);
|
||||
if (IS_ERR(ar->board)) {
|
||||
ret = PTR_ERR(ar->board);
|
||||
ath10k_err("could not fetch board data (%d)\n", ret);
|
||||
ath10k_err("could not fetch board data '%s/%s' (%d)\n",
|
||||
ar->hw_params.fw.dir, ar->hw_params.fw.board,
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -549,19 +531,21 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ar->fw_api = 2;
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
|
||||
|
||||
ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
|
||||
if (ret == 0) {
|
||||
ar->fw_api = 2;
|
||||
goto out;
|
||||
}
|
||||
if (ret == 0)
|
||||
goto success;
|
||||
|
||||
ar->fw_api = 1;
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
|
||||
|
||||
ret = ath10k_core_fetch_firmware_api_1(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ar->fw_api = 1;
|
||||
|
||||
out:
|
||||
success:
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
|
||||
|
||||
return 0;
|
||||
@@ -572,16 +556,22 @@ static int ath10k_init_download_firmware(struct ath10k *ar)
|
||||
int ret;
|
||||
|
||||
ret = ath10k_download_board_data(ar);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_err("failed to download board data: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_download_and_run_otp(ar);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_err("failed to run otp: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_download_fw(ar);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath10k_err("failed to download firmware: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -660,8 +650,9 @@ static void ath10k_core_restart(struct work_struct *work)
|
||||
|
||||
switch (ar->state) {
|
||||
case ATH10K_STATE_ON:
|
||||
ath10k_halt(ar);
|
||||
ar->state = ATH10K_STATE_RESTARTING;
|
||||
del_timer_sync(&ar->scan.timeout);
|
||||
ath10k_reset_scan((unsigned long)ar);
|
||||
ieee80211_restart_hw(ar->hw);
|
||||
break;
|
||||
case ATH10K_STATE_OFF:
|
||||
@@ -670,6 +661,8 @@ static void ath10k_core_restart(struct work_struct *work)
|
||||
ath10k_warn("cannot restart a device that hasn't been started\n");
|
||||
break;
|
||||
case ATH10K_STATE_RESTARTING:
|
||||
/* hw restart might be requested from multiple places */
|
||||
break;
|
||||
case ATH10K_STATE_RESTARTED:
|
||||
ar->state = ATH10K_STATE_WEDGED;
|
||||
/* fall through */
|
||||
@@ -681,70 +674,6 @@ static void ath10k_core_restart(struct work_struct *work)
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
||||
|
||||
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
||||
const struct ath10k_hif_ops *hif_ops)
|
||||
{
|
||||
struct ath10k *ar;
|
||||
|
||||
ar = ath10k_mac_create();
|
||||
if (!ar)
|
||||
return NULL;
|
||||
|
||||
ar->ath_common.priv = ar;
|
||||
ar->ath_common.hw = ar->hw;
|
||||
|
||||
ar->p2p = !!ath10k_p2p;
|
||||
ar->dev = dev;
|
||||
|
||||
ar->hif.priv = hif_priv;
|
||||
ar->hif.ops = hif_ops;
|
||||
|
||||
init_completion(&ar->scan.started);
|
||||
init_completion(&ar->scan.completed);
|
||||
init_completion(&ar->scan.on_channel);
|
||||
init_completion(&ar->target_suspend);
|
||||
|
||||
init_completion(&ar->install_key_done);
|
||||
init_completion(&ar->vdev_setup_done);
|
||||
|
||||
setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
|
||||
|
||||
ar->workqueue = create_singlethread_workqueue("ath10k_wq");
|
||||
if (!ar->workqueue)
|
||||
goto err_wq;
|
||||
|
||||
mutex_init(&ar->conf_mutex);
|
||||
spin_lock_init(&ar->data_lock);
|
||||
|
||||
INIT_LIST_HEAD(&ar->peers);
|
||||
init_waitqueue_head(&ar->peer_mapping_wq);
|
||||
|
||||
init_completion(&ar->offchan_tx_completed);
|
||||
INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
|
||||
skb_queue_head_init(&ar->offchan_tx_queue);
|
||||
|
||||
INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
|
||||
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
|
||||
|
||||
INIT_WORK(&ar->restart_work, ath10k_core_restart);
|
||||
|
||||
return ar;
|
||||
|
||||
err_wq:
|
||||
ath10k_mac_destroy(ar);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_create);
|
||||
|
||||
void ath10k_core_destroy(struct ath10k *ar)
|
||||
{
|
||||
flush_workqueue(ar->workqueue);
|
||||
destroy_workqueue(ar->workqueue);
|
||||
|
||||
ath10k_mac_destroy(ar);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_destroy);
|
||||
|
||||
int ath10k_core_start(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
@@ -785,10 +714,28 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = ath10k_htt_init(ar);
|
||||
if (status) {
|
||||
ath10k_err("failed to init htt: %d\n", status);
|
||||
goto err_wmi_detach;
|
||||
}
|
||||
|
||||
status = ath10k_htt_tx_alloc(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err("failed to alloc htt tx: %d\n", status);
|
||||
goto err_wmi_detach;
|
||||
}
|
||||
|
||||
status = ath10k_htt_rx_alloc(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err("failed to alloc htt rx: %d\n", status);
|
||||
goto err_htt_tx_detach;
|
||||
}
|
||||
|
||||
status = ath10k_hif_start(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not start HIF: %d\n", status);
|
||||
goto err_wmi_detach;
|
||||
goto err_htt_rx_detach;
|
||||
}
|
||||
|
||||
status = ath10k_htc_wait_target(&ar->htc);
|
||||
@@ -797,15 +744,30 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
status = ath10k_htt_attach(ar);
|
||||
status = ath10k_htt_connect(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err("could not attach htt (%d)\n", status);
|
||||
ath10k_err("failed to connect htt (%d)\n", status);
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
status = ath10k_init_connect_htc(ar);
|
||||
if (status)
|
||||
goto err_htt_detach;
|
||||
status = ath10k_wmi_connect(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not connect wmi: %d\n", status);
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
status = ath10k_htc_start(&ar->htc);
|
||||
if (status) {
|
||||
ath10k_err("failed to start htc: %d\n", status);
|
||||
goto err_hif_stop;
|
||||
}
|
||||
|
||||
status = ath10k_wmi_wait_for_service_ready(ar);
|
||||
if (status <= 0) {
|
||||
ath10k_warn("wmi service ready event not received");
|
||||
status = -ETIMEDOUT;
|
||||
goto err_htc_stop;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n",
|
||||
ar->hw->wiphy->fw_version);
|
||||
@@ -813,31 +775,36 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
status = ath10k_wmi_cmd_init(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not send WMI init command (%d)\n", status);
|
||||
goto err_disconnect_htc;
|
||||
goto err_htc_stop;
|
||||
}
|
||||
|
||||
status = ath10k_wmi_wait_for_unified_ready(ar);
|
||||
if (status <= 0) {
|
||||
ath10k_err("wmi unified ready event not received\n");
|
||||
status = -ETIMEDOUT;
|
||||
goto err_disconnect_htc;
|
||||
goto err_htc_stop;
|
||||
}
|
||||
|
||||
status = ath10k_htt_attach_target(&ar->htt);
|
||||
if (status)
|
||||
goto err_disconnect_htc;
|
||||
status = ath10k_htt_setup(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err("failed to setup htt: %d\n", status);
|
||||
goto err_htc_stop;
|
||||
}
|
||||
|
||||
status = ath10k_debug_start(ar);
|
||||
if (status)
|
||||
goto err_disconnect_htc;
|
||||
goto err_htc_stop;
|
||||
|
||||
ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
|
||||
INIT_LIST_HEAD(&ar->arvifs);
|
||||
|
||||
if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
|
||||
ath10k_info("%s (0x%x) fw %s api %d htt %d.%d\n",
|
||||
ar->hw_params.name, ar->target_version,
|
||||
ar->hw->wiphy->fw_version, ar->fw_api,
|
||||
ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
|
||||
ar->hw_params.name,
|
||||
ar->target_version,
|
||||
ar->chip_id,
|
||||
ar->hw->wiphy->fw_version,
|
||||
ar->fw_api,
|
||||
ar->htt.target_version_major,
|
||||
ar->htt.target_version_minor);
|
||||
|
||||
@@ -845,12 +812,14 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
|
||||
return 0;
|
||||
|
||||
err_disconnect_htc:
|
||||
err_htc_stop:
|
||||
ath10k_htc_stop(&ar->htc);
|
||||
err_htt_detach:
|
||||
ath10k_htt_detach(&ar->htt);
|
||||
err_hif_stop:
|
||||
ath10k_hif_stop(ar);
|
||||
err_htt_rx_detach:
|
||||
ath10k_htt_rx_free(&ar->htt);
|
||||
err_htt_tx_detach:
|
||||
ath10k_htt_tx_free(&ar->htt);
|
||||
err_wmi_detach:
|
||||
ath10k_wmi_detach(ar);
|
||||
err:
|
||||
@@ -885,10 +854,14 @@ void ath10k_core_stop(struct ath10k *ar)
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
/* try to suspend target */
|
||||
ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
|
||||
if (ar->state != ATH10K_STATE_RESTARTING)
|
||||
ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
|
||||
|
||||
ath10k_debug_stop(ar);
|
||||
ath10k_htc_stop(&ar->htc);
|
||||
ath10k_htt_detach(&ar->htt);
|
||||
ath10k_hif_stop(ar);
|
||||
ath10k_htt_tx_free(&ar->htt);
|
||||
ath10k_htt_rx_free(&ar->htt);
|
||||
ath10k_wmi_detach(ar);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_stop);
|
||||
@@ -980,22 +953,15 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_core_register(struct ath10k *ar, u32 chip_id)
|
||||
static void ath10k_core_register_work(struct work_struct *work)
|
||||
{
|
||||
struct ath10k *ar = container_of(work, struct ath10k, register_work);
|
||||
int status;
|
||||
|
||||
ar->chip_id = chip_id;
|
||||
|
||||
status = ath10k_core_check_chip_id(ar);
|
||||
if (status) {
|
||||
ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = ath10k_core_probe_fw(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not probe fw (%d)\n", status);
|
||||
return status;
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = ath10k_mac_register(ar);
|
||||
@@ -1010,18 +976,43 @@ int ath10k_core_register(struct ath10k *ar, u32 chip_id)
|
||||
goto err_unregister_mac;
|
||||
}
|
||||
|
||||
return 0;
|
||||
set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);
|
||||
return;
|
||||
|
||||
err_unregister_mac:
|
||||
ath10k_mac_unregister(ar);
|
||||
err_release_fw:
|
||||
ath10k_core_free_firmware_files(ar);
|
||||
return status;
|
||||
err:
|
||||
device_release_driver(ar->dev);
|
||||
return;
|
||||
}
|
||||
|
||||
int ath10k_core_register(struct ath10k *ar, u32 chip_id)
|
||||
{
|
||||
int status;
|
||||
|
||||
ar->chip_id = chip_id;
|
||||
|
||||
status = ath10k_core_check_chip_id(ar);
|
||||
if (status) {
|
||||
ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
|
||||
return status;
|
||||
}
|
||||
|
||||
queue_work(ar->workqueue, &ar->register_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_register);
|
||||
|
||||
void ath10k_core_unregister(struct ath10k *ar)
|
||||
{
|
||||
cancel_work_sync(&ar->register_work);
|
||||
|
||||
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
|
||||
return;
|
||||
|
||||
/* We must unregister from mac80211 before we stop HTC and HIF.
|
||||
* Otherwise we will fail to submit commands to FW and mac80211 will be
|
||||
* unhappy about callback failures. */
|
||||
@@ -1033,6 +1024,71 @@ void ath10k_core_unregister(struct ath10k *ar)
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_unregister);
|
||||
|
||||
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
|
||||
const struct ath10k_hif_ops *hif_ops)
|
||||
{
|
||||
struct ath10k *ar;
|
||||
|
||||
ar = ath10k_mac_create();
|
||||
if (!ar)
|
||||
return NULL;
|
||||
|
||||
ar->ath_common.priv = ar;
|
||||
ar->ath_common.hw = ar->hw;
|
||||
|
||||
ar->p2p = !!ath10k_p2p;
|
||||
ar->dev = dev;
|
||||
|
||||
ar->hif.priv = hif_priv;
|
||||
ar->hif.ops = hif_ops;
|
||||
|
||||
init_completion(&ar->scan.started);
|
||||
init_completion(&ar->scan.completed);
|
||||
init_completion(&ar->scan.on_channel);
|
||||
init_completion(&ar->target_suspend);
|
||||
|
||||
init_completion(&ar->install_key_done);
|
||||
init_completion(&ar->vdev_setup_done);
|
||||
|
||||
setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
|
||||
|
||||
ar->workqueue = create_singlethread_workqueue("ath10k_wq");
|
||||
if (!ar->workqueue)
|
||||
goto err_wq;
|
||||
|
||||
mutex_init(&ar->conf_mutex);
|
||||
spin_lock_init(&ar->data_lock);
|
||||
|
||||
INIT_LIST_HEAD(&ar->peers);
|
||||
init_waitqueue_head(&ar->peer_mapping_wq);
|
||||
|
||||
init_completion(&ar->offchan_tx_completed);
|
||||
INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
|
||||
skb_queue_head_init(&ar->offchan_tx_queue);
|
||||
|
||||
INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
|
||||
skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
|
||||
|
||||
INIT_WORK(&ar->register_work, ath10k_core_register_work);
|
||||
INIT_WORK(&ar->restart_work, ath10k_core_restart);
|
||||
|
||||
return ar;
|
||||
|
||||
err_wq:
|
||||
ath10k_mac_destroy(ar);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_create);
|
||||
|
||||
void ath10k_core_destroy(struct ath10k *ar)
|
||||
{
|
||||
flush_workqueue(ar->workqueue);
|
||||
destroy_workqueue(ar->workqueue);
|
||||
|
||||
ath10k_mac_destroy(ar);
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_core_destroy);
|
||||
|
||||
MODULE_AUTHOR("Qualcomm Atheros");
|
||||
MODULE_DESCRIPTION("Core module for QCA988X PCIe devices.");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
@@ -119,6 +119,7 @@ struct ath10k_peer_stat {
|
||||
u8 peer_macaddr[ETH_ALEN];
|
||||
u32 peer_rssi;
|
||||
u32 peer_tx_rate;
|
||||
u32 peer_rx_rate; /* 10x only */
|
||||
};
|
||||
|
||||
struct ath10k_target_stats {
|
||||
@@ -130,6 +131,12 @@ struct ath10k_target_stats {
|
||||
u32 cycle_count;
|
||||
u32 phy_err_count;
|
||||
u32 chan_tx_power;
|
||||
u32 ack_rx_bad;
|
||||
u32 rts_bad;
|
||||
u32 rts_good;
|
||||
u32 fcs_bad;
|
||||
u32 no_beacons;
|
||||
u32 mib_int_count;
|
||||
|
||||
/* PDEV TX stats */
|
||||
s32 comp_queued;
|
||||
@@ -260,6 +267,8 @@ struct ath10k_vif {
|
||||
u8 fixed_rate;
|
||||
u8 fixed_nss;
|
||||
u8 force_sgi;
|
||||
bool use_cts_prot;
|
||||
int num_legacy_stations;
|
||||
};
|
||||
|
||||
struct ath10k_vif_iter {
|
||||
@@ -326,6 +335,7 @@ enum ath10k_dev_flags {
|
||||
/* Indicates that ath10k device is during CAC phase of DFS */
|
||||
ATH10K_CAC_RUNNING,
|
||||
ATH10K_FLAG_FIRST_BOOT_DONE,
|
||||
ATH10K_FLAG_CORE_REGISTERED,
|
||||
};
|
||||
|
||||
struct ath10k {
|
||||
@@ -419,13 +429,24 @@ struct ath10k {
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
||||
int free_vdev_map;
|
||||
bool promisc;
|
||||
bool monitor;
|
||||
int monitor_vdev_id;
|
||||
bool monitor_enabled;
|
||||
bool monitor_present;
|
||||
bool monitor_started;
|
||||
unsigned int filter_flags;
|
||||
unsigned long dev_flags;
|
||||
u32 dfs_block_radar_events;
|
||||
|
||||
/* protected by conf_mutex */
|
||||
bool radar_enabled;
|
||||
int num_started_vdevs;
|
||||
|
||||
/* Protected by conf-mutex */
|
||||
u8 supp_tx_chainmask;
|
||||
u8 supp_rx_chainmask;
|
||||
u8 cfg_tx_chainmask;
|
||||
u8 cfg_rx_chainmask;
|
||||
|
||||
struct wmi_pdev_set_wmm_params_arg wmm_params;
|
||||
struct completion install_key_done;
|
||||
|
||||
@@ -456,6 +477,7 @@ struct ath10k {
|
||||
|
||||
enum ath10k_state state;
|
||||
|
||||
struct work_struct register_work;
|
||||
struct work_struct restart_work;
|
||||
|
||||
/* cycle count is reported twice for each visited channel during scan.
|
||||
|
@@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
|
||||
u8 *tmp = ev->data;
|
||||
struct ath10k_target_stats *stats;
|
||||
int num_pdev_stats, num_vdev_stats, num_peer_stats;
|
||||
struct wmi_pdev_stats *ps;
|
||||
struct wmi_pdev_stats_10x *ps;
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
@@ -173,7 +173,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
|
||||
num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */
|
||||
|
||||
if (num_pdev_stats) {
|
||||
ps = (struct wmi_pdev_stats *)tmp;
|
||||
ps = (struct wmi_pdev_stats_10x *)tmp;
|
||||
|
||||
stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);
|
||||
stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count);
|
||||
@@ -228,7 +228,18 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
|
||||
stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop);
|
||||
stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs);
|
||||
|
||||
tmp += sizeof(struct wmi_pdev_stats);
|
||||
if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
|
||||
ar->fw_features)) {
|
||||
stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad);
|
||||
stats->rts_bad = __le32_to_cpu(ps->rts_bad);
|
||||
stats->rts_good = __le32_to_cpu(ps->rts_good);
|
||||
stats->fcs_bad = __le32_to_cpu(ps->fcs_bad);
|
||||
stats->no_beacons = __le32_to_cpu(ps->no_beacons);
|
||||
stats->mib_int_count = __le32_to_cpu(ps->mib_int_count);
|
||||
tmp += sizeof(struct wmi_pdev_stats_10x);
|
||||
} else {
|
||||
tmp += sizeof(struct wmi_pdev_stats_old);
|
||||
}
|
||||
}
|
||||
|
||||
/* 0 or max vdevs */
|
||||
@@ -243,22 +254,29 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
|
||||
}
|
||||
|
||||
if (num_peer_stats) {
|
||||
struct wmi_peer_stats *peer_stats;
|
||||
struct wmi_peer_stats_10x *peer_stats;
|
||||
struct ath10k_peer_stat *s;
|
||||
|
||||
stats->peers = num_peer_stats;
|
||||
|
||||
for (i = 0; i < num_peer_stats; i++) {
|
||||
peer_stats = (struct wmi_peer_stats *)tmp;
|
||||
peer_stats = (struct wmi_peer_stats_10x *)tmp;
|
||||
s = &stats->peer_stat[i];
|
||||
|
||||
WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr,
|
||||
s->peer_macaddr);
|
||||
memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr,
|
||||
ETH_ALEN);
|
||||
s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
|
||||
s->peer_tx_rate =
|
||||
__le32_to_cpu(peer_stats->peer_tx_rate);
|
||||
if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
|
||||
ar->fw_features)) {
|
||||
s->peer_rx_rate =
|
||||
__le32_to_cpu(peer_stats->peer_rx_rate);
|
||||
tmp += sizeof(struct wmi_peer_stats_10x);
|
||||
|
||||
tmp += sizeof(struct wmi_peer_stats);
|
||||
} else {
|
||||
tmp += sizeof(struct wmi_peer_stats_old);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +290,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
|
||||
struct ath10k *ar = file->private_data;
|
||||
struct ath10k_target_stats *fw_stats;
|
||||
char *buf = NULL;
|
||||
unsigned int len = 0, buf_len = 2500;
|
||||
unsigned int len = 0, buf_len = 8000;
|
||||
ssize_t ret_cnt = 0;
|
||||
long left;
|
||||
int i;
|
||||
@@ -320,6 +338,16 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
|
||||
"Cycle count", fw_stats->cycle_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"PHY error count", fw_stats->phy_err_count);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RTS bad count", fw_stats->rts_bad);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"RTS good count", fw_stats->rts_good);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"FCS bad count", fw_stats->fcs_bad);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"No beacon count", fw_stats->no_beacons);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
|
||||
"MIB int count", fw_stats->mib_int_count);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
@@ -411,8 +439,8 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
|
||||
"MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n",
|
||||
"ath10k PEER stats");
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n",
|
||||
"ath10k PEER stats", fw_stats->peers);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
|
||||
"=================");
|
||||
|
||||
@@ -425,6 +453,9 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer TX rate",
|
||||
fw_stats->peer_stat[i].peer_tx_rate);
|
||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||
"Peer RX rate",
|
||||
fw_stats->peer_stat[i].peer_rx_rate);
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
@@ -451,27 +482,37 @@ static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
const char buf[] = "To simulate firmware crash write the keyword"
|
||||
" `crash` to this file.\nThis will force firmware"
|
||||
" to report a crash to the host system.\n";
|
||||
const char buf[] = "To simulate firmware crash write one of the"
|
||||
" keywords to this file:\n `soft` - this will send"
|
||||
" WMI_FORCE_FW_HANG_ASSERT to firmware if FW"
|
||||
" supports that command.\n `hard` - this will send"
|
||||
" to firmware command with illegal parameters"
|
||||
" causing firmware crash.\n";
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
|
||||
}
|
||||
|
||||
/* Simulate firmware crash:
|
||||
* 'soft': Call wmi command causing firmware hang. This firmware hang is
|
||||
* recoverable by warm firmware reset.
|
||||
* 'hard': Force firmware crash by setting any vdev parameter for not allowed
|
||||
* vdev id. This is hard firmware crash because it is recoverable only by cold
|
||||
* firmware reset.
|
||||
*/
|
||||
static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char buf[32] = {};
|
||||
char buf[32];
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
|
||||
if (strcmp(buf, "crash") && strcmp(buf, "crash\n")) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* make sure that buf is null terminated */
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
|
||||
if (ar->state != ATH10K_STATE_ON &&
|
||||
ar->state != ATH10K_STATE_RESTARTED) {
|
||||
@@ -479,14 +520,30 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ath10k_info("simulating firmware crash\n");
|
||||
/* drop the possible '\n' from the end */
|
||||
if (buf[count - 1] == '\n') {
|
||||
buf[count - 1] = 0;
|
||||
count--;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
|
||||
if (ret)
|
||||
ath10k_warn("failed to force fw hang (%d)\n", ret);
|
||||
if (!strcmp(buf, "soft")) {
|
||||
ath10k_info("simulating soft firmware crash\n");
|
||||
ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
|
||||
} else if (!strcmp(buf, "hard")) {
|
||||
ath10k_info("simulating hard firmware crash\n");
|
||||
ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1,
|
||||
ar->wmi.vdev_param->rts_threshold, 0);
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
ret = count;
|
||||
if (ret) {
|
||||
ath10k_warn("failed to simulate firmware crash: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = count;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
@@ -157,6 +157,9 @@ int ath10k_htc_send(struct ath10k_htc *htc,
|
||||
goto err_pull;
|
||||
}
|
||||
ep->tx_credits -= credits;
|
||||
ath10k_dbg(ATH10K_DBG_HTC,
|
||||
"htc ep %d consumed %d credits (total %d)\n",
|
||||
eid, credits, ep->tx_credits);
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
}
|
||||
|
||||
@@ -185,6 +188,9 @@ err_credits:
|
||||
if (ep->tx_credit_flow_enabled) {
|
||||
spin_lock_bh(&htc->tx_lock);
|
||||
ep->tx_credits += credits;
|
||||
ath10k_dbg(ATH10K_DBG_HTC,
|
||||
"htc ep %d reverted %d credits back (total %d)\n",
|
||||
eid, credits, ep->tx_credits);
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
|
||||
if (ep->ep_ops.ep_tx_credits)
|
||||
@@ -234,12 +240,12 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
|
||||
if (report->eid >= ATH10K_HTC_EP_COUNT)
|
||||
break;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTC, "ep %d got %d credits\n",
|
||||
report->eid, report->credits);
|
||||
|
||||
ep = &htc->endpoint[report->eid];
|
||||
ep->tx_credits += report->credits;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
|
||||
report->eid, report->credits, ep->tx_credits);
|
||||
|
||||
if (ep->ep_ops.ep_tx_credits) {
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
ep->ep_ops.ep_tx_credits(htc->ar);
|
||||
@@ -824,17 +830,11 @@ int ath10k_htc_start(struct ath10k_htc *htc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* stop HTC communications, i.e. stop interrupt reception, and flush all
|
||||
* queued buffers
|
||||
*/
|
||||
void ath10k_htc_stop(struct ath10k_htc *htc)
|
||||
{
|
||||
spin_lock_bh(&htc->tx_lock);
|
||||
htc->stopped = true;
|
||||
spin_unlock_bh(&htc->tx_lock);
|
||||
|
||||
ath10k_hif_stop(htc->ar);
|
||||
}
|
||||
|
||||
/* registered target arrival callback from the HIF layer */
|
||||
|
@@ -22,7 +22,7 @@
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
|
||||
int ath10k_htt_connect(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
struct ath10k_htc_svc_conn_resp conn_resp;
|
||||
@@ -48,38 +48,13 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_attach(struct ath10k *ar)
|
||||
int ath10k_htt_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
int ret;
|
||||
|
||||
htt->ar = ar;
|
||||
htt->max_throughput_mbps = 800;
|
||||
|
||||
/*
|
||||
* Connect to HTC service.
|
||||
* This has to be done before calling ath10k_htt_rx_attach,
|
||||
* since ath10k_htt_rx_attach involves sending a rx ring configure
|
||||
* message to the target.
|
||||
*/
|
||||
ret = ath10k_htt_htc_attach(htt);
|
||||
if (ret) {
|
||||
ath10k_err("could not attach htt htc (%d)\n", ret);
|
||||
goto err_htc_attach;
|
||||
}
|
||||
|
||||
ret = ath10k_htt_tx_attach(htt);
|
||||
if (ret) {
|
||||
ath10k_err("could not attach htt tx (%d)\n", ret);
|
||||
goto err_htc_attach;
|
||||
}
|
||||
|
||||
ret = ath10k_htt_rx_attach(htt);
|
||||
if (ret) {
|
||||
ath10k_err("could not attach htt rx (%d)\n", ret);
|
||||
goto err_rx_attach;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prefetch enough data to satisfy target
|
||||
* classification engine.
|
||||
@@ -93,11 +68,6 @@ int ath10k_htt_attach(struct ath10k *ar)
|
||||
2; /* ip4 dscp or ip6 priority */
|
||||
|
||||
return 0;
|
||||
|
||||
err_rx_attach:
|
||||
ath10k_htt_tx_detach(htt);
|
||||
err_htc_attach:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ)
|
||||
@@ -117,7 +87,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_attach_target(struct ath10k_htt *htt)
|
||||
int ath10k_htt_setup(struct ath10k_htt *htt)
|
||||
{
|
||||
int status;
|
||||
|
||||
@@ -140,9 +110,3 @@ int ath10k_htt_attach_target(struct ath10k_htt *htt)
|
||||
|
||||
return ath10k_htt_send_rx_ring_cfg_ll(htt);
|
||||
}
|
||||
|
||||
void ath10k_htt_detach(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_htt_rx_detach(htt);
|
||||
ath10k_htt_tx_detach(htt);
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include <linux/bug.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "htc.h"
|
||||
#include "rx_desc.h"
|
||||
@@ -1172,23 +1173,6 @@ struct htt_peer_unmap_event {
|
||||
u16 peer_id;
|
||||
};
|
||||
|
||||
struct htt_rx_info {
|
||||
struct sk_buff *skb;
|
||||
enum htt_rx_mpdu_status status;
|
||||
enum htt_rx_mpdu_encrypt_type encrypt_type;
|
||||
s8 signal;
|
||||
struct {
|
||||
u8 info0;
|
||||
u32 info1;
|
||||
u32 info2;
|
||||
} rate;
|
||||
|
||||
u32 tsf;
|
||||
bool fcs_err;
|
||||
bool amsdu_more;
|
||||
bool mic_err;
|
||||
};
|
||||
|
||||
struct ath10k_htt_txbuf {
|
||||
struct htt_data_tx_desc_frag frags[2];
|
||||
struct ath10k_htc_hdr htc_hdr;
|
||||
@@ -1289,6 +1273,9 @@ struct ath10k_htt {
|
||||
struct tasklet_struct txrx_compl_task;
|
||||
struct sk_buff_head tx_compl_q;
|
||||
struct sk_buff_head rx_compl_q;
|
||||
|
||||
/* rx_status template */
|
||||
struct ieee80211_rx_status rx_status;
|
||||
};
|
||||
|
||||
#define RX_HTT_HDR_STATUS_LEN 64
|
||||
@@ -1341,14 +1328,16 @@ struct htt_rx_desc {
|
||||
#define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */
|
||||
#define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1)
|
||||
|
||||
int ath10k_htt_attach(struct ath10k *ar);
|
||||
int ath10k_htt_attach_target(struct ath10k_htt *htt);
|
||||
void ath10k_htt_detach(struct ath10k_htt *htt);
|
||||
int ath10k_htt_connect(struct ath10k_htt *htt);
|
||||
int ath10k_htt_init(struct ath10k *ar);
|
||||
int ath10k_htt_setup(struct ath10k_htt *htt);
|
||||
|
||||
int ath10k_htt_tx_alloc(struct ath10k_htt *htt);
|
||||
void ath10k_htt_tx_free(struct ath10k_htt *htt);
|
||||
|
||||
int ath10k_htt_rx_alloc(struct ath10k_htt *htt);
|
||||
void ath10k_htt_rx_free(struct ath10k_htt *htt);
|
||||
|
||||
int ath10k_htt_tx_attach(struct ath10k_htt *htt);
|
||||
void ath10k_htt_tx_detach(struct ath10k_htt *htt);
|
||||
int ath10k_htt_rx_attach(struct ath10k_htt *htt);
|
||||
void ath10k_htt_rx_detach(struct ath10k_htt *htt);
|
||||
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
|
||||
|
@@ -225,10 +225,26 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg)
|
||||
ath10k_htt_rx_msdu_buff_replenish(htt);
|
||||
}
|
||||
|
||||
void ath10k_htt_rx_detach(struct ath10k_htt *htt)
|
||||
static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt)
|
||||
{
|
||||
int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld;
|
||||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < htt->rx_ring.size; i++) {
|
||||
skb = htt->rx_ring.netbufs_ring[i];
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
dma_unmap_single(htt->ar->dev, ATH10K_SKB_CB(skb)->paddr,
|
||||
skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(skb);
|
||||
htt->rx_ring.netbufs_ring[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_htt_rx_free(struct ath10k_htt *htt)
|
||||
{
|
||||
del_timer_sync(&htt->rx_ring.refill_retry_timer);
|
||||
tasklet_kill(&htt->rx_replenish_task);
|
||||
tasklet_kill(&htt->txrx_compl_task);
|
||||
@@ -236,18 +252,7 @@ void ath10k_htt_rx_detach(struct ath10k_htt *htt)
|
||||
skb_queue_purge(&htt->tx_compl_q);
|
||||
skb_queue_purge(&htt->rx_compl_q);
|
||||
|
||||
while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) {
|
||||
struct sk_buff *skb =
|
||||
htt->rx_ring.netbufs_ring[sw_rd_idx];
|
||||
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
|
||||
|
||||
dma_unmap_single(htt->ar->dev, cb->paddr,
|
||||
skb->len + skb_tailroom(skb),
|
||||
DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(htt->rx_ring.netbufs_ring[sw_rd_idx]);
|
||||
sw_rd_idx++;
|
||||
sw_rd_idx &= htt->rx_ring.size_mask;
|
||||
}
|
||||
ath10k_htt_rx_ring_clean_up(htt);
|
||||
|
||||
dma_free_coherent(htt->ar->dev,
|
||||
(htt->rx_ring.size *
|
||||
@@ -277,6 +282,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
|
||||
|
||||
idx = htt->rx_ring.sw_rd_idx.msdu_payld;
|
||||
msdu = htt->rx_ring.netbufs_ring[idx];
|
||||
htt->rx_ring.netbufs_ring[idx] = NULL;
|
||||
|
||||
idx++;
|
||||
idx &= htt->rx_ring.size_mask;
|
||||
@@ -297,6 +303,7 @@ static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
/* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */
|
||||
static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
u8 **fw_desc, int *fw_desc_len,
|
||||
struct sk_buff **head_msdu,
|
||||
@@ -305,12 +312,13 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
int msdu_len, msdu_chaining = 0;
|
||||
struct sk_buff *msdu;
|
||||
struct htt_rx_desc *rx_desc;
|
||||
bool corrupted = false;
|
||||
|
||||
lockdep_assert_held(&htt->rx_ring.lock);
|
||||
|
||||
if (htt->rx_confused) {
|
||||
ath10k_warn("htt is confused. refusing rx\n");
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt);
|
||||
@@ -398,7 +406,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0),
|
||||
RX_MSDU_START_INFO0_MSDU_LENGTH);
|
||||
msdu_chained = rx_desc->frag_info.ring2_more_count;
|
||||
msdu_chaining = msdu_chained;
|
||||
|
||||
if (msdu_len_invalid)
|
||||
msdu_len = 0;
|
||||
@@ -426,11 +433,15 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
|
||||
msdu->next = next;
|
||||
msdu = next;
|
||||
msdu_chaining = 1;
|
||||
}
|
||||
|
||||
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
|
||||
RX_MSDU_END_INFO0_LAST_MSDU;
|
||||
|
||||
if (msdu_chaining && !last_msdu)
|
||||
corrupted = true;
|
||||
|
||||
if (last_msdu) {
|
||||
msdu->next = NULL;
|
||||
break;
|
||||
@@ -442,6 +453,23 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
}
|
||||
*tail_msdu = msdu;
|
||||
|
||||
if (*head_msdu == NULL)
|
||||
msdu_chaining = -1;
|
||||
|
||||
/*
|
||||
* Apparently FW sometimes reports weird chained MSDU sequences with
|
||||
* more than one rx descriptor. This seems like a bug but needs more
|
||||
* analyzing. For the time being fix it by dropping such sequences to
|
||||
* avoid blowing up the host system.
|
||||
*/
|
||||
if (corrupted) {
|
||||
ath10k_warn("failed to pop chained msdus, dropping\n");
|
||||
ath10k_htt_rx_free_msdu_chain(*head_msdu);
|
||||
*head_msdu = NULL;
|
||||
*tail_msdu = NULL;
|
||||
msdu_chaining = -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't refill the ring yet.
|
||||
*
|
||||
@@ -464,7 +492,7 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr)
|
||||
ath10k_htt_rx_msdu_buff_replenish(htt);
|
||||
}
|
||||
|
||||
int ath10k_htt_rx_attach(struct ath10k_htt *htt)
|
||||
int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
|
||||
{
|
||||
dma_addr_t paddr;
|
||||
void *vaddr;
|
||||
@@ -490,7 +518,7 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)
|
||||
htt->rx_ring.fill_level = ath10k_htt_rx_ring_fill_level(htt);
|
||||
|
||||
htt->rx_ring.netbufs_ring =
|
||||
kmalloc(htt->rx_ring.size * sizeof(struct sk_buff *),
|
||||
kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *),
|
||||
GFP_KERNEL);
|
||||
if (!htt->rx_ring.netbufs_ring)
|
||||
goto err_netbuf;
|
||||
@@ -636,6 +664,203 @@ struct amsdu_subframe_hdr {
|
||||
__be16 len;
|
||||
} __packed;
|
||||
|
||||
static const u8 rx_legacy_rate_idx[] = {
|
||||
3, /* 0x00 - 11Mbps */
|
||||
2, /* 0x01 - 5.5Mbps */
|
||||
1, /* 0x02 - 2Mbps */
|
||||
0, /* 0x03 - 1Mbps */
|
||||
3, /* 0x04 - 11Mbps */
|
||||
2, /* 0x05 - 5.5Mbps */
|
||||
1, /* 0x06 - 2Mbps */
|
||||
0, /* 0x07 - 1Mbps */
|
||||
10, /* 0x08 - 48Mbps */
|
||||
8, /* 0x09 - 24Mbps */
|
||||
6, /* 0x0A - 12Mbps */
|
||||
4, /* 0x0B - 6Mbps */
|
||||
11, /* 0x0C - 54Mbps */
|
||||
9, /* 0x0D - 36Mbps */
|
||||
7, /* 0x0E - 18Mbps */
|
||||
5, /* 0x0F - 9Mbps */
|
||||
};
|
||||
|
||||
static void ath10k_htt_rx_h_rates(struct ath10k *ar,
|
||||
enum ieee80211_band band,
|
||||
u8 info0, u32 info1, u32 info2,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
|
||||
u8 preamble = 0;
|
||||
|
||||
/* Check if valid fields */
|
||||
if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID))
|
||||
return;
|
||||
|
||||
preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE);
|
||||
|
||||
switch (preamble) {
|
||||
case HTT_RX_LEGACY:
|
||||
cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK;
|
||||
rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE);
|
||||
rate_idx = 0;
|
||||
|
||||
if (rate < 0x08 || rate > 0x0F)
|
||||
break;
|
||||
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if (cck)
|
||||
rate &= ~BIT(3);
|
||||
rate_idx = rx_legacy_rate_idx[rate];
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
rate_idx = rx_legacy_rate_idx[rate];
|
||||
/* We are using same rate table registering
|
||||
HW - ath10k_rates[]. In case of 5GHz skip
|
||||
CCK rates, so -4 here */
|
||||
rate_idx -= 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
status->rate_idx = rate_idx;
|
||||
break;
|
||||
case HTT_RX_HT:
|
||||
case HTT_RX_HT_WITH_TXBF:
|
||||
/* HT-SIG - Table 20-11 in info1 and info2 */
|
||||
mcs = info1 & 0x1F;
|
||||
nss = mcs >> 3;
|
||||
bw = (info1 >> 7) & 1;
|
||||
sgi = (info2 >> 7) & 1;
|
||||
|
||||
status->rate_idx = mcs;
|
||||
status->flag |= RX_FLAG_HT;
|
||||
if (sgi)
|
||||
status->flag |= RX_FLAG_SHORT_GI;
|
||||
if (bw)
|
||||
status->flag |= RX_FLAG_40MHZ;
|
||||
break;
|
||||
case HTT_RX_VHT:
|
||||
case HTT_RX_VHT_WITH_TXBF:
|
||||
/* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2
|
||||
TODO check this */
|
||||
mcs = (info2 >> 4) & 0x0F;
|
||||
nss = ((info1 >> 10) & 0x07) + 1;
|
||||
bw = info1 & 3;
|
||||
sgi = info2 & 1;
|
||||
|
||||
status->rate_idx = mcs;
|
||||
status->vht_nss = nss;
|
||||
|
||||
if (sgi)
|
||||
status->flag |= RX_FLAG_SHORT_GI;
|
||||
|
||||
switch (bw) {
|
||||
/* 20MHZ */
|
||||
case 0:
|
||||
break;
|
||||
/* 40MHZ */
|
||||
case 1:
|
||||
status->flag |= RX_FLAG_40MHZ;
|
||||
break;
|
||||
/* 80MHZ */
|
||||
case 2:
|
||||
status->vht_flag |= RX_VHT_FLAG_80MHZ;
|
||||
}
|
||||
|
||||
status->flag |= RX_FLAG_VHT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct sk_buff *skb,
|
||||
enum htt_rx_mpdu_encrypt_type enctype,
|
||||
enum rx_msdu_decap_format fmt,
|
||||
bool dot11frag)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
rx_status->flag &= ~(RX_FLAG_DECRYPTED |
|
||||
RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED);
|
||||
|
||||
if (enctype == HTT_RX_MPDU_ENCRYPT_NONE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* There's no explicit rx descriptor flag to indicate whether a given
|
||||
* frame has been decrypted or not. We're forced to use the decap
|
||||
* format as an implicit indication. However fragmentation rx is always
|
||||
* raw and it probably never reports undecrypted raws.
|
||||
*
|
||||
* This makes sure sniffed frames are reported as-is without stripping
|
||||
* the protected flag.
|
||||
*/
|
||||
if (fmt == RX_MSDU_DECAP_RAW && !dot11frag)
|
||||
return;
|
||||
|
||||
rx_status->flag |= RX_FLAG_DECRYPTED |
|
||||
RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
hdr->frame_control = __cpu_to_le16(__le16_to_cpu(hdr->frame_control) &
|
||||
~IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
struct ieee80211_channel *ch;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ch = ar->scan_channel;
|
||||
if (!ch)
|
||||
ch = ar->rx_channel;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!ch)
|
||||
return false;
|
||||
|
||||
status->band = ch->band;
|
||||
status->freq = ch->center_freq;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ath10k_process_rx(struct ath10k *ar,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_rx_status *status;
|
||||
|
||||
status = IEEE80211_SKB_RXCB(skb);
|
||||
*status = *rx_status;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_DATA,
|
||||
"rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n",
|
||||
skb,
|
||||
skb->len,
|
||||
status->flag == 0 ? "legacy" : "",
|
||||
status->flag & RX_FLAG_HT ? "ht" : "",
|
||||
status->flag & RX_FLAG_VHT ? "vht" : "",
|
||||
status->flag & RX_FLAG_40MHZ ? "40" : "",
|
||||
status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "",
|
||||
status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
|
||||
status->rate_idx,
|
||||
status->vht_nss,
|
||||
status->freq,
|
||||
status->band, status->flag,
|
||||
!!(status->flag & RX_FLAG_FAILED_FCS_CRC),
|
||||
!!(status->flag & RX_FLAG_MMIC_ERROR));
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
|
||||
skb->data, skb->len);
|
||||
|
||||
ieee80211_rx(ar->hw, skb);
|
||||
}
|
||||
|
||||
static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
|
||||
{
|
||||
/* nwifi header is padded to 4 bytes. this fixes 4addr rx */
|
||||
@@ -643,11 +868,12 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ieee80211_hdr *hdr)
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
|
||||
struct htt_rx_info *info)
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct sk_buff *skb_in)
|
||||
{
|
||||
struct htt_rx_desc *rxd;
|
||||
struct sk_buff *skb = skb_in;
|
||||
struct sk_buff *first;
|
||||
struct sk_buff *skb = info->skb;
|
||||
enum rx_msdu_decap_format fmt;
|
||||
enum htt_rx_mpdu_encrypt_type enctype;
|
||||
struct ieee80211_hdr *hdr;
|
||||
@@ -728,24 +954,28 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
|
||||
break;
|
||||
}
|
||||
|
||||
info->skb = skb;
|
||||
info->encrypt_type = enctype;
|
||||
skb_in = skb;
|
||||
ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype, fmt,
|
||||
false);
|
||||
skb = skb->next;
|
||||
info->skb->next = NULL;
|
||||
skb_in->next = NULL;
|
||||
|
||||
if (skb)
|
||||
info->amsdu_more = true;
|
||||
rx_status->flag |= RX_FLAG_AMSDU_MORE;
|
||||
else
|
||||
rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
|
||||
|
||||
ath10k_process_rx(htt->ar, info);
|
||||
ath10k_process_rx(htt->ar, rx_status, skb_in);
|
||||
}
|
||||
|
||||
/* FIXME: It might be nice to re-assemble the A-MSDU when there's a
|
||||
* monitor interface active for sniffing purposes. */
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
|
||||
static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *skb = info->skb;
|
||||
struct htt_rx_desc *rxd;
|
||||
struct ieee80211_hdr *hdr;
|
||||
enum rx_msdu_decap_format fmt;
|
||||
@@ -808,66 +1038,9 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
|
||||
break;
|
||||
}
|
||||
|
||||
info->skb = skb;
|
||||
info->encrypt_type = enctype;
|
||||
ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype, fmt, false);
|
||||
|
||||
ath10k_process_rx(htt->ar, info);
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_has_decrypt_err(struct sk_buff *skb)
|
||||
{
|
||||
struct htt_rx_desc *rxd;
|
||||
u32 flags;
|
||||
|
||||
rxd = (void *)skb->data - sizeof(*rxd);
|
||||
flags = __le32_to_cpu(rxd->attention.flags);
|
||||
|
||||
if (flags & RX_ATTENTION_FLAGS_DECRYPT_ERR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_has_fcs_err(struct sk_buff *skb)
|
||||
{
|
||||
struct htt_rx_desc *rxd;
|
||||
u32 flags;
|
||||
|
||||
rxd = (void *)skb->data - sizeof(*rxd);
|
||||
flags = __le32_to_cpu(rxd->attention.flags);
|
||||
|
||||
if (flags & RX_ATTENTION_FLAGS_FCS_ERR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_has_mic_err(struct sk_buff *skb)
|
||||
{
|
||||
struct htt_rx_desc *rxd;
|
||||
u32 flags;
|
||||
|
||||
rxd = (void *)skb->data - sizeof(*rxd);
|
||||
flags = __le32_to_cpu(rxd->attention.flags);
|
||||
|
||||
if (flags & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_is_mgmt(struct sk_buff *skb)
|
||||
{
|
||||
struct htt_rx_desc *rxd;
|
||||
u32 flags;
|
||||
|
||||
rxd = (void *)skb->data - sizeof(*rxd);
|
||||
flags = __le32_to_cpu(rxd->attention.flags);
|
||||
|
||||
if (flags & RX_ATTENTION_FLAGS_MGMT_TYPE)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
ath10k_process_rx(htt->ar, rx_status, skb);
|
||||
}
|
||||
|
||||
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
|
||||
@@ -952,21 +1125,73 @@ static int ath10k_unchain_msdu(struct sk_buff *msdu_head)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
|
||||
struct sk_buff *head,
|
||||
enum htt_rx_mpdu_status status,
|
||||
bool channel_set,
|
||||
u32 attention)
|
||||
{
|
||||
if (head->len == 0) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx dropping due to zero-len\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx dropping due to decrypt-err\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!channel_set) {
|
||||
ath10k_warn("no channel configured; ignoring frame!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Skip mgmt frames while we handle this in WMI */
|
||||
if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
|
||||
attention & RX_ATTENTION_FLAGS_MGMT_TYPE) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (status != HTT_RX_IND_MPDU_STATUS_OK &&
|
||||
status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
|
||||
status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
|
||||
!htt->ar->monitor_started) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx ignoring frame w/ status %d\n",
|
||||
status);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx CAC running\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
||||
struct htt_rx_indication *rx)
|
||||
{
|
||||
struct htt_rx_info info;
|
||||
struct ieee80211_rx_status *rx_status = &htt->rx_status;
|
||||
struct htt_rx_indication_mpdu_range *mpdu_ranges;
|
||||
struct htt_rx_desc *rxd;
|
||||
enum htt_rx_mpdu_status status;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int num_mpdu_ranges;
|
||||
u32 attention;
|
||||
int fw_desc_len;
|
||||
u8 *fw_desc;
|
||||
bool channel_set;
|
||||
int i, j;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&htt->rx_ring.lock);
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes);
|
||||
fw_desc = (u8 *)&rx->fw_desc;
|
||||
|
||||
@@ -974,106 +1199,90 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
|
||||
HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
|
||||
mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
|
||||
|
||||
/* Fill this once, while this is per-ppdu */
|
||||
if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) {
|
||||
memset(rx_status, 0, sizeof(*rx_status));
|
||||
rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
|
||||
rx->ppdu.combined_rssi;
|
||||
}
|
||||
|
||||
if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) {
|
||||
/* TSF available only in 32-bit */
|
||||
rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff;
|
||||
rx_status->flag |= RX_FLAG_MACTIME_END;
|
||||
}
|
||||
|
||||
channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status);
|
||||
|
||||
if (channel_set) {
|
||||
ath10k_htt_rx_h_rates(htt->ar, rx_status->band,
|
||||
rx->ppdu.info0,
|
||||
__le32_to_cpu(rx->ppdu.info1),
|
||||
__le32_to_cpu(rx->ppdu.info2),
|
||||
rx_status);
|
||||
}
|
||||
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
|
||||
rx, sizeof(*rx) +
|
||||
(sizeof(struct htt_rx_indication_mpdu_range) *
|
||||
num_mpdu_ranges));
|
||||
|
||||
for (i = 0; i < num_mpdu_ranges; i++) {
|
||||
info.status = mpdu_ranges[i].mpdu_range_status;
|
||||
status = mpdu_ranges[i].mpdu_range_status;
|
||||
|
||||
for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) {
|
||||
struct sk_buff *msdu_head, *msdu_tail;
|
||||
enum htt_rx_mpdu_status status;
|
||||
int msdu_chaining;
|
||||
|
||||
msdu_head = NULL;
|
||||
msdu_tail = NULL;
|
||||
msdu_chaining = ath10k_htt_rx_amsdu_pop(htt,
|
||||
&fw_desc,
|
||||
&fw_desc_len,
|
||||
&msdu_head,
|
||||
&msdu_tail);
|
||||
ret = ath10k_htt_rx_amsdu_pop(htt,
|
||||
&fw_desc,
|
||||
&fw_desc_len,
|
||||
&msdu_head,
|
||||
&msdu_tail);
|
||||
|
||||
if (!msdu_head) {
|
||||
ath10k_warn("htt rx no data!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msdu_head->len == 0) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx dropping due to zero-len\n");
|
||||
if (ret < 0) {
|
||||
ath10k_warn("failed to pop amsdu from htt rx ring %d\n",
|
||||
ret);
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ath10k_htt_rx_has_decrypt_err(msdu_head)) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx dropping due to decrypt-err\n");
|
||||
rxd = container_of((void *)msdu_head->data,
|
||||
struct htt_rx_desc,
|
||||
msdu_payload);
|
||||
attention = __le32_to_cpu(rxd->attention.flags);
|
||||
|
||||
if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head,
|
||||
status,
|
||||
channel_set,
|
||||
attention)) {
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
|
||||
status = info.status;
|
||||
|
||||
/* Skip mgmt frames while we handle this in WMI */
|
||||
if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
|
||||
ath10k_htt_rx_is_mgmt(msdu_head)) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
|
||||
if (ret > 0 &&
|
||||
ath10k_unchain_msdu(msdu_head) < 0) {
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status != HTT_RX_IND_MPDU_STATUS_OK &&
|
||||
status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
|
||||
status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
|
||||
!htt->ar->monitor_enabled) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx ignoring frame w/ status %d\n",
|
||||
status);
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
if (attention & RX_ATTENTION_FLAGS_FCS_ERR)
|
||||
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
else
|
||||
rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC;
|
||||
|
||||
if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx CAC running\n");
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msdu_chaining &&
|
||||
(ath10k_unchain_msdu(msdu_head) < 0)) {
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
continue;
|
||||
}
|
||||
|
||||
info.skb = msdu_head;
|
||||
info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
|
||||
info.mic_err = ath10k_htt_rx_has_mic_err(msdu_head);
|
||||
|
||||
if (info.fcs_err)
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx has FCS err\n");
|
||||
|
||||
if (info.mic_err)
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt rx has MIC err\n");
|
||||
|
||||
info.signal = ATH10K_DEFAULT_NOISE_FLOOR;
|
||||
info.signal += rx->ppdu.combined_rssi;
|
||||
|
||||
info.rate.info0 = rx->ppdu.info0;
|
||||
info.rate.info1 = __le32_to_cpu(rx->ppdu.info1);
|
||||
info.rate.info2 = __le32_to_cpu(rx->ppdu.info2);
|
||||
info.tsf = __le32_to_cpu(rx->ppdu.tsf);
|
||||
if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
|
||||
rx_status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
else
|
||||
rx_status->flag &= ~RX_FLAG_MMIC_ERROR;
|
||||
|
||||
hdr = ath10k_htt_rx_skb_get_hdr(msdu_head);
|
||||
|
||||
if (ath10k_htt_rx_hdr_is_amsdu(hdr))
|
||||
ath10k_htt_rx_amsdu(htt, &info);
|
||||
ath10k_htt_rx_amsdu(htt, rx_status, msdu_head);
|
||||
else
|
||||
ath10k_htt_rx_msdu(htt, &info);
|
||||
ath10k_htt_rx_msdu(htt, rx_status, msdu_head);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1084,11 +1293,12 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
||||
struct htt_rx_fragment_indication *frag)
|
||||
{
|
||||
struct sk_buff *msdu_head, *msdu_tail;
|
||||
enum htt_rx_mpdu_encrypt_type enctype;
|
||||
struct htt_rx_desc *rxd;
|
||||
enum rx_msdu_decap_format fmt;
|
||||
struct htt_rx_info info = {};
|
||||
struct ieee80211_rx_status *rx_status = &htt->rx_status;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int msdu_chaining;
|
||||
int ret;
|
||||
bool tkip_mic_err;
|
||||
bool decrypt_err;
|
||||
u8 *fw_desc;
|
||||
@@ -1102,24 +1312,21 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
||||
msdu_tail = NULL;
|
||||
|
||||
spin_lock_bh(&htt->rx_ring.lock);
|
||||
msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
|
||||
&msdu_head, &msdu_tail);
|
||||
ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
|
||||
&msdu_head, &msdu_tail);
|
||||
spin_unlock_bh(&htt->rx_ring.lock);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
|
||||
|
||||
if (!msdu_head) {
|
||||
ath10k_warn("htt rx frag no data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (msdu_chaining || msdu_head != msdu_tail) {
|
||||
ath10k_warn("aggregation with fragmentation?!\n");
|
||||
if (ret) {
|
||||
ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n",
|
||||
ret);
|
||||
ath10k_htt_rx_free_msdu_chain(msdu_head);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: implement signal strength */
|
||||
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)msdu_head->data;
|
||||
rxd = (void *)msdu_head->data - sizeof(*rxd);
|
||||
@@ -1136,57 +1343,55 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
|
||||
goto end;
|
||||
}
|
||||
|
||||
info.skb = msdu_head;
|
||||
info.status = HTT_RX_IND_MPDU_STATUS_OK;
|
||||
info.encrypt_type = MS(__le32_to_cpu(rxd->mpdu_start.info0),
|
||||
RX_MPDU_START_INFO0_ENCRYPT_TYPE);
|
||||
info.skb->ip_summed = ath10k_htt_rx_get_csum_state(info.skb);
|
||||
enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
|
||||
RX_MPDU_START_INFO0_ENCRYPT_TYPE);
|
||||
ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype, fmt,
|
||||
true);
|
||||
msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
|
||||
|
||||
if (tkip_mic_err) {
|
||||
if (tkip_mic_err)
|
||||
ath10k_warn("tkip mic error\n");
|
||||
info.status = HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR;
|
||||
}
|
||||
|
||||
if (decrypt_err) {
|
||||
ath10k_warn("decryption err in fragmented rx\n");
|
||||
dev_kfree_skb_any(info.skb);
|
||||
dev_kfree_skb_any(msdu_head);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (info.encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) {
|
||||
if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) {
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
paramlen = ath10k_htt_rx_crypto_param_len(info.encrypt_type);
|
||||
paramlen = ath10k_htt_rx_crypto_param_len(enctype);
|
||||
|
||||
/* It is more efficient to move the header than the payload */
|
||||
memmove((void *)info.skb->data + paramlen,
|
||||
(void *)info.skb->data,
|
||||
memmove((void *)msdu_head->data + paramlen,
|
||||
(void *)msdu_head->data,
|
||||
hdrlen);
|
||||
skb_pull(info.skb, paramlen);
|
||||
hdr = (struct ieee80211_hdr *)info.skb->data;
|
||||
skb_pull(msdu_head, paramlen);
|
||||
hdr = (struct ieee80211_hdr *)msdu_head->data;
|
||||
}
|
||||
|
||||
/* remove trailing FCS */
|
||||
trim = 4;
|
||||
|
||||
/* remove crypto trailer */
|
||||
trim += ath10k_htt_rx_crypto_tail_len(info.encrypt_type);
|
||||
trim += ath10k_htt_rx_crypto_tail_len(enctype);
|
||||
|
||||
/* last fragment of TKIP frags has MIC */
|
||||
if (!ieee80211_has_morefrags(hdr->frame_control) &&
|
||||
info.encrypt_type == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
|
||||
enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
|
||||
trim += 8;
|
||||
|
||||
if (trim > info.skb->len) {
|
||||
if (trim > msdu_head->len) {
|
||||
ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n");
|
||||
dev_kfree_skb_any(info.skb);
|
||||
dev_kfree_skb_any(msdu_head);
|
||||
goto end;
|
||||
}
|
||||
|
||||
skb_trim(info.skb, info.skb->len - trim);
|
||||
skb_trim(msdu_head, msdu_head->len - trim);
|
||||
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
|
||||
info.skb->data, info.skb->len);
|
||||
ath10k_process_rx(htt->ar, &info);
|
||||
msdu_head->data, msdu_head->len);
|
||||
ath10k_process_rx(htt->ar, rx_status, msdu_head);
|
||||
|
||||
end:
|
||||
if (fw_desc_len > 0) {
|
||||
|
@@ -83,7 +83,7 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
|
||||
__clear_bit(msdu_id, htt->used_msdu_ids);
|
||||
}
|
||||
|
||||
int ath10k_htt_tx_attach(struct ath10k_htt *htt)
|
||||
int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
|
||||
{
|
||||
spin_lock_init(&htt->tx_lock);
|
||||
init_waitqueue_head(&htt->empty_tx_wq);
|
||||
@@ -120,7 +120,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
|
||||
static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
|
||||
{
|
||||
struct htt_tx_done tx_done = {0};
|
||||
int msdu_id;
|
||||
@@ -141,9 +141,9 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
}
|
||||
|
||||
void ath10k_htt_tx_detach(struct ath10k_htt *htt)
|
||||
void ath10k_htt_tx_free(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_htt_tx_cleanup_pending(htt);
|
||||
ath10k_htt_tx_free_pending(htt);
|
||||
kfree(htt->pending_tx);
|
||||
kfree(htt->used_msdu_ids);
|
||||
dma_pool_destroy(htt->tx_pool);
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#define QCA988X_HW_2_0_CHIP_ID_REV 0x2
|
||||
#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0"
|
||||
#define QCA988X_HW_2_0_FW_FILE "firmware.bin"
|
||||
#define QCA988X_HW_2_0_FW_2_FILE "firmware-2.bin"
|
||||
#define QCA988X_HW_2_0_OTP_FILE "otp.bin"
|
||||
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
|
||||
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -39,15 +39,28 @@ enum ath10k_pci_irq_mode {
|
||||
ATH10K_PCI_IRQ_MSI = 2,
|
||||
};
|
||||
|
||||
static unsigned int ath10k_target_ps;
|
||||
static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
|
||||
enum ath10k_pci_reset_mode {
|
||||
ATH10K_PCI_RESET_AUTO = 0,
|
||||
ATH10K_PCI_RESET_WARM_ONLY = 1,
|
||||
};
|
||||
|
||||
module_param(ath10k_target_ps, uint, 0644);
|
||||
MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option");
|
||||
static unsigned int ath10k_pci_target_ps;
|
||||
static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
|
||||
static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO;
|
||||
|
||||
module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644);
|
||||
MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option");
|
||||
|
||||
module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
|
||||
MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)");
|
||||
|
||||
module_param_named(reset_mode, ath10k_pci_reset_mode, uint, 0644);
|
||||
MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
|
||||
|
||||
/* how long wait to wait for target to initialise, in ms */
|
||||
#define ATH10K_PCI_TARGET_WAIT 3000
|
||||
#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3
|
||||
|
||||
#define QCA988X_2_0_DEVICE_ID (0x003c)
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {
|
||||
@@ -346,9 +359,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
|
||||
* 2) Buffer in DMA-able space
|
||||
*/
|
||||
orig_nbytes = nbytes;
|
||||
data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev,
|
||||
orig_nbytes,
|
||||
&ce_data_base);
|
||||
data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
|
||||
orig_nbytes,
|
||||
&ce_data_base,
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (!data_buf) {
|
||||
ret = -ENOMEM;
|
||||
@@ -442,12 +456,12 @@ done:
|
||||
__le32_to_cpu(((__le32 *)data_buf)[i]);
|
||||
}
|
||||
} else
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n",
|
||||
__func__, address);
|
||||
ath10k_warn("failed to read diag value at 0x%x: %d\n",
|
||||
address, ret);
|
||||
|
||||
if (data_buf)
|
||||
pci_free_consistent(ar_pci->pdev, orig_nbytes,
|
||||
data_buf, ce_data_base);
|
||||
dma_free_coherent(ar->dev, orig_nbytes, data_buf,
|
||||
ce_data_base);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -490,9 +504,10 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
||||
* 2) Buffer in DMA-able space
|
||||
*/
|
||||
orig_nbytes = nbytes;
|
||||
data_buf = (unsigned char *)pci_alloc_consistent(ar_pci->pdev,
|
||||
orig_nbytes,
|
||||
&ce_data_base);
|
||||
data_buf = (unsigned char *)dma_alloc_coherent(ar->dev,
|
||||
orig_nbytes,
|
||||
&ce_data_base,
|
||||
GFP_ATOMIC);
|
||||
if (!data_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
@@ -588,13 +603,13 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
||||
|
||||
done:
|
||||
if (data_buf) {
|
||||
pci_free_consistent(ar_pci->pdev, orig_nbytes, data_buf,
|
||||
ce_data_base);
|
||||
dma_free_coherent(ar->dev, orig_nbytes, data_buf,
|
||||
ce_data_base);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "%s failure (0x%x)\n", __func__,
|
||||
address);
|
||||
ath10k_warn("failed to write diag value at 0x%x: %d\n",
|
||||
address, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -747,17 +762,21 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
|
||||
struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl;
|
||||
struct ath10k_ce_ring *src_ring = ce_pipe->src_ring;
|
||||
unsigned int nentries_mask = src_ring->nentries_mask;
|
||||
unsigned int sw_index = src_ring->sw_index;
|
||||
unsigned int write_index = src_ring->write_index;
|
||||
int err, i;
|
||||
unsigned int nentries_mask;
|
||||
unsigned int sw_index;
|
||||
unsigned int write_index;
|
||||
int err, i = 0;
|
||||
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
|
||||
nentries_mask = src_ring->nentries_mask;
|
||||
sw_index = src_ring->sw_index;
|
||||
write_index = src_ring->write_index;
|
||||
|
||||
if (unlikely(CE_RING_DELTA(nentries_mask,
|
||||
write_index, sw_index - 1) < n_items)) {
|
||||
err = -ENOBUFS;
|
||||
goto unlock;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_items - 1; i++) {
|
||||
@@ -774,7 +793,7 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
items[i].transfer_id,
|
||||
CE_SEND_FLAG_GATHER);
|
||||
if (err)
|
||||
goto unlock;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* `i` is equal to `n_items -1` after for() */
|
||||
@@ -792,10 +811,15 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
items[i].transfer_id,
|
||||
0);
|
||||
if (err)
|
||||
goto unlock;
|
||||
goto err;
|
||||
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
for (; i > 0; i--)
|
||||
__ath10k_ce_send_revert(ce_pipe);
|
||||
|
||||
err = 0;
|
||||
unlock:
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
return err;
|
||||
}
|
||||
@@ -803,6 +827,9 @@ unlock:
|
||||
static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n");
|
||||
|
||||
return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
|
||||
}
|
||||
|
||||
@@ -854,6 +881,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
|
||||
static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
|
||||
int force)
|
||||
{
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n");
|
||||
|
||||
if (!force) {
|
||||
int resources;
|
||||
/*
|
||||
@@ -880,7 +909,7 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n");
|
||||
|
||||
memcpy(&ar_pci->msg_callbacks_current, callbacks,
|
||||
sizeof(ar_pci->msg_callbacks_current));
|
||||
@@ -938,6 +967,8 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n");
|
||||
|
||||
/* polling for received messages not supported */
|
||||
*dl_is_polled = 0;
|
||||
|
||||
@@ -997,6 +1028,8 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
|
||||
{
|
||||
int ul_is_polled, dl_is_polled;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n");
|
||||
|
||||
(void)ath10k_pci_hif_map_service_to_pipe(ar,
|
||||
ATH10K_HTC_SVC_ID_RSVD_CTRL,
|
||||
ul_pipe,
|
||||
@@ -1098,6 +1131,8 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret, ret_early;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n");
|
||||
|
||||
ath10k_pci_free_early_irq(ar);
|
||||
ath10k_pci_kill_tasklet(ar);
|
||||
|
||||
@@ -1233,18 +1268,10 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)
|
||||
|
||||
static void ath10k_pci_ce_deinit(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_pci_pipe *pipe_info;
|
||||
int pipe_num;
|
||||
int i;
|
||||
|
||||
for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
|
||||
pipe_info = &ar_pci->pipe_info[pipe_num];
|
||||
if (pipe_info->ce_hdl) {
|
||||
ath10k_ce_deinit(pipe_info->ce_hdl);
|
||||
pipe_info->ce_hdl = NULL;
|
||||
pipe_info->buf_sz = 0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < CE_COUNT; i++)
|
||||
ath10k_ce_deinit_pipe(ar, i);
|
||||
}
|
||||
|
||||
static void ath10k_pci_hif_stop(struct ath10k *ar)
|
||||
@@ -1252,7 +1279,10 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n");
|
||||
|
||||
if (WARN_ON(!ar_pci->started))
|
||||
return;
|
||||
|
||||
ret = ath10k_ce_disable_interrupts(ar);
|
||||
if (ret)
|
||||
@@ -1697,30 +1727,49 @@ static int ath10k_pci_init_config(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_pci_alloc_ce(struct ath10k *ar)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < CE_COUNT; i++) {
|
||||
ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
|
||||
if (ret) {
|
||||
ath10k_err("failed to allocate copy engine pipe %d: %d\n",
|
||||
i, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_pci_free_ce(struct ath10k *ar)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CE_COUNT; i++)
|
||||
ath10k_ce_free_pipe(ar, i);
|
||||
}
|
||||
|
||||
static int ath10k_pci_ce_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_pci_pipe *pipe_info;
|
||||
const struct ce_attr *attr;
|
||||
int pipe_num;
|
||||
int pipe_num, ret;
|
||||
|
||||
for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
|
||||
pipe_info = &ar_pci->pipe_info[pipe_num];
|
||||
pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num];
|
||||
pipe_info->pipe_num = pipe_num;
|
||||
pipe_info->hif_ce_state = ar;
|
||||
attr = &host_ce_config_wlan[pipe_num];
|
||||
|
||||
pipe_info->ce_hdl = ath10k_ce_init(ar, pipe_num, attr);
|
||||
if (pipe_info->ce_hdl == NULL) {
|
||||
ath10k_err("failed to initialize CE for pipe: %d\n",
|
||||
pipe_num);
|
||||
|
||||
/* It is safe to call it here. It checks if ce_hdl is
|
||||
* valid for each pipe */
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
return -1;
|
||||
ret = ath10k_ce_init_pipe(ar, pipe_num, attr);
|
||||
if (ret) {
|
||||
ath10k_err("failed to initialize copy engine pipe %d: %d\n",
|
||||
pipe_num, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pipe_num == CE_COUNT - 1) {
|
||||
@@ -1741,16 +1790,15 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
|
||||
static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
u32 fw_indicator_address, fw_indicator;
|
||||
u32 fw_indicator;
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
|
||||
fw_indicator_address = ar_pci->fw_indicator_address;
|
||||
fw_indicator = ath10k_pci_read32(ar, fw_indicator_address);
|
||||
fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
|
||||
|
||||
if (fw_indicator & FW_IND_EVENT_PENDING) {
|
||||
/* ACK: clear Target-side pending event */
|
||||
ath10k_pci_write32(ar, fw_indicator_address,
|
||||
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
|
||||
fw_indicator & ~FW_IND_EVENT_PENDING);
|
||||
|
||||
if (ar_pci->started) {
|
||||
@@ -1767,13 +1815,32 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
|
||||
ath10k_pci_sleep(ar);
|
||||
}
|
||||
|
||||
/* this function effectively clears target memory controller assert line */
|
||||
static void ath10k_pci_warm_reset_si0(struct ath10k *ar)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
|
||||
ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
|
||||
val | SOC_RESET_CONTROL_SI0_RST_MASK);
|
||||
val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
|
||||
|
||||
msleep(10);
|
||||
|
||||
val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
|
||||
ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
|
||||
val & ~SOC_RESET_CONTROL_SI0_RST_MASK);
|
||||
val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
|
||||
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static int ath10k_pci_warm_reset(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ret = 0;
|
||||
u32 val;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot performing warm chip reset\n");
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n");
|
||||
|
||||
ret = ath10k_do_pci_wake(ar);
|
||||
if (ret) {
|
||||
@@ -1801,7 +1868,7 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
|
||||
msleep(100);
|
||||
|
||||
/* clear fw indicator */
|
||||
ath10k_pci_write32(ar, ar_pci->fw_indicator_address, 0);
|
||||
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0);
|
||||
|
||||
/* clear target LF timer interrupts */
|
||||
val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
|
||||
@@ -1826,6 +1893,8 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
|
||||
SOC_RESET_CONTROL_ADDRESS);
|
||||
msleep(10);
|
||||
|
||||
ath10k_pci_warm_reset_si0(ar);
|
||||
|
||||
/* debug */
|
||||
val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
|
||||
PCIE_INTR_CAUSE_ADDRESS);
|
||||
@@ -1934,7 +2003,9 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
|
||||
irq_mode = "legacy";
|
||||
|
||||
if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
|
||||
ath10k_info("pci irq %s\n", irq_mode);
|
||||
ath10k_info("pci irq %s irq_mode %d reset_mode %d\n",
|
||||
irq_mode, ath10k_pci_irq_mode,
|
||||
ath10k_pci_reset_mode);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1952,23 +2023,52 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_pci_hif_power_up_warm(struct ath10k *ar)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
/*
|
||||
* Sometime warm reset succeeds after retries.
|
||||
*
|
||||
* FIXME: It might be possible to tune ath10k_pci_warm_reset() to work
|
||||
* at first try.
|
||||
*/
|
||||
for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) {
|
||||
ret = __ath10k_pci_hif_power_up(ar, false);
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n",
|
||||
i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_pci_hif_power_up(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n");
|
||||
|
||||
/*
|
||||
* Hardware CUS232 version 2 has some issues with cold reset and the
|
||||
* preferred (and safer) way to perform a device reset is through a
|
||||
* warm reset.
|
||||
*
|
||||
* Warm reset doesn't always work though (notably after a firmware
|
||||
* crash) so fall back to cold reset if necessary.
|
||||
* Warm reset doesn't always work though so fall back to cold reset may
|
||||
* be necessary.
|
||||
*/
|
||||
ret = __ath10k_pci_hif_power_up(ar, false);
|
||||
ret = ath10k_pci_hif_power_up_warm(ar);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to power up target using warm reset (%d), trying cold reset\n",
|
||||
ath10k_warn("failed to power up target using warm reset: %d\n",
|
||||
ret);
|
||||
|
||||
if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY)
|
||||
return ret;
|
||||
|
||||
ath10k_warn("trying cold reset\n");
|
||||
|
||||
ret = __ath10k_pci_hif_power_up(ar, true);
|
||||
if (ret) {
|
||||
ath10k_err("failed to power up target using cold reset too (%d)\n",
|
||||
@@ -1984,12 +2084,14 @@ static void ath10k_pci_hif_power_down(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n");
|
||||
|
||||
ath10k_pci_free_early_irq(ar);
|
||||
ath10k_pci_kill_tasklet(ar);
|
||||
ath10k_pci_deinit_irq(ar);
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
ath10k_pci_warm_reset(ar);
|
||||
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
|
||||
ath10k_do_pci_sleep(ar);
|
||||
}
|
||||
@@ -2137,7 +2239,6 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
|
||||
static void ath10k_pci_early_irq_tasklet(unsigned long data)
|
||||
{
|
||||
struct ath10k *ar = (struct ath10k *)data;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
u32 fw_ind;
|
||||
int ret;
|
||||
|
||||
@@ -2148,14 +2249,11 @@ static void ath10k_pci_early_irq_tasklet(unsigned long data)
|
||||
return;
|
||||
}
|
||||
|
||||
fw_ind = ath10k_pci_read32(ar, ar_pci->fw_indicator_address);
|
||||
fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
|
||||
if (fw_ind & FW_IND_EVENT_PENDING) {
|
||||
ath10k_pci_write32(ar, ar_pci->fw_indicator_address,
|
||||
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
|
||||
fw_ind & ~FW_IND_EVENT_PENDING);
|
||||
|
||||
/* Some structures are unavailable during early boot or at
|
||||
* driver teardown so just print that the device has crashed. */
|
||||
ath10k_warn("device crashed - no diagnostics available\n");
|
||||
ath10k_pci_hif_dump_area(ar);
|
||||
}
|
||||
|
||||
ath10k_pci_sleep(ar);
|
||||
@@ -2385,33 +2483,69 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
|
||||
static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int wait_limit = 300; /* 3 sec */
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_err("failed to wake up target: %d\n", ret);
|
||||
ath10k_err("failed to wake up target for init: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (wait_limit-- &&
|
||||
!(ioread32(ar_pci->mem + FW_INDICATOR_ADDRESS) &
|
||||
FW_IND_INITIALIZED)) {
|
||||
timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT);
|
||||
|
||||
do {
|
||||
val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val);
|
||||
|
||||
/* target should never return this */
|
||||
if (val == 0xffffffff)
|
||||
continue;
|
||||
|
||||
/* the device has crashed so don't bother trying anymore */
|
||||
if (val & FW_IND_EVENT_PENDING)
|
||||
break;
|
||||
|
||||
if (val & FW_IND_INITIALIZED)
|
||||
break;
|
||||
|
||||
if (ar_pci->num_msi_intrs == 0)
|
||||
/* Fix potential race by repeating CORE_BASE writes */
|
||||
iowrite32(PCIE_INTR_FIRMWARE_MASK |
|
||||
PCIE_INTR_CE_MASK_ALL,
|
||||
ar_pci->mem + (SOC_CORE_BASE_ADDRESS |
|
||||
PCIE_INTR_ENABLE_ADDRESS));
|
||||
mdelay(10);
|
||||
}
|
||||
ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS,
|
||||
PCIE_INTR_FIRMWARE_MASK |
|
||||
PCIE_INTR_CE_MASK_ALL);
|
||||
|
||||
if (wait_limit < 0) {
|
||||
ath10k_err("target stalled\n");
|
||||
mdelay(10);
|
||||
} while (time_before(jiffies, timeout));
|
||||
|
||||
if (val == 0xffffffff) {
|
||||
ath10k_err("failed to read device register, device is gone\n");
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (val & FW_IND_EVENT_PENDING) {
|
||||
ath10k_warn("device has crashed during init\n");
|
||||
ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
|
||||
val & ~FW_IND_EVENT_PENDING);
|
||||
ath10k_pci_hif_dump_area(ar);
|
||||
ret = -ECOMM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(val & FW_IND_INITIALIZED)) {
|
||||
ath10k_err("failed to receive initialized event from target: %08x\n",
|
||||
val);
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n");
|
||||
|
||||
out:
|
||||
ath10k_pci_sleep(ar);
|
||||
return ret;
|
||||
@@ -2422,6 +2556,8 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
|
||||
int i, ret;
|
||||
u32 val;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n");
|
||||
|
||||
ret = ath10k_do_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_err("failed to wake up target: %d\n",
|
||||
@@ -2453,6 +2589,9 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
|
||||
}
|
||||
|
||||
ath10k_do_pci_sleep(ar);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2484,7 +2623,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
struct ath10k_pci *ar_pci;
|
||||
u32 lcr_val, chip_id;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n");
|
||||
|
||||
ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL);
|
||||
if (ar_pci == NULL)
|
||||
@@ -2503,7 +2642,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
goto err_ar_pci;
|
||||
}
|
||||
|
||||
if (ath10k_target_ps)
|
||||
if (ath10k_pci_target_ps)
|
||||
set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features);
|
||||
|
||||
ath10k_pci_dump_features(ar_pci);
|
||||
@@ -2516,23 +2655,10 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
ar_pci->ar = ar;
|
||||
ar_pci->fw_indicator_address = FW_INDICATOR_ADDRESS;
|
||||
atomic_set(&ar_pci->keep_awake_count, 0);
|
||||
|
||||
pci_set_drvdata(pdev, ar);
|
||||
|
||||
/*
|
||||
* Without any knowledge of the Host, the Target may have been reset or
|
||||
* power cycled and its Config Space may no longer reflect the PCI
|
||||
* address space that was assigned earlier by the PCI infrastructure.
|
||||
* Refresh it now.
|
||||
*/
|
||||
ret = pci_assign_resource(pdev, BAR_NUM);
|
||||
if (ret) {
|
||||
ath10k_err("failed to assign PCI space: %d\n", ret);
|
||||
goto err_ar;
|
||||
}
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
ath10k_err("failed to enable PCI device: %d\n", ret);
|
||||
@@ -2594,16 +2720,24 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||
|
||||
ath10k_do_pci_sleep(ar);
|
||||
|
||||
ret = ath10k_pci_alloc_ce(ar);
|
||||
if (ret) {
|
||||
ath10k_err("failed to allocate copy engine pipes: %d\n", ret);
|
||||
goto err_iomap;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
|
||||
|
||||
ret = ath10k_core_register(ar, chip_id);
|
||||
if (ret) {
|
||||
ath10k_err("failed to register driver core: %d\n", ret);
|
||||
goto err_iomap;
|
||||
goto err_free_ce;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_ce:
|
||||
ath10k_pci_free_ce(ar);
|
||||
err_iomap:
|
||||
pci_iounmap(pdev, mem);
|
||||
err_master:
|
||||
@@ -2626,7 +2760,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
|
||||
struct ath10k *ar = pci_get_drvdata(pdev);
|
||||
struct ath10k_pci *ar_pci;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n");
|
||||
|
||||
if (!ar)
|
||||
return;
|
||||
@@ -2636,9 +2770,8 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
|
||||
if (!ar_pci)
|
||||
return;
|
||||
|
||||
tasklet_kill(&ar_pci->msi_fw_err);
|
||||
|
||||
ath10k_core_unregister(ar);
|
||||
ath10k_pci_free_ce(ar);
|
||||
|
||||
pci_iounmap(pdev, ar_pci->mem);
|
||||
pci_release_region(pdev, BAR_NUM);
|
||||
@@ -2680,6 +2813,5 @@ module_exit(ath10k_pci_exit);
|
||||
MODULE_AUTHOR("Qualcomm Atheros");
|
||||
MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_OTP_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
|
||||
|
@@ -189,9 +189,6 @@ struct ath10k_pci {
|
||||
|
||||
struct ath10k_hif_cb msg_callbacks_current;
|
||||
|
||||
/* Target address used to signal a pending firmware event */
|
||||
u32 fw_indicator_address;
|
||||
|
||||
/* Copy Engine used for Diagnostic Accesses */
|
||||
struct ath10k_ce_pipe *ce_diag;
|
||||
|
||||
|
@@ -100,189 +100,6 @@ exit:
|
||||
wake_up(&htt->empty_tx_wq);
|
||||
}
|
||||
|
||||
static const u8 rx_legacy_rate_idx[] = {
|
||||
3, /* 0x00 - 11Mbps */
|
||||
2, /* 0x01 - 5.5Mbps */
|
||||
1, /* 0x02 - 2Mbps */
|
||||
0, /* 0x03 - 1Mbps */
|
||||
3, /* 0x04 - 11Mbps */
|
||||
2, /* 0x05 - 5.5Mbps */
|
||||
1, /* 0x06 - 2Mbps */
|
||||
0, /* 0x07 - 1Mbps */
|
||||
10, /* 0x08 - 48Mbps */
|
||||
8, /* 0x09 - 24Mbps */
|
||||
6, /* 0x0A - 12Mbps */
|
||||
4, /* 0x0B - 6Mbps */
|
||||
11, /* 0x0C - 54Mbps */
|
||||
9, /* 0x0D - 36Mbps */
|
||||
7, /* 0x0E - 18Mbps */
|
||||
5, /* 0x0F - 9Mbps */
|
||||
};
|
||||
|
||||
static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
|
||||
u8 info0 = info->rate.info0;
|
||||
u32 info1 = info->rate.info1;
|
||||
u32 info2 = info->rate.info2;
|
||||
u8 preamble = 0;
|
||||
|
||||
/* Check if valid fields */
|
||||
if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID))
|
||||
return;
|
||||
|
||||
preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE);
|
||||
|
||||
switch (preamble) {
|
||||
case HTT_RX_LEGACY:
|
||||
cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK;
|
||||
rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE);
|
||||
rate_idx = 0;
|
||||
|
||||
if (rate < 0x08 || rate > 0x0F)
|
||||
break;
|
||||
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if (cck)
|
||||
rate &= ~BIT(3);
|
||||
rate_idx = rx_legacy_rate_idx[rate];
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
rate_idx = rx_legacy_rate_idx[rate];
|
||||
/* We are using same rate table registering
|
||||
HW - ath10k_rates[]. In case of 5GHz skip
|
||||
CCK rates, so -4 here */
|
||||
rate_idx -= 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
status->rate_idx = rate_idx;
|
||||
break;
|
||||
case HTT_RX_HT:
|
||||
case HTT_RX_HT_WITH_TXBF:
|
||||
/* HT-SIG - Table 20-11 in info1 and info2 */
|
||||
mcs = info1 & 0x1F;
|
||||
nss = mcs >> 3;
|
||||
bw = (info1 >> 7) & 1;
|
||||
sgi = (info2 >> 7) & 1;
|
||||
|
||||
status->rate_idx = mcs;
|
||||
status->flag |= RX_FLAG_HT;
|
||||
if (sgi)
|
||||
status->flag |= RX_FLAG_SHORT_GI;
|
||||
if (bw)
|
||||
status->flag |= RX_FLAG_40MHZ;
|
||||
break;
|
||||
case HTT_RX_VHT:
|
||||
case HTT_RX_VHT_WITH_TXBF:
|
||||
/* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2
|
||||
TODO check this */
|
||||
mcs = (info2 >> 4) & 0x0F;
|
||||
nss = ((info1 >> 10) & 0x07) + 1;
|
||||
bw = info1 & 3;
|
||||
sgi = info2 & 1;
|
||||
|
||||
status->rate_idx = mcs;
|
||||
status->vht_nss = nss;
|
||||
|
||||
if (sgi)
|
||||
status->flag |= RX_FLAG_SHORT_GI;
|
||||
|
||||
switch (bw) {
|
||||
/* 20MHZ */
|
||||
case 0:
|
||||
break;
|
||||
/* 40MHZ */
|
||||
case 1:
|
||||
status->flag |= RX_FLAG_40MHZ;
|
||||
break;
|
||||
/* 80MHZ */
|
||||
case 2:
|
||||
status->vht_flag |= RX_VHT_FLAG_80MHZ;
|
||||
}
|
||||
|
||||
status->flag |= RX_FLAG_VHT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
|
||||
{
|
||||
struct ieee80211_rx_status *status;
|
||||
struct ieee80211_channel *ch;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)info->skb->data;
|
||||
|
||||
status = IEEE80211_SKB_RXCB(info->skb);
|
||||
memset(status, 0, sizeof(*status));
|
||||
|
||||
if (info->encrypt_type != HTT_RX_MPDU_ENCRYPT_NONE) {
|
||||
status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
hdr->frame_control = __cpu_to_le16(
|
||||
__le16_to_cpu(hdr->frame_control) &
|
||||
~IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
|
||||
if (info->mic_err)
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
if (info->fcs_err)
|
||||
status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
|
||||
if (info->amsdu_more)
|
||||
status->flag |= RX_FLAG_AMSDU_MORE;
|
||||
|
||||
status->signal = info->signal;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ch = ar->scan_channel;
|
||||
if (!ch)
|
||||
ch = ar->rx_channel;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (!ch) {
|
||||
ath10k_warn("no channel configured; ignoring frame!\n");
|
||||
dev_kfree_skb_any(info->skb);
|
||||
return;
|
||||
}
|
||||
|
||||
process_rx_rates(ar, info, ch->band, status);
|
||||
status->band = ch->band;
|
||||
status->freq = ch->center_freq;
|
||||
|
||||
if (info->rate.info0 & HTT_RX_INDICATION_INFO0_END_VALID) {
|
||||
/* TSF available only in 32-bit */
|
||||
status->mactime = info->tsf & 0xffffffff;
|
||||
status->flag |= RX_FLAG_MACTIME_END;
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_DATA,
|
||||
"rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i\n",
|
||||
info->skb,
|
||||
info->skb->len,
|
||||
status->flag == 0 ? "legacy" : "",
|
||||
status->flag & RX_FLAG_HT ? "ht" : "",
|
||||
status->flag & RX_FLAG_VHT ? "vht" : "",
|
||||
status->flag & RX_FLAG_40MHZ ? "40" : "",
|
||||
status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "",
|
||||
status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
|
||||
status->rate_idx,
|
||||
status->vht_nss,
|
||||
status->freq,
|
||||
status->band, status->flag, info->fcs_err);
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
|
||||
info->skb->data, info->skb->len);
|
||||
|
||||
ieee80211_rx(ar->hw, info->skb);
|
||||
}
|
||||
|
||||
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr)
|
||||
{
|
||||
|
@@ -21,7 +21,6 @@
|
||||
|
||||
void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
const struct htt_tx_done *tx_done);
|
||||
void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info);
|
||||
|
||||
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr);
|
||||
|
@@ -639,6 +639,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
|
||||
struct sk_buff *wmi_skb;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
int len;
|
||||
u32 buf_len = skb->len;
|
||||
u16 fc;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
@@ -648,6 +649,15 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
|
||||
return -EINVAL;
|
||||
|
||||
len = sizeof(cmd->hdr) + skb->len;
|
||||
|
||||
if ((ieee80211_is_action(hdr->frame_control) ||
|
||||
ieee80211_is_deauth(hdr->frame_control) ||
|
||||
ieee80211_is_disassoc(hdr->frame_control)) &&
|
||||
ieee80211_has_protected(hdr->frame_control)) {
|
||||
len += IEEE80211_CCMP_MIC_LEN;
|
||||
buf_len += IEEE80211_CCMP_MIC_LEN;
|
||||
}
|
||||
|
||||
len = round_up(len, 4);
|
||||
|
||||
wmi_skb = ath10k_wmi_alloc_skb(len);
|
||||
@@ -659,7 +669,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
|
||||
cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id);
|
||||
cmd->hdr.tx_rate = 0;
|
||||
cmd->hdr.tx_power = 0;
|
||||
cmd->hdr.buf_len = __cpu_to_le32((u32)(skb->len));
|
||||
cmd->hdr.buf_len = __cpu_to_le32(buf_len);
|
||||
|
||||
memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN);
|
||||
memcpy(cmd->buf, skb->data, skb->len);
|
||||
@@ -957,10 +967,16 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
* frames with Protected Bit set. */
|
||||
if (ieee80211_has_protected(hdr->frame_control) &&
|
||||
!ieee80211_is_auth(hdr->frame_control)) {
|
||||
status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
hdr->frame_control = __cpu_to_le16(fc &
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
|
||||
if (!ieee80211_is_action(hdr->frame_control) &&
|
||||
!ieee80211_is_deauth(hdr->frame_control) &&
|
||||
!ieee80211_is_disassoc(hdr->frame_control)) {
|
||||
status->flag |= RX_FLAG_IV_STRIPPED |
|
||||
RX_FLAG_MMIC_STRIPPED;
|
||||
hdr->frame_control = __cpu_to_le16(fc &
|
||||
~IEEE80211_FCTL_PROTECTED);
|
||||
}
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MGMT,
|
||||
@@ -1362,13 +1378,10 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
|
||||
struct sk_buff *bcn;
|
||||
int ret, vdev_id = 0;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n");
|
||||
|
||||
ev = (struct wmi_host_swba_event *)skb->data;
|
||||
map = __le32_to_cpu(ev->vdev_map);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MGMT, "host swba:\n"
|
||||
"-vdev map 0x%x\n",
|
||||
ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
|
||||
ev->vdev_map);
|
||||
|
||||
for (; map; map >>= 1, vdev_id++) {
|
||||
@@ -1385,12 +1398,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
|
||||
bcn_info = &ev->bcn_info[i];
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_MGMT,
|
||||
"-bcn_info[%d]:\n"
|
||||
"--tim_len %d\n"
|
||||
"--tim_mcast %d\n"
|
||||
"--tim_changed %d\n"
|
||||
"--tim_num_ps_pending %d\n"
|
||||
"--tim_bitmap 0x%08x%08x%08x%08x\n",
|
||||
"mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",
|
||||
i,
|
||||
__le32_to_cpu(bcn_info->tim_info.tim_len),
|
||||
__le32_to_cpu(bcn_info->tim_info.tim_mcast),
|
||||
@@ -1439,6 +1447,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
|
||||
ATH10K_SKB_CB(arvif->beacon)->paddr,
|
||||
arvif->beacon->len, DMA_TO_DEVICE);
|
||||
dev_kfree_skb_any(arvif->beacon);
|
||||
arvif->beacon = NULL;
|
||||
}
|
||||
|
||||
ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev,
|
||||
@@ -1448,6 +1457,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
|
||||
ATH10K_SKB_CB(bcn)->paddr);
|
||||
if (ret) {
|
||||
ath10k_warn("failed to map beacon: %d\n", ret);
|
||||
dev_kfree_skb_any(bcn);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
@@ -2365,7 +2375,7 @@ void ath10k_wmi_detach(struct ath10k *ar)
|
||||
ar->wmi.num_mem_chunks = 0;
|
||||
}
|
||||
|
||||
int ath10k_wmi_connect_htc_service(struct ath10k *ar)
|
||||
int ath10k_wmi_connect(struct ath10k *ar)
|
||||
{
|
||||
int status;
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
@@ -2393,8 +2403,9 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
|
||||
u16 rd5g, u16 ctl2g, u16 ctl5g)
|
||||
static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
|
||||
u16 rd2g, u16 rd5g, u16 ctl2g,
|
||||
u16 ctl5g)
|
||||
{
|
||||
struct wmi_pdev_set_regdomain_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
@@ -2418,6 +2429,46 @@ int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
|
||||
ar->wmi.cmd->pdev_set_regdomain_cmdid);
|
||||
}
|
||||
|
||||
static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
|
||||
u16 rd2g, u16 rd5g,
|
||||
u16 ctl2g, u16 ctl5g,
|
||||
enum wmi_dfs_region dfs_reg)
|
||||
{
|
||||
struct wmi_pdev_set_regdomain_cmd_10x *cmd;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data;
|
||||
cmd->reg_domain = __cpu_to_le32(rd);
|
||||
cmd->reg_domain_2G = __cpu_to_le32(rd2g);
|
||||
cmd->reg_domain_5G = __cpu_to_le32(rd5g);
|
||||
cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g);
|
||||
cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
|
||||
cmd->dfs_domain = __cpu_to_le32(dfs_reg);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_WMI,
|
||||
"wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n",
|
||||
rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg);
|
||||
|
||||
return ath10k_wmi_cmd_send(ar, skb,
|
||||
ar->wmi.cmd->pdev_set_regdomain_cmdid);
|
||||
}
|
||||
|
||||
int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
|
||||
u16 rd5g, u16 ctl2g, u16 ctl5g,
|
||||
enum wmi_dfs_region dfs_reg)
|
||||
{
|
||||
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
|
||||
return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g,
|
||||
ctl2g, ctl5g, dfs_reg);
|
||||
else
|
||||
return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g,
|
||||
ctl2g, ctl5g);
|
||||
}
|
||||
|
||||
int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
|
||||
const struct wmi_channel_arg *arg)
|
||||
{
|
||||
@@ -3456,8 +3507,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
|
||||
__cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_WMI,
|
||||
"wmi peer assoc vdev %d addr %pM\n",
|
||||
arg->vdev_id, arg->addr);
|
||||
"wmi peer assoc vdev %d addr %pM (%s)\n",
|
||||
arg->vdev_id, arg->addr,
|
||||
arg->peer_reassoc ? "reassociate" : "new");
|
||||
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
|
||||
}
|
||||
|
||||
|
@@ -198,16 +198,6 @@ struct wmi_mac_addr {
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
/* macro to convert MAC address from WMI word format to char array */
|
||||
#define WMI_MAC_ADDR_TO_CHAR_ARRAY(pwmi_mac_addr, c_macaddr) do { \
|
||||
(c_macaddr)[0] = ((pwmi_mac_addr)->word0) & 0xff; \
|
||||
(c_macaddr)[1] = (((pwmi_mac_addr)->word0) >> 8) & 0xff; \
|
||||
(c_macaddr)[2] = (((pwmi_mac_addr)->word0) >> 16) & 0xff; \
|
||||
(c_macaddr)[3] = (((pwmi_mac_addr)->word0) >> 24) & 0xff; \
|
||||
(c_macaddr)[4] = ((pwmi_mac_addr)->word1) & 0xff; \
|
||||
(c_macaddr)[5] = (((pwmi_mac_addr)->word1) >> 8) & 0xff; \
|
||||
} while (0)
|
||||
|
||||
struct wmi_cmd_map {
|
||||
u32 init_cmdid;
|
||||
u32 start_scan_cmdid;
|
||||
@@ -2185,6 +2175,31 @@ struct wmi_pdev_set_regdomain_cmd {
|
||||
__le32 conformance_test_limit_5G;
|
||||
} __packed;
|
||||
|
||||
enum wmi_dfs_region {
|
||||
/* Uninitialized dfs domain */
|
||||
WMI_UNINIT_DFS_DOMAIN = 0,
|
||||
|
||||
/* FCC3 dfs domain */
|
||||
WMI_FCC_DFS_DOMAIN = 1,
|
||||
|
||||
/* ETSI dfs domain */
|
||||
WMI_ETSI_DFS_DOMAIN = 2,
|
||||
|
||||
/*Japan dfs domain */
|
||||
WMI_MKK4_DFS_DOMAIN = 3,
|
||||
};
|
||||
|
||||
struct wmi_pdev_set_regdomain_cmd_10x {
|
||||
__le32 reg_domain;
|
||||
__le32 reg_domain_2G;
|
||||
__le32 reg_domain_5G;
|
||||
__le32 conformance_test_limit_2G;
|
||||
__le32 conformance_test_limit_5G;
|
||||
|
||||
/* dfs domain from wmi_dfs_region */
|
||||
__le32 dfs_domain;
|
||||
} __packed;
|
||||
|
||||
/* Command to set/unset chip in quiet mode */
|
||||
struct wmi_pdev_set_quiet_cmd {
|
||||
/* period in TUs */
|
||||
@@ -2210,6 +2225,19 @@ enum ath10k_protmode {
|
||||
ATH10K_PROT_RTSCTS = 2, /* RTS-CTS */
|
||||
};
|
||||
|
||||
enum wmi_rtscts_profile {
|
||||
WMI_RTSCTS_FOR_NO_RATESERIES = 0,
|
||||
WMI_RTSCTS_FOR_SECOND_RATESERIES,
|
||||
WMI_RTSCTS_ACROSS_SW_RETRIES
|
||||
};
|
||||
|
||||
#define WMI_RTSCTS_ENABLED 1
|
||||
#define WMI_RTSCTS_SET_MASK 0x0f
|
||||
#define WMI_RTSCTS_SET_LSB 0
|
||||
|
||||
#define WMI_RTSCTS_PROFILE_MASK 0xf0
|
||||
#define WMI_RTSCTS_PROFILE_LSB 4
|
||||
|
||||
enum wmi_beacon_gen_mode {
|
||||
WMI_BEACON_STAGGERED_MODE = 0,
|
||||
WMI_BEACON_BURST_MODE = 1
|
||||
@@ -2295,9 +2323,9 @@ struct wmi_pdev_param_map {
|
||||
#define WMI_PDEV_PARAM_UNSUPPORTED 0
|
||||
|
||||
enum wmi_pdev_param {
|
||||
/* TX chian mask */
|
||||
/* TX chain mask */
|
||||
WMI_PDEV_PARAM_TX_CHAIN_MASK = 0x1,
|
||||
/* RX chian mask */
|
||||
/* RX chain mask */
|
||||
WMI_PDEV_PARAM_RX_CHAIN_MASK,
|
||||
/* TX power limit for 2G Radio */
|
||||
WMI_PDEV_PARAM_TXPOWER_LIMIT2G,
|
||||
@@ -2682,6 +2710,9 @@ struct wal_dbg_tx_stats {
|
||||
/* wal pdev resets */
|
||||
__le32 pdev_resets;
|
||||
|
||||
/* frames dropped due to non-availability of stateless TIDs */
|
||||
__le32 stateless_tid_alloc_failure;
|
||||
|
||||
__le32 phy_underrun;
|
||||
|
||||
/* MPDU is more than txop limit */
|
||||
@@ -2738,13 +2769,21 @@ enum wmi_stats_id {
|
||||
WMI_REQUEST_AP_STAT = 0x02
|
||||
};
|
||||
|
||||
struct wlan_inst_rssi_args {
|
||||
__le16 cfg_retry_count;
|
||||
__le16 retry_count;
|
||||
};
|
||||
|
||||
struct wmi_request_stats_cmd {
|
||||
__le32 stats_id;
|
||||
|
||||
/*
|
||||
* Space to add parameters like
|
||||
* peer mac addr
|
||||
*/
|
||||
__le32 vdev_id;
|
||||
|
||||
/* peer MAC address */
|
||||
struct wmi_mac_addr peer_macaddr;
|
||||
|
||||
/* Instantaneous RSSI arguments */
|
||||
struct wlan_inst_rssi_args inst_rssi_args;
|
||||
} __packed;
|
||||
|
||||
/* Suspend option */
|
||||
@@ -2795,7 +2834,7 @@ struct wmi_stats_event {
|
||||
* PDEV statistics
|
||||
* TODO: add all PDEV stats here
|
||||
*/
|
||||
struct wmi_pdev_stats {
|
||||
struct wmi_pdev_stats_old {
|
||||
__le32 chan_nf; /* Channel noise floor */
|
||||
__le32 tx_frame_count; /* TX frame count */
|
||||
__le32 rx_frame_count; /* RX frame count */
|
||||
@@ -2806,6 +2845,23 @@ struct wmi_pdev_stats {
|
||||
struct wal_dbg_stats wal; /* WAL dbg stats */
|
||||
} __packed;
|
||||
|
||||
struct wmi_pdev_stats_10x {
|
||||
__le32 chan_nf; /* Channel noise floor */
|
||||
__le32 tx_frame_count; /* TX frame count */
|
||||
__le32 rx_frame_count; /* RX frame count */
|
||||
__le32 rx_clear_count; /* rx clear count */
|
||||
__le32 cycle_count; /* cycle count */
|
||||
__le32 phy_err_count; /* Phy error count */
|
||||
__le32 chan_tx_pwr; /* channel tx power */
|
||||
struct wal_dbg_stats wal; /* WAL dbg stats */
|
||||
__le32 ack_rx_bad;
|
||||
__le32 rts_bad;
|
||||
__le32 rts_good;
|
||||
__le32 fcs_bad;
|
||||
__le32 no_beacons;
|
||||
__le32 mib_int_count;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* VDEV statistics
|
||||
* TODO: add all VDEV stats here
|
||||
@@ -2818,12 +2874,19 @@ struct wmi_vdev_stats {
|
||||
* peer statistics.
|
||||
* TODO: add more stats
|
||||
*/
|
||||
struct wmi_peer_stats {
|
||||
struct wmi_peer_stats_old {
|
||||
struct wmi_mac_addr peer_macaddr;
|
||||
__le32 peer_rssi;
|
||||
__le32 peer_tx_rate;
|
||||
} __packed;
|
||||
|
||||
struct wmi_peer_stats_10x {
|
||||
struct wmi_mac_addr peer_macaddr;
|
||||
__le32 peer_rssi;
|
||||
__le32 peer_tx_rate;
|
||||
__le32 peer_rx_rate;
|
||||
} __packed;
|
||||
|
||||
struct wmi_vdev_create_cmd {
|
||||
__le32 vdev_id;
|
||||
__le32 vdev_type;
|
||||
@@ -4196,13 +4259,14 @@ void ath10k_wmi_detach(struct ath10k *ar);
|
||||
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);
|
||||
int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
|
||||
|
||||
int ath10k_wmi_connect_htc_service(struct ath10k *ar);
|
||||
int ath10k_wmi_connect(struct ath10k *ar);
|
||||
int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
|
||||
const struct wmi_channel_arg *);
|
||||
int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
|
||||
int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
|
||||
int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
|
||||
u16 rd5g, u16 ctl2g, u16 ctl5g);
|
||||
u16 rd5g, u16 ctl2g, u16 ctl5g,
|
||||
enum wmi_dfs_region dfs_reg);
|
||||
int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value);
|
||||
int ath10k_wmi_cmd_init(struct ath10k *ar);
|
||||
int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *);
|
||||
|
Reference in New Issue
Block a user