mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-linville' of git://github.com/kvalo/ath
This commit is contained in:
commit
98497bb241
|
@ -76,36 +76,7 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar,
|
|||
u32 ce_ctrl_addr,
|
||||
unsigned int n)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
void __iomem *indicator_addr;
|
||||
|
||||
if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) {
|
||||
ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n);
|
||||
return;
|
||||
}
|
||||
|
||||
/* workaround for QCA988x_1.0 HW CE */
|
||||
indicator_addr = ar_pci->mem + ce_ctrl_addr + DST_WATERMARK_ADDRESS;
|
||||
|
||||
if (ce_ctrl_addr == ath10k_ce_base_address(CDC_WAR_DATA_CE)) {
|
||||
iowrite32((CDC_WAR_MAGIC_STR | n), indicator_addr);
|
||||
} else {
|
||||
unsigned long irq_flags;
|
||||
local_irq_save(irq_flags);
|
||||
iowrite32(1, indicator_addr);
|
||||
|
||||
/*
|
||||
* PCIE write waits for ACK in IPQ8K, there is no
|
||||
* need to read back value.
|
||||
*/
|
||||
(void)ioread32(indicator_addr);
|
||||
(void)ioread32(indicator_addr); /* conservative */
|
||||
|
||||
ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n);
|
||||
|
||||
iowrite32(0, indicator_addr);
|
||||
local_irq_restore(irq_flags);
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar,
|
||||
|
@ -285,7 +256,7 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,
|
|||
* ath10k_ce_sendlist_send.
|
||||
* The caller takes responsibility for any needed locking.
|
||||
*/
|
||||
static int ath10k_ce_send_nolock(struct ce_state *ce_state,
|
||||
static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
|
@ -293,7 +264,7 @@ static int ath10k_ce_send_nolock(struct ce_state *ce_state,
|
|||
unsigned int flags)
|
||||
{
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ce_ring_state *src_ring = ce_state->src_ring;
|
||||
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
|
||||
struct ce_desc *desc, *sdesc;
|
||||
unsigned int nentries_mask = src_ring->nentries_mask;
|
||||
unsigned int sw_index = src_ring->sw_index;
|
||||
|
@ -306,7 +277,9 @@ static int ath10k_ce_send_nolock(struct ce_state *ce_state,
|
|||
ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n",
|
||||
__func__, nbytes, ce_state->src_sz_max);
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (unlikely(CE_RING_DELTA(nentries_mask,
|
||||
write_index, sw_index - 1) <= 0)) {
|
||||
|
@ -346,7 +319,7 @@ static int ath10k_ce_send_nolock(struct ce_state *ce_state,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ath10k_ce_send(struct ce_state *ce_state,
|
||||
int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
|
@ -378,12 +351,12 @@ void ath10k_ce_sendlist_buf_add(struct ce_sendlist *sendlist, u32 buffer,
|
|||
sendlist->num_items++;
|
||||
}
|
||||
|
||||
int ath10k_ce_sendlist_send(struct ce_state *ce_state,
|
||||
int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_context,
|
||||
struct ce_sendlist *sendlist,
|
||||
unsigned int transfer_id)
|
||||
{
|
||||
struct ce_ring_state *src_ring = ce_state->src_ring;
|
||||
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
|
||||
struct ce_sendlist_item *item;
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
@ -431,11 +404,11 @@ int ath10k_ce_sendlist_send(struct ce_state *ce_state,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
|
||||
int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_recv_context,
|
||||
u32 buffer)
|
||||
{
|
||||
struct ce_ring_state *dest_ring = ce_state->dest_ring;
|
||||
struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
|
||||
u32 ctrl_addr = ce_state->ctrl_addr;
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
@ -448,7 +421,9 @@ int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
|
|||
write_index = dest_ring->write_index;
|
||||
sw_index = dest_ring->sw_index;
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) {
|
||||
struct ce_desc *base = dest_ring->base_addr_owner_space;
|
||||
|
@ -470,6 +445,8 @@ int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
|
|||
ret = -EIO;
|
||||
}
|
||||
ath10k_pci_sleep(ar);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
|
||||
return ret;
|
||||
|
@ -479,14 +456,14 @@ int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
|
|||
* Guts of ath10k_ce_completed_recv_next.
|
||||
* The caller takes responsibility for any necessary locking.
|
||||
*/
|
||||
static int ath10k_ce_completed_recv_next_nolock(struct ce_state *ce_state,
|
||||
static int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp,
|
||||
unsigned int *flagsp)
|
||||
{
|
||||
struct ce_ring_state *dest_ring = ce_state->dest_ring;
|
||||
struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
|
||||
unsigned int nentries_mask = dest_ring->nentries_mask;
|
||||
unsigned int sw_index = dest_ring->sw_index;
|
||||
|
||||
|
@ -535,7 +512,7 @@ static int ath10k_ce_completed_recv_next_nolock(struct ce_state *ce_state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
|
||||
int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
|
@ -556,11 +533,11 @@ int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
|
||||
int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp)
|
||||
{
|
||||
struct ce_ring_state *dest_ring;
|
||||
struct ath10k_ce_ring *dest_ring;
|
||||
unsigned int nentries_mask;
|
||||
unsigned int sw_index;
|
||||
unsigned int write_index;
|
||||
|
@ -612,19 +589,20 @@ int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
|
|||
* Guts of ath10k_ce_completed_send_next.
|
||||
* The caller takes responsibility for any necessary locking.
|
||||
*/
|
||||
static int ath10k_ce_completed_send_next_nolock(struct ce_state *ce_state,
|
||||
static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp)
|
||||
{
|
||||
struct ce_ring_state *src_ring = ce_state->src_ring;
|
||||
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
|
||||
u32 ctrl_addr = ce_state->ctrl_addr;
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
unsigned int nentries_mask = src_ring->nentries_mask;
|
||||
unsigned int sw_index = src_ring->sw_index;
|
||||
struct ce_desc *sdesc, *sbase;
|
||||
unsigned int read_index;
|
||||
int ret = -EIO;
|
||||
int ret;
|
||||
|
||||
if (src_ring->hw_index == sw_index) {
|
||||
/*
|
||||
|
@ -634,17 +612,25 @@ static int ath10k_ce_completed_send_next_nolock(struct ce_state *ce_state,
|
|||
* the SW has really caught up to the HW, or if the cached
|
||||
* value of the HW index has become stale.
|
||||
*/
|
||||
ath10k_pci_wake(ar);
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
src_ring->hw_index =
|
||||
ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
|
||||
src_ring->hw_index &= nentries_mask;
|
||||
|
||||
ath10k_pci_sleep(ar);
|
||||
}
|
||||
|
||||
read_index = src_ring->hw_index;
|
||||
|
||||
if ((read_index != sw_index) && (read_index != 0xffffffff)) {
|
||||
struct ce_desc *sbase = src_ring->shadow_base;
|
||||
struct ce_desc *sdesc = CE_SRC_RING_TO_DESC(sbase, sw_index);
|
||||
if ((read_index == sw_index) || (read_index == 0xffffffff))
|
||||
return -EIO;
|
||||
|
||||
sbase = src_ring->shadow_base;
|
||||
sdesc = CE_SRC_RING_TO_DESC(sbase, sw_index);
|
||||
|
||||
/* Return data from completed source descriptor */
|
||||
*bufferp = __le32_to_cpu(sdesc->addr);
|
||||
|
@ -662,20 +648,18 @@ static int ath10k_ce_completed_send_next_nolock(struct ce_state *ce_state,
|
|||
/* Update sw_index */
|
||||
sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
|
||||
src_ring->sw_index = sw_index;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NB: Modeled after ath10k_ce_completed_send_next */
|
||||
int ath10k_ce_cancel_send_next(struct ce_state *ce_state,
|
||||
int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp)
|
||||
{
|
||||
struct ce_ring_state *src_ring;
|
||||
struct ath10k_ce_ring *src_ring;
|
||||
unsigned int nentries_mask;
|
||||
unsigned int sw_index;
|
||||
unsigned int write_index;
|
||||
|
@ -727,7 +711,7 @@ int ath10k_ce_cancel_send_next(struct ce_state *ce_state,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ath10k_ce_completed_send_next(struct ce_state *ce_state,
|
||||
int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
|
@ -756,15 +740,19 @@ int ath10k_ce_completed_send_next(struct ce_state *ce_state,
|
|||
void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ce_state *ce_state = ar_pci->ce_id_to_state[ce_id];
|
||||
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
|
||||
u32 ctrl_addr = ce_state->ctrl_addr;
|
||||
void *transfer_context;
|
||||
u32 buf;
|
||||
unsigned int nbytes;
|
||||
unsigned int id;
|
||||
unsigned int flags;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
spin_lock_bh(&ar_pci->ce_lock);
|
||||
|
||||
/* Clear the copy-complete interrupts that will be handled here. */
|
||||
|
@ -823,10 +811,13 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
|
|||
void ath10k_ce_per_engine_service_any(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ce_id;
|
||||
int ce_id, ret;
|
||||
u32 intr_summary;
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
intr_summary = CE_INTERRUPT_SUMMARY(ar);
|
||||
|
||||
for (ce_id = 0; intr_summary && (ce_id < ar_pci->ce_count); ce_id++) {
|
||||
|
@ -849,13 +840,16 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
|
|||
*
|
||||
* Called with ce_lock held.
|
||||
*/
|
||||
static void ath10k_ce_per_engine_handler_adjust(struct ce_state *ce_state,
|
||||
static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
|
||||
int disable_copy_compl_intr)
|
||||
{
|
||||
u32 ctrl_addr = ce_state->ctrl_addr;
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
int ret;
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
if ((!disable_copy_compl_intr) &&
|
||||
(ce_state->send_cb || ce_state->recv_cb))
|
||||
|
@ -871,11 +865,14 @@ static void ath10k_ce_per_engine_handler_adjust(struct ce_state *ce_state,
|
|||
void ath10k_ce_disable_interrupts(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
int ce_id;
|
||||
int ce_id, ret;
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
for (ce_id = 0; ce_id < ar_pci->ce_count; ce_id++) {
|
||||
struct ce_state *ce_state = ar_pci->ce_id_to_state[ce_id];
|
||||
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
|
||||
u32 ctrl_addr = ce_state->ctrl_addr;
|
||||
|
||||
ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
|
||||
|
@ -883,8 +880,8 @@ void ath10k_ce_disable_interrupts(struct ath10k *ar)
|
|||
ath10k_pci_sleep(ar);
|
||||
}
|
||||
|
||||
void ath10k_ce_send_cb_register(struct ce_state *ce_state,
|
||||
void (*send_cb) (struct ce_state *ce_state,
|
||||
void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
|
||||
void (*send_cb)(struct ath10k_ce_pipe *ce_state,
|
||||
void *transfer_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
|
@ -900,8 +897,8 @@ void ath10k_ce_send_cb_register(struct ce_state *ce_state,
|
|||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
}
|
||||
|
||||
void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
|
||||
void (*recv_cb) (struct ce_state *ce_state,
|
||||
void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
|
||||
void (*recv_cb)(struct ath10k_ce_pipe *ce_state,
|
||||
void *transfer_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
|
@ -919,11 +916,11 @@ void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
|
|||
|
||||
static int ath10k_ce_init_src_ring(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
struct ce_state *ce_state,
|
||||
struct ath10k_ce_pipe *ce_state,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ce_ring_state *src_ring;
|
||||
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);
|
||||
|
@ -937,19 +934,18 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
|
|||
return 0;
|
||||
}
|
||||
|
||||
ce_nbytes = sizeof(struct ce_ring_state) + (nentries * sizeof(void *));
|
||||
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 ce_ring_state *)ptr;
|
||||
ce_state->src_ring = (struct ath10k_ce_ring *)ptr;
|
||||
src_ring = ce_state->src_ring;
|
||||
|
||||
ptr += sizeof(struct ce_ring_state);
|
||||
ptr += sizeof(struct ath10k_ce_ring);
|
||||
src_ring->nentries = nentries;
|
||||
src_ring->nentries_mask = nentries - 1;
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
|
||||
src_ring->sw_index &= src_ring->nentries_mask;
|
||||
src_ring->hw_index = src_ring->sw_index;
|
||||
|
@ -957,7 +953,6 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
|
|||
src_ring->write_index =
|
||||
ath10k_ce_src_ring_write_index_get(ar, ctrl_addr);
|
||||
src_ring->write_index &= src_ring->nentries_mask;
|
||||
ath10k_pci_sleep(ar);
|
||||
|
||||
src_ring->per_transfer_context = (void **)ptr;
|
||||
|
||||
|
@ -970,6 +965,12 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
|
|||
(nentries * sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
&base_addr);
|
||||
if (!src_ring->base_addr_owner_space_unaligned) {
|
||||
kfree(ce_state->src_ring);
|
||||
ce_state->src_ring = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
src_ring->base_addr_ce_space_unaligned = base_addr;
|
||||
|
||||
src_ring->base_addr_owner_space = PTR_ALIGN(
|
||||
|
@ -986,12 +987,21 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
|
|||
src_ring->shadow_base_unaligned =
|
||||
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;
|
||||
}
|
||||
|
||||
src_ring->shadow_base = PTR_ALIGN(
|
||||
src_ring->shadow_base_unaligned,
|
||||
CE_DESC_RING_ALIGN);
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
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);
|
||||
|
@ -999,18 +1009,17 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
|
|||
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_pci_sleep(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_ce_init_dest_ring(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
struct ce_state *ce_state,
|
||||
struct ath10k_ce_pipe *ce_state,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ce_ring_state *dest_ring;
|
||||
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);
|
||||
|
@ -1024,25 +1033,23 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
|
|||
return 0;
|
||||
}
|
||||
|
||||
ce_nbytes = sizeof(struct ce_ring_state) + (nentries * sizeof(void *));
|
||||
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 ce_ring_state *)ptr;
|
||||
ce_state->dest_ring = (struct ath10k_ce_ring *)ptr;
|
||||
dest_ring = ce_state->dest_ring;
|
||||
|
||||
ptr += sizeof(struct ce_ring_state);
|
||||
ptr += sizeof(struct ath10k_ce_ring);
|
||||
dest_ring->nentries = nentries;
|
||||
dest_ring->nentries_mask = nentries - 1;
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
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_pci_sleep(ar);
|
||||
|
||||
dest_ring->per_transfer_context = (void **)ptr;
|
||||
|
||||
|
@ -1055,6 +1062,12 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
|
|||
(nentries * sizeof(struct ce_desc) +
|
||||
CE_DESC_RING_ALIGN),
|
||||
&base_addr);
|
||||
if (!dest_ring->base_addr_owner_space_unaligned) {
|
||||
kfree(ce_state->dest_ring);
|
||||
ce_state->dest_ring = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dest_ring->base_addr_ce_space_unaligned = base_addr;
|
||||
|
||||
/*
|
||||
|
@ -1071,44 +1084,31 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
|
|||
dest_ring->base_addr_ce_space_unaligned,
|
||||
CE_DESC_RING_ALIGN);
|
||||
|
||||
ath10k_pci_wake(ar);
|
||||
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_pci_sleep(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ce_state *ath10k_ce_init_state(struct ath10k *ar,
|
||||
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 ce_state *ce_state = NULL;
|
||||
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);
|
||||
|
||||
if (!ar_pci->ce_id_to_state[ce_id]) {
|
||||
ce_state = kzalloc(sizeof(*ce_state), GFP_ATOMIC);
|
||||
if (ce_state == NULL) {
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ar_pci->ce_id_to_state[ce_id] = ce_state;
|
||||
ce_state->ar = ar;
|
||||
ce_state->id = ce_id;
|
||||
ce_state->ctrl_addr = ctrl_addr;
|
||||
ce_state->state = CE_RUNNING;
|
||||
/* Save attribute flags */
|
||||
ce_state->attr_flags = attr->flags;
|
||||
ce_state->src_sz_max = attr->src_sz_max;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&ar_pci->ce_lock);
|
||||
|
||||
|
@ -1122,12 +1122,17 @@ static struct ce_state *ath10k_ce_init_state(struct ath10k *ar,
|
|||
* initialization. It may be that only one side or the other is
|
||||
* initialized by software/firmware.
|
||||
*/
|
||||
struct ce_state *ath10k_ce_init(struct ath10k *ar,
|
||||
struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
const struct ce_attr *attr)
|
||||
{
|
||||
struct ce_state *ce_state;
|
||||
struct ath10k_ce_pipe *ce_state;
|
||||
u32 ctrl_addr = ath10k_ce_base_address(ce_id);
|
||||
int ret;
|
||||
|
||||
ret = ath10k_pci_wake(ar);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
ce_state = ath10k_ce_init_state(ar, ce_id, attr);
|
||||
if (!ce_state) {
|
||||
|
@ -1136,40 +1141,38 @@ struct ce_state *ath10k_ce_init(struct ath10k *ar,
|
|||
}
|
||||
|
||||
if (attr->src_nentries) {
|
||||
if (ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr)) {
|
||||
ath10k_err("Failed to initialize CE src ring for ID: %d\n",
|
||||
ce_id);
|
||||
ret = ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr);
|
||||
if (ret) {
|
||||
ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
|
||||
ce_id, ret);
|
||||
ath10k_ce_deinit(ce_state);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr->dest_nentries) {
|
||||
if (ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr)) {
|
||||
ath10k_err("Failed to initialize CE dest ring for ID: %d\n",
|
||||
ce_id);
|
||||
ret = ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr);
|
||||
if (ret) {
|
||||
ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
|
||||
ce_id, ret);
|
||||
ath10k_ce_deinit(ce_state);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable CE error interrupts */
|
||||
ath10k_pci_wake(ar);
|
||||
ath10k_ce_error_intr_enable(ar, ctrl_addr);
|
||||
|
||||
ath10k_pci_sleep(ar);
|
||||
|
||||
return ce_state;
|
||||
}
|
||||
|
||||
void ath10k_ce_deinit(struct ce_state *ce_state)
|
||||
void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state)
|
||||
{
|
||||
unsigned int ce_id = ce_state->id;
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
ce_state->state = CE_UNUSED;
|
||||
ar_pci->ce_id_to_state[ce_id] = NULL;
|
||||
|
||||
if (ce_state->src_ring) {
|
||||
kfree(ce_state->src_ring->shadow_base_unaligned);
|
||||
pci_free_consistent(ar_pci->pdev,
|
||||
|
@ -1190,5 +1193,7 @@ void ath10k_ce_deinit(struct ce_state *ce_state)
|
|||
ce_state->dest_ring->base_addr_ce_space);
|
||||
kfree(ce_state->dest_ring);
|
||||
}
|
||||
kfree(ce_state);
|
||||
|
||||
ce_state->src_ring = NULL;
|
||||
ce_state->dest_ring = NULL;
|
||||
}
|
||||
|
|
|
@ -36,16 +36,9 @@
|
|||
* how to use copy engines.
|
||||
*/
|
||||
|
||||
struct ce_state;
|
||||
struct ath10k_ce_pipe;
|
||||
|
||||
|
||||
/* Copy Engine operational state */
|
||||
enum ce_op_state {
|
||||
CE_UNUSED,
|
||||
CE_PAUSED,
|
||||
CE_RUNNING,
|
||||
};
|
||||
|
||||
#define CE_DESC_FLAGS_GATHER (1 << 0)
|
||||
#define CE_DESC_FLAGS_BYTE_SWAP (1 << 1)
|
||||
#define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC
|
||||
|
@ -57,8 +50,7 @@ struct ce_desc {
|
|||
__le16 flags; /* %CE_DESC_FLAGS_ */
|
||||
};
|
||||
|
||||
/* Copy Engine Ring internal state */
|
||||
struct ce_ring_state {
|
||||
struct ath10k_ce_ring {
|
||||
/* Number of entries in this ring; must be power of 2 */
|
||||
unsigned int nentries;
|
||||
unsigned int nentries_mask;
|
||||
|
@ -116,22 +108,20 @@ struct ce_ring_state {
|
|||
void **per_transfer_context;
|
||||
};
|
||||
|
||||
/* Copy Engine internal state */
|
||||
struct ce_state {
|
||||
struct ath10k_ce_pipe {
|
||||
struct ath10k *ar;
|
||||
unsigned int id;
|
||||
|
||||
unsigned int attr_flags;
|
||||
|
||||
u32 ctrl_addr;
|
||||
enum ce_op_state state;
|
||||
|
||||
void (*send_cb) (struct ce_state *ce_state,
|
||||
void (*send_cb) (struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_send_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
unsigned int transfer_id);
|
||||
void (*recv_cb) (struct ce_state *ce_state,
|
||||
void (*recv_cb) (struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_recv_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
|
@ -139,8 +129,8 @@ struct ce_state {
|
|||
unsigned int flags);
|
||||
|
||||
unsigned int src_sz_max;
|
||||
struct ce_ring_state *src_ring;
|
||||
struct ce_ring_state *dest_ring;
|
||||
struct ath10k_ce_ring *src_ring;
|
||||
struct ath10k_ce_ring *dest_ring;
|
||||
};
|
||||
|
||||
struct ce_sendlist_item {
|
||||
|
@ -182,7 +172,7 @@ struct ce_attr;
|
|||
*
|
||||
* Implementation note: pushes 1 buffer to Source ring
|
||||
*/
|
||||
int ath10k_ce_send(struct ce_state *ce_state,
|
||||
int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_send_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
|
@ -190,8 +180,8 @@ int ath10k_ce_send(struct ce_state *ce_state,
|
|||
unsigned int transfer_id,
|
||||
unsigned int flags);
|
||||
|
||||
void ath10k_ce_send_cb_register(struct ce_state *ce_state,
|
||||
void (*send_cb) (struct ce_state *ce_state,
|
||||
void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
|
||||
void (*send_cb)(struct ath10k_ce_pipe *ce_state,
|
||||
void *transfer_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
|
@ -215,7 +205,7 @@ void ath10k_ce_sendlist_buf_add(struct ce_sendlist *sendlist,
|
|||
*
|
||||
* Implemenation note: Pushes multiple buffers with Gather to Source ring.
|
||||
*/
|
||||
int ath10k_ce_sendlist_send(struct ce_state *ce_state,
|
||||
int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_send_context,
|
||||
struct ce_sendlist *sendlist,
|
||||
/* 14 bits */
|
||||
|
@ -233,12 +223,12 @@ int ath10k_ce_sendlist_send(struct ce_state *ce_state,
|
|||
*
|
||||
* Implemenation note: Pushes a buffer to Dest ring.
|
||||
*/
|
||||
int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
|
||||
int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_recv_context,
|
||||
u32 buffer);
|
||||
|
||||
void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
|
||||
void (*recv_cb) (struct ce_state *ce_state,
|
||||
void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
|
||||
void (*recv_cb)(struct ath10k_ce_pipe *ce_state,
|
||||
void *transfer_context,
|
||||
u32 buffer,
|
||||
unsigned int nbytes,
|
||||
|
@ -253,7 +243,7 @@ void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
|
|||
* Supply data for the next completed unprocessed receive descriptor.
|
||||
* Pops buffer from Dest ring.
|
||||
*/
|
||||
int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
|
||||
int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
|
@ -263,7 +253,7 @@ int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
|
|||
* Supply data for the next completed unprocessed send descriptor.
|
||||
* Pops 1 completed send buffer from Source ring.
|
||||
*/
|
||||
int ath10k_ce_completed_send_next(struct ce_state *ce_state,
|
||||
int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
|
@ -272,7 +262,7 @@ int ath10k_ce_completed_send_next(struct ce_state *ce_state,
|
|||
/*==================CE Engine Initialization=======================*/
|
||||
|
||||
/* Initialize an instance of a CE */
|
||||
struct ce_state *ath10k_ce_init(struct ath10k *ar,
|
||||
struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
|
||||
unsigned int ce_id,
|
||||
const struct ce_attr *attr);
|
||||
|
||||
|
@ -282,7 +272,7 @@ struct ce_state *ath10k_ce_init(struct ath10k *ar,
|
|||
* receive buffers. Target DMA must be stopped before using
|
||||
* this API.
|
||||
*/
|
||||
int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
|
||||
int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp);
|
||||
|
||||
|
@ -291,13 +281,13 @@ int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
|
|||
* pending sends. Target DMA must be stopped before using
|
||||
* this API.
|
||||
*/
|
||||
int ath10k_ce_cancel_send_next(struct ce_state *ce_state,
|
||||
int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp);
|
||||
|
||||
void ath10k_ce_deinit(struct ce_state *ce_state);
|
||||
void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state);
|
||||
|
||||
/*==================CE Interrupt Handlers====================*/
|
||||
void ath10k_ce_per_engine_service_any(struct ath10k *ar);
|
||||
|
@ -322,9 +312,6 @@ struct ce_attr {
|
|||
/* CE_ATTR_* values */
|
||||
unsigned int flags;
|
||||
|
||||
/* currently not in use */
|
||||
unsigned int priority;
|
||||
|
||||
/* #entries in source ring - Must be a power of 2 */
|
||||
unsigned int src_nentries;
|
||||
|
||||
|
@ -336,9 +323,6 @@ struct ce_attr {
|
|||
|
||||
/* #entries in destination ring - Must be a power of 2 */
|
||||
unsigned int dest_nentries;
|
||||
|
||||
/* Future use */
|
||||
void *reserved;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -38,17 +38,6 @@ MODULE_PARM_DESC(uart_print, "Uart target debugging");
|
|||
MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");
|
||||
|
||||
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||
{
|
||||
.id = QCA988X_HW_1_0_VERSION,
|
||||
.name = "qca988x hw1.0",
|
||||
.patch_load_addr = QCA988X_HW_1_0_PATCH_LOAD_ADDR,
|
||||
.fw = {
|
||||
.dir = QCA988X_HW_1_0_FW_DIR,
|
||||
.fw = QCA988X_HW_1_0_FW_FILE,
|
||||
.otp = QCA988X_HW_1_0_OTP_FILE,
|
||||
.board = QCA988X_HW_1_0_BOARD_DATA_FILE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.id = QCA988X_HW_2_0_VERSION,
|
||||
.name = "qca988x hw2.0",
|
||||
|
@ -717,10 +706,43 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_core_register(struct ath10k *ar)
|
||||
static int ath10k_core_check_chip_id(struct ath10k *ar)
|
||||
{
|
||||
u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
|
||||
|
||||
/* Check that we are not using hw1.0 (some of them have same pci id
|
||||
* as hw2.0) before doing anything else as ath10k crashes horribly
|
||||
* due to missing hw1.0 workarounds. */
|
||||
switch (hw_revision) {
|
||||
case QCA988X_HW_1_0_CHIP_ID_REV:
|
||||
ath10k_err("ERROR: qca988x hw1.0 is not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
case QCA988X_HW_2_0_CHIP_ID_REV:
|
||||
/* known hardware revision, continue normally */
|
||||
return 0;
|
||||
|
||||
default:
|
||||
ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n",
|
||||
ar->chip_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
status = ath10k_core_probe_fw(ar);
|
||||
if (status) {
|
||||
ath10k_err("could not probe fw (%d)\n", status);
|
||||
|
|
|
@ -270,12 +270,21 @@ enum ath10k_state {
|
|||
ATH10K_STATE_WEDGED,
|
||||
};
|
||||
|
||||
enum ath10k_fw_features {
|
||||
/* wmi_mgmt_rx_hdr contains extra RSSI information */
|
||||
ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_FW_FEATURE_COUNT,
|
||||
};
|
||||
|
||||
struct ath10k {
|
||||
struct ath_common ath_common;
|
||||
struct ieee80211_hw *hw;
|
||||
struct device *dev;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
|
||||
u32 chip_id;
|
||||
u32 target_version;
|
||||
u8 fw_version_major;
|
||||
u32 fw_version_minor;
|
||||
|
@ -288,6 +297,8 @@ struct ath10k {
|
|||
u32 vht_cap_info;
|
||||
u32 num_rf_chains;
|
||||
|
||||
DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
|
||||
|
||||
struct targetdef *targetdef;
|
||||
struct hostdef *hostdef;
|
||||
|
||||
|
@ -393,7 +404,7 @@ void ath10k_core_destroy(struct ath10k *ar);
|
|||
|
||||
int ath10k_core_start(struct ath10k *ar);
|
||||
void ath10k_core_stop(struct ath10k *ar);
|
||||
int ath10k_core_register(struct ath10k *ar);
|
||||
int ath10k_core_register(struct ath10k *ar, u32 chip_id);
|
||||
void ath10k_core_unregister(struct ath10k *ar);
|
||||
|
||||
#endif /* _CORE_H_ */
|
||||
|
|
|
@ -260,7 +260,6 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
|
|||
}
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
complete(&ar->debug.event_stats_compl);
|
||||
}
|
||||
|
||||
|
@ -499,6 +498,25 @@ static const struct file_operations fops_simulate_fw_crash = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
unsigned int len;
|
||||
char buf[50];
|
||||
|
||||
len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_chip_id = {
|
||||
.read = ath10k_read_chip_id,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
int ath10k_debug_create(struct ath10k *ar)
|
||||
{
|
||||
ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
|
||||
|
@ -518,6 +536,9 @@ int ath10k_debug_create(struct ath10k *ar)
|
|||
debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
|
||||
ar, &fops_simulate_fw_crash);
|
||||
|
||||
debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
|
||||
ar, &fops_chip_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ATH10K_DEBUGFS */
|
||||
|
|
|
@ -772,16 +772,16 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
|
|||
|
||||
flags |= SM(tx_alloc, ATH10K_HTC_CONN_FLAGS_RECV_ALLOC);
|
||||
|
||||
req_msg = &msg->connect_service;
|
||||
req_msg->flags = __cpu_to_le16(flags);
|
||||
req_msg->service_id = __cpu_to_le16(conn_req->service_id);
|
||||
|
||||
/* Only enable credit flow control for WMI ctrl service */
|
||||
if (conn_req->service_id != ATH10K_HTC_SVC_ID_WMI_CONTROL) {
|
||||
flags |= ATH10K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
|
||||
disable_credit_flow_ctrl = true;
|
||||
}
|
||||
|
||||
req_msg = &msg->connect_service;
|
||||
req_msg->flags = __cpu_to_le16(flags);
|
||||
req_msg->service_id = __cpu_to_le16(conn_req->service_id);
|
||||
|
||||
INIT_COMPLETION(htc->ctl_resp);
|
||||
|
||||
status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
|
||||
|
|
|
@ -104,21 +104,16 @@ int ath10k_htt_attach(struct ath10k *ar)
|
|||
|
||||
static int ath10k_htt_verify_version(struct ath10k_htt *htt)
|
||||
{
|
||||
ath10k_dbg(ATH10K_DBG_HTT,
|
||||
"htt target version %d.%d; host version %d.%d\n",
|
||||
htt->target_version_major,
|
||||
htt->target_version_minor,
|
||||
HTT_CURRENT_VERSION_MAJOR,
|
||||
HTT_CURRENT_VERSION_MINOR);
|
||||
ath10k_info("htt target version %d.%d\n",
|
||||
htt->target_version_major, htt->target_version_minor);
|
||||
|
||||
if (htt->target_version_major != HTT_CURRENT_VERSION_MAJOR) {
|
||||
ath10k_err("htt major versions are incompatible!\n");
|
||||
if (htt->target_version_major != 2 &&
|
||||
htt->target_version_major != 3) {
|
||||
ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n",
|
||||
htt->target_version_major);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (htt->target_version_minor != HTT_CURRENT_VERSION_MINOR)
|
||||
ath10k_warn("htt minor version differ but still compatible\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
#include "htc.h"
|
||||
#include "rx_desc.h"
|
||||
|
||||
#define HTT_CURRENT_VERSION_MAJOR 2
|
||||
#define HTT_CURRENT_VERSION_MINOR 1
|
||||
|
||||
enum htt_dbg_stats_type {
|
||||
HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0,
|
||||
HTT_DBG_STATS_RX_REORDER = 1 << 1,
|
||||
|
@ -45,6 +42,9 @@ enum htt_h2t_msg_type { /* host-to-target */
|
|||
HTT_H2T_MSG_TYPE_SYNC = 4,
|
||||
HTT_H2T_MSG_TYPE_AGGR_CFG = 5,
|
||||
HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 6,
|
||||
|
||||
/* This command is used for sending management frames in HTT < 3.0.
|
||||
* HTT >= 3.0 uses TX_FRM for everything. */
|
||||
HTT_H2T_MSG_TYPE_MGMT_TX = 7,
|
||||
|
||||
HTT_H2T_NUM_MSGS /* keep this last */
|
||||
|
|
|
@ -610,8 +610,7 @@ static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
|
|||
RX_MPDU_START_INFO0_ENCRYPT_TYPE);
|
||||
|
||||
/* FIXME: No idea what assumptions are safe here. Need logs */
|
||||
if ((fmt == RX_MSDU_DECAP_RAW && skb->next) ||
|
||||
(fmt == RX_MSDU_DECAP_8023_SNAP_LLC)) {
|
||||
if ((fmt == RX_MSDU_DECAP_RAW && skb->next)) {
|
||||
ath10k_htt_rx_free_msdu_chain(skb->next);
|
||||
skb->next = NULL;
|
||||
return -ENOTSUPP;
|
||||
|
@ -659,6 +658,15 @@ static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
|
|||
decap_hdr += roundup(crypto_len, 4);
|
||||
}
|
||||
|
||||
/* When fmt == RX_MSDU_DECAP_8023_SNAP_LLC:
|
||||
*
|
||||
* SNAP 802.3 consists of:
|
||||
* [dst:6][src:6][len:2][dsap:1][ssap:1][ctl:1][snap:5]
|
||||
* [data][fcs:4].
|
||||
*
|
||||
* Since this overlaps with A-MSDU header (da, sa, len)
|
||||
* there's nothing extra to do. */
|
||||
|
||||
if (fmt == RX_MSDU_DECAP_ETHERNET2_DIX) {
|
||||
/* Ethernet2 decap inserts ethernet header in place of
|
||||
* A-MSDU subframe header. */
|
||||
|
|
|
@ -401,11 +401,17 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* Since HTT 3.0 there is no separate mgmt tx command. However in case
|
||||
* of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
|
||||
* fragment list host driver specifies directly frame pointer. */
|
||||
if (htt->target_version_major < 3 ||
|
||||
!ieee80211_is_mgmt(hdr->frame_control)) {
|
||||
txfrag = dev_alloc_skb(frag_len);
|
||||
if (!txfrag) {
|
||||
res = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) {
|
||||
ath10k_warn("htt alignment check failed. dropping packet.\n");
|
||||
|
@ -427,6 +433,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
|||
if (res)
|
||||
goto err;
|
||||
|
||||
/* Since HTT 3.0 there is no separate mgmt tx command. However in case
|
||||
* of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
|
||||
* fragment list host driver specifies directly frame pointer. */
|
||||
if (htt->target_version_major < 3 ||
|
||||
!ieee80211_is_mgmt(hdr->frame_control)) {
|
||||
/* tx fragment list must be terminated with zero-entry */
|
||||
skb_put(txfrag, frag_len);
|
||||
tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data;
|
||||
|
@ -439,11 +450,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
|||
if (res)
|
||||
goto err;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx msdu 0x%llx\n",
|
||||
(unsigned long long) ATH10K_SKB_CB(txfrag)->paddr,
|
||||
(unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx\n",
|
||||
(unsigned long long) ATH10K_SKB_CB(txfrag)->paddr);
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ",
|
||||
txfrag->data, frag_len);
|
||||
}
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n",
|
||||
(unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
|
||||
ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ",
|
||||
msdu->data, msdu->len);
|
||||
|
||||
|
@ -459,6 +473,15 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
|||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
|
||||
flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
|
||||
|
||||
/* Since HTT 3.0 there is no separate mgmt tx command. However in case
|
||||
* of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
|
||||
* fragment list host driver specifies directly frame pointer. */
|
||||
if (htt->target_version_major >= 3 &&
|
||||
ieee80211_is_mgmt(hdr->frame_control))
|
||||
flags0 |= SM(ATH10K_HW_TXRX_MGMT,
|
||||
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
|
||||
else
|
||||
flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
|
||||
HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
|
||||
|
||||
|
@ -468,6 +491,13 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
|
|||
flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
|
||||
flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
|
||||
|
||||
/* Since HTT 3.0 there is no separate mgmt tx command. However in case
|
||||
* of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
|
||||
* fragment list host driver specifies directly frame pointer. */
|
||||
if (htt->target_version_major >= 3 &&
|
||||
ieee80211_is_mgmt(hdr->frame_control))
|
||||
frags_paddr = ATH10K_SKB_CB(msdu)->paddr;
|
||||
else
|
||||
frags_paddr = ATH10K_SKB_CB(txfrag)->paddr;
|
||||
|
||||
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
|
||||
|
|
|
@ -24,18 +24,14 @@
|
|||
#define SUPPORTED_FW_MAJOR 1
|
||||
#define SUPPORTED_FW_MINOR 0
|
||||
#define SUPPORTED_FW_RELEASE 0
|
||||
#define SUPPORTED_FW_BUILD 629
|
||||
#define SUPPORTED_FW_BUILD 636
|
||||
|
||||
/* QCA988X 1.0 definitions */
|
||||
#define QCA988X_HW_1_0_VERSION 0x4000002c
|
||||
#define QCA988X_HW_1_0_FW_DIR "ath10k/QCA988X/hw1.0"
|
||||
#define QCA988X_HW_1_0_FW_FILE "firmware.bin"
|
||||
#define QCA988X_HW_1_0_OTP_FILE "otp.bin"
|
||||
#define QCA988X_HW_1_0_BOARD_DATA_FILE "board.bin"
|
||||
#define QCA988X_HW_1_0_PATCH_LOAD_ADDR 0x1234
|
||||
/* QCA988X 1.0 definitions (unsupported) */
|
||||
#define QCA988X_HW_1_0_CHIP_ID_REV 0x0
|
||||
|
||||
/* QCA988X 2.0 definitions */
|
||||
#define QCA988X_HW_2_0_VERSION 0x4100016c
|
||||
#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_OTP_FILE "otp.bin"
|
||||
|
@ -53,6 +49,9 @@ enum ath10k_hw_txrx_mode {
|
|||
ATH10K_HW_TXRX_RAW = 0,
|
||||
ATH10K_HW_TXRX_NATIVE_WIFI = 1,
|
||||
ATH10K_HW_TXRX_ETHERNET = 2,
|
||||
|
||||
/* Valid for HTT >= 3.0. Used for management frames in TX_FRM. */
|
||||
ATH10K_HW_TXRX_MGMT = 3,
|
||||
};
|
||||
|
||||
enum ath10k_mcast2ucast_mode {
|
||||
|
@ -169,6 +168,10 @@ enum ath10k_mcast2ucast_mode {
|
|||
#define SOC_LPO_CAL_ENABLE_LSB 20
|
||||
#define SOC_LPO_CAL_ENABLE_MASK 0x00100000
|
||||
|
||||
#define SOC_CHIP_ID_ADDRESS 0x000000ec
|
||||
#define SOC_CHIP_ID_REV_LSB 8
|
||||
#define SOC_CHIP_ID_REV_MASK 0x00000f00
|
||||
|
||||
#define WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008
|
||||
#define WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004
|
||||
#define WLAN_SYSTEM_SLEEP_DISABLE_LSB 0
|
||||
|
|
|
@ -503,13 +503,10 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
|
|||
{
|
||||
struct ieee80211_channel *channel = ar->hw->conf.chandef.chan;
|
||||
struct wmi_vdev_start_request_arg arg = {};
|
||||
enum nl80211_channel_type type;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
type = cfg80211_get_chandef_type(&ar->hw->conf.chandef);
|
||||
|
||||
arg.vdev_id = vdev_id;
|
||||
arg.channel.freq = channel->center_freq;
|
||||
arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1;
|
||||
|
@ -973,7 +970,7 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
|
|||
sta->uapsd_queues, sta->max_sp);
|
||||
|
||||
arg->peer_flags |= WMI_PEER_APSD;
|
||||
arg->peer_flags |= WMI_RC_UAPSD_FLAG;
|
||||
arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
|
||||
|
||||
if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
|
||||
uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
|
||||
|
@ -1421,10 +1418,6 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
|||
struct ieee80211_key_conf *key = info->control.hw_key;
|
||||
int ret;
|
||||
|
||||
/* TODO AP mode should be implemented */
|
||||
if (vif->type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
if (!ieee80211_has_protected(hdr->frame_control))
|
||||
return;
|
||||
|
||||
|
@ -1480,6 +1473,12 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
|
|||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
int ret;
|
||||
|
||||
if (ar->htt.target_version_major >= 3) {
|
||||
/* Since HTT 3.0 there is no separate mgmt tx command */
|
||||
ret = ath10k_htt_tx(&ar->htt, skb);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ieee80211_is_mgmt(hdr->frame_control))
|
||||
ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
|
||||
else if (ieee80211_is_nullfunc(hdr->frame_control))
|
||||
|
@ -1491,6 +1490,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
|
|||
else
|
||||
ret = ath10k_htt_tx(&ar->htt, skb);
|
||||
|
||||
exit:
|
||||
if (ret) {
|
||||
ath10k_warn("tx failed (%d). dropping packet.\n", ret);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
|
@ -1727,7 +1727,9 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
|||
/* we must calculate tid before we apply qos workaround
|
||||
* as we'd lose the qos control field */
|
||||
tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
||||
if (ieee80211_is_data_qos(hdr->frame_control) &&
|
||||
if (ieee80211_is_mgmt(hdr->frame_control)) {
|
||||
tid = HTT_DATA_TX_EXT_TID_MGMT;
|
||||
} else if (ieee80211_is_data_qos(hdr->frame_control) &&
|
||||
is_unicast_ether_addr(ieee80211_get_DA(hdr))) {
|
||||
u8 *qc = ieee80211_get_qos_ctl(hdr);
|
||||
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
|
|
@ -36,11 +36,9 @@ static unsigned int ath10k_target_ps;
|
|||
module_param(ath10k_target_ps, uint, 0644);
|
||||
MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option");
|
||||
|
||||
#define QCA988X_1_0_DEVICE_ID (0xabcd)
|
||||
#define QCA988X_2_0_DEVICE_ID (0x003c)
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {
|
||||
{ PCI_VDEVICE(ATHEROS, QCA988X_1_0_DEVICE_ID) }, /* PCI-E QCA988X V1 */
|
||||
{ PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
|
||||
{0}
|
||||
};
|
||||
|
@ -50,9 +48,9 @@ static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
|
|||
|
||||
static void ath10k_pci_process_ce(struct ath10k *ar);
|
||||
static int ath10k_pci_post_rx(struct ath10k *ar);
|
||||
static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,
|
||||
static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
|
||||
int num);
|
||||
static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info);
|
||||
static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
|
||||
static void ath10k_pci_stop_ce(struct ath10k *ar);
|
||||
static void ath10k_pci_device_reset(struct ath10k *ar);
|
||||
static int ath10k_pci_reset_target(struct ath10k *ar);
|
||||
|
@ -60,43 +58,145 @@ static int ath10k_pci_start_intr(struct ath10k *ar);
|
|||
static void ath10k_pci_stop_intr(struct ath10k *ar);
|
||||
|
||||
static const struct ce_attr host_ce_config_wlan[] = {
|
||||
/* host->target HTC control and raw streams */
|
||||
{ /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,},
|
||||
/* could be moved to share CE3 */
|
||||
/* target->host HTT + HTC control */
|
||||
{ /* CE1 */ CE_ATTR_FLAGS, 0, 0, 512, 512, NULL,},
|
||||
/* target->host WMI */
|
||||
{ /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 32, NULL,},
|
||||
/* host->target WMI */
|
||||
{ /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL,},
|
||||
/* host->target HTT */
|
||||
{ /* CE4 */ CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 0,
|
||||
CE_HTT_H2T_MSG_SRC_NENTRIES, 256, 0, NULL,},
|
||||
/* unused */
|
||||
{ /* CE5 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,},
|
||||
/* Target autonomous hif_memcpy */
|
||||
{ /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,},
|
||||
/* ce_diag, the Diagnostic Window */
|
||||
{ /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,},
|
||||
/* CE0: host->target HTC control and raw streams */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.src_nentries = 16,
|
||||
.src_sz_max = 256,
|
||||
.dest_nentries = 0,
|
||||
},
|
||||
|
||||
/* CE1: target->host HTT + HTC control */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.src_nentries = 0,
|
||||
.src_sz_max = 512,
|
||||
.dest_nentries = 512,
|
||||
},
|
||||
|
||||
/* CE2: target->host WMI */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.src_nentries = 0,
|
||||
.src_sz_max = 2048,
|
||||
.dest_nentries = 32,
|
||||
},
|
||||
|
||||
/* CE3: host->target WMI */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.src_nentries = 32,
|
||||
.src_sz_max = 2048,
|
||||
.dest_nentries = 0,
|
||||
},
|
||||
|
||||
/* CE4: host->target HTT */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
|
||||
.src_nentries = CE_HTT_H2T_MSG_SRC_NENTRIES,
|
||||
.src_sz_max = 256,
|
||||
.dest_nentries = 0,
|
||||
},
|
||||
|
||||
/* CE5: unused */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.src_nentries = 0,
|
||||
.src_sz_max = 0,
|
||||
.dest_nentries = 0,
|
||||
},
|
||||
|
||||
/* CE6: target autonomous hif_memcpy */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.src_nentries = 0,
|
||||
.src_sz_max = 0,
|
||||
.dest_nentries = 0,
|
||||
},
|
||||
|
||||
/* CE7: ce_diag, the Diagnostic Window */
|
||||
{
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.src_nentries = 2,
|
||||
.src_sz_max = DIAG_TRANSFER_LIMIT,
|
||||
.dest_nentries = 2,
|
||||
},
|
||||
};
|
||||
|
||||
/* Target firmware's Copy Engine configuration. */
|
||||
static const struct ce_pipe_config target_ce_config_wlan[] = {
|
||||
/* host->target HTC control and raw streams */
|
||||
{ /* CE0 */ 0, PIPEDIR_OUT, 32, 256, CE_ATTR_FLAGS, 0,},
|
||||
/* target->host HTT + HTC control */
|
||||
{ /* CE1 */ 1, PIPEDIR_IN, 32, 512, CE_ATTR_FLAGS, 0,},
|
||||
/* target->host WMI */
|
||||
{ /* CE2 */ 2, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,},
|
||||
/* host->target WMI */
|
||||
{ /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,},
|
||||
/* host->target HTT */
|
||||
{ /* CE4 */ 4, PIPEDIR_OUT, 256, 256, CE_ATTR_FLAGS, 0,},
|
||||
/* CE0: host->target HTC control and raw streams */
|
||||
{
|
||||
.pipenum = 0,
|
||||
.pipedir = PIPEDIR_OUT,
|
||||
.nentries = 32,
|
||||
.nbytes_max = 256,
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.reserved = 0,
|
||||
},
|
||||
|
||||
/* CE1: target->host HTT + HTC control */
|
||||
{
|
||||
.pipenum = 1,
|
||||
.pipedir = PIPEDIR_IN,
|
||||
.nentries = 32,
|
||||
.nbytes_max = 512,
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.reserved = 0,
|
||||
},
|
||||
|
||||
/* CE2: target->host WMI */
|
||||
{
|
||||
.pipenum = 2,
|
||||
.pipedir = PIPEDIR_IN,
|
||||
.nentries = 32,
|
||||
.nbytes_max = 2048,
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.reserved = 0,
|
||||
},
|
||||
|
||||
/* CE3: host->target WMI */
|
||||
{
|
||||
.pipenum = 3,
|
||||
.pipedir = PIPEDIR_OUT,
|
||||
.nentries = 32,
|
||||
.nbytes_max = 2048,
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.reserved = 0,
|
||||
},
|
||||
|
||||
/* CE4: host->target HTT */
|
||||
{
|
||||
.pipenum = 4,
|
||||
.pipedir = PIPEDIR_OUT,
|
||||
.nentries = 256,
|
||||
.nbytes_max = 256,
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.reserved = 0,
|
||||
},
|
||||
|
||||
/* NB: 50% of src nentries, since tx has 2 frags */
|
||||
/* unused */
|
||||
{ /* CE5 */ 5, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,},
|
||||
/* Reserved for target autonomous hif_memcpy */
|
||||
{ /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0,},
|
||||
|
||||
/* CE5: unused */
|
||||
{
|
||||
.pipenum = 5,
|
||||
.pipedir = PIPEDIR_OUT,
|
||||
.nentries = 32,
|
||||
.nbytes_max = 2048,
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.reserved = 0,
|
||||
},
|
||||
|
||||
/* CE6: Reserved for target autonomous hif_memcpy */
|
||||
{
|
||||
.pipenum = 6,
|
||||
.pipedir = PIPEDIR_INOUT,
|
||||
.nentries = 32,
|
||||
.nbytes_max = 4096,
|
||||
.flags = CE_ATTR_FLAGS,
|
||||
.reserved = 0,
|
||||
},
|
||||
|
||||
/* CE7 used only by Host */
|
||||
};
|
||||
|
||||
|
@ -114,7 +214,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
|
|||
unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
|
||||
unsigned int id;
|
||||
unsigned int flags;
|
||||
struct ce_state *ce_diag;
|
||||
struct ath10k_ce_pipe *ce_diag;
|
||||
/* Host buffer address in CE space */
|
||||
u32 ce_data;
|
||||
dma_addr_t ce_data_base = 0;
|
||||
|
@ -278,7 +378,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
|||
unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
|
||||
unsigned int id;
|
||||
unsigned int flags;
|
||||
struct ce_state *ce_diag;
|
||||
struct ath10k_ce_pipe *ce_diag;
|
||||
void *data_buf = NULL;
|
||||
u32 ce_data; /* Host buffer address in CE space */
|
||||
dma_addr_t ce_data_base = 0;
|
||||
|
@ -437,7 +537,7 @@ static void ath10k_pci_wait(struct ath10k *ar)
|
|||
ath10k_warn("Unable to wakeup target\n");
|
||||
}
|
||||
|
||||
void ath10k_do_pci_wake(struct ath10k *ar)
|
||||
int ath10k_do_pci_wake(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
void __iomem *pci_addr = ar_pci->mem;
|
||||
|
@ -453,18 +553,19 @@ void ath10k_do_pci_wake(struct ath10k *ar)
|
|||
atomic_inc(&ar_pci->keep_awake_count);
|
||||
|
||||
if (ar_pci->verified_awake)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
for (;;) {
|
||||
if (ath10k_pci_target_is_awake(ar)) {
|
||||
ar_pci->verified_awake = true;
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tot_delay > PCIE_WAKE_TIMEOUT) {
|
||||
ath10k_warn("target takes too long to wake up (awake count %d)\n",
|
||||
ath10k_warn("target took longer %d us to wake up (awake count %d)\n",
|
||||
PCIE_WAKE_TIMEOUT,
|
||||
atomic_read(&ar_pci->keep_awake_count));
|
||||
break;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
udelay(curr_delay);
|
||||
|
@ -493,7 +594,7 @@ void ath10k_do_pci_sleep(struct ath10k *ar)
|
|||
* FIXME: Handle OOM properly.
|
||||
*/
|
||||
static inline
|
||||
struct ath10k_pci_compl *get_free_compl(struct hif_ce_pipe_info *pipe_info)
|
||||
struct ath10k_pci_compl *get_free_compl(struct ath10k_pci_pipe *pipe_info)
|
||||
{
|
||||
struct ath10k_pci_compl *compl = NULL;
|
||||
|
||||
|
@ -511,7 +612,7 @@ struct ath10k_pci_compl *get_free_compl(struct hif_ce_pipe_info *pipe_info)
|
|||
}
|
||||
|
||||
/* Called by lower (CE) layer when a send to Target completes. */
|
||||
static void ath10k_pci_ce_send_done(struct ce_state *ce_state,
|
||||
static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state,
|
||||
void *transfer_context,
|
||||
u32 ce_data,
|
||||
unsigned int nbytes,
|
||||
|
@ -519,7 +620,7 @@ static void ath10k_pci_ce_send_done(struct ce_state *ce_state,
|
|||
{
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct hif_ce_pipe_info *pipe_info = &ar_pci->pipe_info[ce_state->id];
|
||||
struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id];
|
||||
struct ath10k_pci_compl *compl;
|
||||
bool process = false;
|
||||
|
||||
|
@ -540,10 +641,10 @@ static void ath10k_pci_ce_send_done(struct ce_state *ce_state,
|
|||
if (!compl)
|
||||
break;
|
||||
|
||||
compl->send_or_recv = HIF_CE_COMPLETE_SEND;
|
||||
compl->state = ATH10K_PCI_COMPL_SEND;
|
||||
compl->ce_state = ce_state;
|
||||
compl->pipe_info = pipe_info;
|
||||
compl->transfer_context = transfer_context;
|
||||
compl->skb = transfer_context;
|
||||
compl->nbytes = nbytes;
|
||||
compl->transfer_id = transfer_id;
|
||||
compl->flags = 0;
|
||||
|
@ -573,7 +674,7 @@ static void ath10k_pci_ce_send_done(struct ce_state *ce_state,
|
|||
}
|
||||
|
||||
/* Called by lower (CE) layer when data is received from the Target. */
|
||||
static void ath10k_pci_ce_recv_data(struct ce_state *ce_state,
|
||||
static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state,
|
||||
void *transfer_context, u32 ce_data,
|
||||
unsigned int nbytes,
|
||||
unsigned int transfer_id,
|
||||
|
@ -581,7 +682,7 @@ static void ath10k_pci_ce_recv_data(struct ce_state *ce_state,
|
|||
{
|
||||
struct ath10k *ar = ce_state->ar;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct hif_ce_pipe_info *pipe_info = &ar_pci->pipe_info[ce_state->id];
|
||||
struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id];
|
||||
struct ath10k_pci_compl *compl;
|
||||
struct sk_buff *skb;
|
||||
|
||||
|
@ -590,10 +691,10 @@ static void ath10k_pci_ce_recv_data(struct ce_state *ce_state,
|
|||
if (!compl)
|
||||
break;
|
||||
|
||||
compl->send_or_recv = HIF_CE_COMPLETE_RECV;
|
||||
compl->state = ATH10K_PCI_COMPL_RECV;
|
||||
compl->ce_state = ce_state;
|
||||
compl->pipe_info = pipe_info;
|
||||
compl->transfer_context = transfer_context;
|
||||
compl->skb = transfer_context;
|
||||
compl->nbytes = nbytes;
|
||||
compl->transfer_id = transfer_id;
|
||||
compl->flags = flags;
|
||||
|
@ -625,8 +726,8 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
|
|||
{
|
||||
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(nbuf);
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct hif_ce_pipe_info *pipe_info = &(ar_pci->pipe_info[pipe_id]);
|
||||
struct ce_state *ce_hdl = pipe_info->ce_hdl;
|
||||
struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe_id]);
|
||||
struct ath10k_ce_pipe *ce_hdl = pipe_info->ce_hdl;
|
||||
struct ce_sendlist sendlist;
|
||||
unsigned int len;
|
||||
u32 flags = 0;
|
||||
|
@ -670,7 +771,7 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
|
|||
static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct hif_ce_pipe_info *pipe_info = &(ar_pci->pipe_info[pipe]);
|
||||
struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe]);
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&pipe_info->pipe_lock);
|
||||
|
@ -764,9 +865,9 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
|
|||
static int ath10k_pci_start_ce(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ce_state *ce_diag = ar_pci->ce_diag;
|
||||
struct ath10k_ce_pipe *ce_diag = ar_pci->ce_diag;
|
||||
const struct ce_attr *attr;
|
||||
struct hif_ce_pipe_info *pipe_info;
|
||||
struct ath10k_pci_pipe *pipe_info;
|
||||
struct ath10k_pci_compl *compl;
|
||||
int i, pipe_num, completions, disable_interrupts;
|
||||
|
||||
|
@ -805,15 +906,14 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
|
|||
continue;
|
||||
|
||||
for (i = 0; i < completions; i++) {
|
||||
compl = kmalloc(sizeof(struct ath10k_pci_compl),
|
||||
GFP_KERNEL);
|
||||
compl = kmalloc(sizeof(*compl), GFP_KERNEL);
|
||||
if (!compl) {
|
||||
ath10k_warn("No memory for completion state\n");
|
||||
ath10k_pci_stop_ce(ar);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
compl->send_or_recv = HIF_CE_COMPLETE_FREE;
|
||||
compl->state = ATH10K_PCI_COMPL_FREE;
|
||||
list_add_tail(&compl->list, &pipe_info->compl_free);
|
||||
}
|
||||
}
|
||||
|
@ -840,7 +940,7 @@ static void ath10k_pci_stop_ce(struct ath10k *ar)
|
|||
* their associated resources */
|
||||
spin_lock_bh(&ar_pci->compl_lock);
|
||||
list_for_each_entry(compl, &ar_pci->compl_process, list) {
|
||||
skb = (struct sk_buff *)compl->transfer_context;
|
||||
skb = compl->skb;
|
||||
ATH10K_SKB_CB(skb)->is_aborted = true;
|
||||
}
|
||||
spin_unlock_bh(&ar_pci->compl_lock);
|
||||
|
@ -850,7 +950,7 @@ static void ath10k_pci_cleanup_ce(struct ath10k *ar)
|
|||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_pci_compl *compl, *tmp;
|
||||
struct hif_ce_pipe_info *pipe_info;
|
||||
struct ath10k_pci_pipe *pipe_info;
|
||||
struct sk_buff *netbuf;
|
||||
int pipe_num;
|
||||
|
||||
|
@ -861,7 +961,7 @@ static void ath10k_pci_cleanup_ce(struct ath10k *ar)
|
|||
|
||||
list_for_each_entry_safe(compl, tmp, &ar_pci->compl_process, list) {
|
||||
list_del(&compl->list);
|
||||
netbuf = (struct sk_buff *)compl->transfer_context;
|
||||
netbuf = compl->skb;
|
||||
dev_kfree_skb_any(netbuf);
|
||||
kfree(compl);
|
||||
}
|
||||
|
@ -912,12 +1012,14 @@ static void ath10k_pci_process_ce(struct ath10k *ar)
|
|||
list_del(&compl->list);
|
||||
spin_unlock_bh(&ar_pci->compl_lock);
|
||||
|
||||
if (compl->send_or_recv == HIF_CE_COMPLETE_SEND) {
|
||||
switch (compl->state) {
|
||||
case ATH10K_PCI_COMPL_SEND:
|
||||
cb->tx_completion(ar,
|
||||
compl->transfer_context,
|
||||
compl->skb,
|
||||
compl->transfer_id);
|
||||
send_done = 1;
|
||||
} else {
|
||||
break;
|
||||
case ATH10K_PCI_COMPL_RECV:
|
||||
ret = ath10k_pci_post_rx_pipe(compl->pipe_info, 1);
|
||||
if (ret) {
|
||||
ath10k_warn("Unable to post recv buffer for pipe: %d\n",
|
||||
|
@ -925,7 +1027,7 @@ static void ath10k_pci_process_ce(struct ath10k *ar)
|
|||
break;
|
||||
}
|
||||
|
||||
skb = (struct sk_buff *)compl->transfer_context;
|
||||
skb = compl->skb;
|
||||
nbytes = compl->nbytes;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_PCI,
|
||||
|
@ -944,9 +1046,17 @@ static void ath10k_pci_process_ce(struct ath10k *ar)
|
|||
nbytes,
|
||||
skb->len + skb_tailroom(skb));
|
||||
}
|
||||
break;
|
||||
case ATH10K_PCI_COMPL_FREE:
|
||||
ath10k_warn("free completion cannot be processed\n");
|
||||
break;
|
||||
default:
|
||||
ath10k_warn("invalid completion state (%d)\n",
|
||||
compl->state);
|
||||
break;
|
||||
}
|
||||
|
||||
compl->send_or_recv = HIF_CE_COMPLETE_FREE;
|
||||
compl->state = ATH10K_PCI_COMPL_FREE;
|
||||
|
||||
/*
|
||||
* Add completion back to the pipe's free list.
|
||||
|
@ -1037,12 +1147,12 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
|
|||
&dl_is_polled);
|
||||
}
|
||||
|
||||
static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,
|
||||
static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
|
||||
int num)
|
||||
{
|
||||
struct ath10k *ar = pipe_info->hif_ce_state;
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ce_state *ce_state = pipe_info->ce_hdl;
|
||||
struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl;
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t ce_data;
|
||||
int i, ret = 0;
|
||||
|
@ -1097,7 +1207,7 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,
|
|||
static int ath10k_pci_post_rx(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct hif_ce_pipe_info *pipe_info;
|
||||
struct ath10k_pci_pipe *pipe_info;
|
||||
const struct ce_attr *attr;
|
||||
int pipe_num, ret = 0;
|
||||
|
||||
|
@ -1147,11 +1257,11 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info)
|
||||
static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
|
||||
{
|
||||
struct ath10k *ar;
|
||||
struct ath10k_pci *ar_pci;
|
||||
struct ce_state *ce_hdl;
|
||||
struct ath10k_ce_pipe *ce_hdl;
|
||||
u32 buf_sz;
|
||||
struct sk_buff *netbuf;
|
||||
u32 ce_data;
|
||||
|
@ -1179,11 +1289,11 @@ static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info)
|
|||
}
|
||||
}
|
||||
|
||||
static void ath10k_pci_tx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info)
|
||||
static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
|
||||
{
|
||||
struct ath10k *ar;
|
||||
struct ath10k_pci *ar_pci;
|
||||
struct ce_state *ce_hdl;
|
||||
struct ath10k_ce_pipe *ce_hdl;
|
||||
struct sk_buff *netbuf;
|
||||
u32 ce_data;
|
||||
unsigned int nbytes;
|
||||
|
@ -1232,7 +1342,7 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)
|
|||
int pipe_num;
|
||||
|
||||
for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
|
||||
struct hif_ce_pipe_info *pipe_info;
|
||||
struct ath10k_pci_pipe *pipe_info;
|
||||
|
||||
pipe_info = &ar_pci->pipe_info[pipe_num];
|
||||
ath10k_pci_rx_pipe_cleanup(pipe_info);
|
||||
|
@ -1243,7 +1353,7 @@ 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 hif_ce_pipe_info *pipe_info;
|
||||
struct ath10k_pci_pipe *pipe_info;
|
||||
int pipe_num;
|
||||
|
||||
for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
|
||||
|
@ -1293,8 +1403,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
|
|||
void *resp, u32 *resp_len)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ce_state *ce_tx = ar_pci->pipe_info[BMI_CE_NUM_TO_TARG].ce_hdl;
|
||||
struct ce_state *ce_rx = ar_pci->pipe_info[BMI_CE_NUM_TO_HOST].ce_hdl;
|
||||
struct ath10k_pci_pipe *pci_tx = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG];
|
||||
struct ath10k_pci_pipe *pci_rx = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST];
|
||||
struct ath10k_ce_pipe *ce_tx = pci_tx->ce_hdl;
|
||||
struct ath10k_ce_pipe *ce_rx = pci_rx->ce_hdl;
|
||||
dma_addr_t req_paddr = 0;
|
||||
dma_addr_t resp_paddr = 0;
|
||||
struct bmi_xfer xfer = {};
|
||||
|
@ -1378,7 +1490,7 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_pci_bmi_send_done(struct ce_state *ce_state,
|
||||
static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state,
|
||||
void *transfer_context,
|
||||
u32 data,
|
||||
unsigned int nbytes,
|
||||
|
@ -1392,7 +1504,7 @@ static void ath10k_pci_bmi_send_done(struct ce_state *ce_state,
|
|||
complete(&xfer->done);
|
||||
}
|
||||
|
||||
static void ath10k_pci_bmi_recv_data(struct ce_state *ce_state,
|
||||
static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state,
|
||||
void *transfer_context,
|
||||
u32 data,
|
||||
unsigned int nbytes,
|
||||
|
@ -1679,7 +1791,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
|
|||
static int ath10k_pci_ce_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct hif_ce_pipe_info *pipe_info;
|
||||
struct ath10k_pci_pipe *pipe_info;
|
||||
const struct ce_attr *attr;
|
||||
int pipe_num;
|
||||
|
||||
|
@ -1895,7 +2007,7 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
|
|||
|
||||
static void ath10k_pci_ce_tasklet(unsigned long ptr)
|
||||
{
|
||||
struct hif_ce_pipe_info *pipe = (struct hif_ce_pipe_info *)ptr;
|
||||
struct ath10k_pci_pipe *pipe = (struct ath10k_pci_pipe *)ptr;
|
||||
struct ath10k_pci *ar_pci = pipe->ar_pci;
|
||||
|
||||
ath10k_ce_per_engine_service(ar_pci->ar, pipe->pipe_num);
|
||||
|
@ -2212,18 +2324,13 @@ static int ath10k_pci_reset_target(struct ath10k *ar)
|
|||
|
||||
static void ath10k_pci_device_reset(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
void __iomem *mem = ar_pci->mem;
|
||||
int i;
|
||||
u32 val;
|
||||
|
||||
if (!SOC_GLOBAL_RESET_ADDRESS)
|
||||
return;
|
||||
|
||||
if (!mem)
|
||||
return;
|
||||
|
||||
ath10k_pci_reg_write32(mem, PCIE_SOC_WAKE_ADDRESS,
|
||||
ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
|
||||
PCIE_SOC_WAKE_V_MASK);
|
||||
for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
|
||||
if (ath10k_pci_target_is_awake(ar))
|
||||
|
@ -2232,12 +2339,12 @@ static void ath10k_pci_device_reset(struct ath10k *ar)
|
|||
}
|
||||
|
||||
/* Put Target, including PCIe, into RESET. */
|
||||
val = ath10k_pci_reg_read32(mem, SOC_GLOBAL_RESET_ADDRESS);
|
||||
val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
|
||||
val |= 1;
|
||||
ath10k_pci_reg_write32(mem, SOC_GLOBAL_RESET_ADDRESS, val);
|
||||
ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
|
||||
|
||||
for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
|
||||
if (ath10k_pci_reg_read32(mem, RTC_STATE_ADDRESS) &
|
||||
if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
|
||||
RTC_STATE_COLD_RESET_MASK)
|
||||
break;
|
||||
msleep(1);
|
||||
|
@ -2245,16 +2352,16 @@ static void ath10k_pci_device_reset(struct ath10k *ar)
|
|||
|
||||
/* Pull Target, including PCIe, out of RESET. */
|
||||
val &= ~1;
|
||||
ath10k_pci_reg_write32(mem, SOC_GLOBAL_RESET_ADDRESS, val);
|
||||
ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
|
||||
|
||||
for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
|
||||
if (!(ath10k_pci_reg_read32(mem, RTC_STATE_ADDRESS) &
|
||||
if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
|
||||
RTC_STATE_COLD_RESET_MASK))
|
||||
break;
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
ath10k_pci_reg_write32(mem, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET);
|
||||
ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET);
|
||||
}
|
||||
|
||||
static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
|
||||
|
@ -2269,9 +2376,6 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
|
|||
case ATH10K_PCI_FEATURE_MSI_X:
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "device supports MSI-X\n");
|
||||
break;
|
||||
case ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND:
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "QCA988X_1.0 workaround enabled\n");
|
||||
break;
|
||||
case ATH10K_PCI_FEATURE_SOC_POWER_SAVE:
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "QCA98XX SoC power save enabled\n");
|
||||
break;
|
||||
|
@ -2286,7 +2390,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
|||
int ret = 0;
|
||||
struct ath10k *ar;
|
||||
struct ath10k_pci *ar_pci;
|
||||
u32 lcr_val;
|
||||
u32 lcr_val, chip_id;
|
||||
|
||||
ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
|
||||
|
||||
|
@ -2298,9 +2402,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
|||
ar_pci->dev = &pdev->dev;
|
||||
|
||||
switch (pci_dev->device) {
|
||||
case QCA988X_1_0_DEVICE_ID:
|
||||
set_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features);
|
||||
break;
|
||||
case QCA988X_2_0_DEVICE_ID:
|
||||
set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);
|
||||
break;
|
||||
|
@ -2322,10 +2423,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
|||
goto err_ar_pci;
|
||||
}
|
||||
|
||||
/* Enable QCA988X_1.0 HW workarounds */
|
||||
if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features))
|
||||
spin_lock_init(&ar_pci->hw_v1_workaround_lock);
|
||||
|
||||
ar_pci->ar = ar;
|
||||
ar_pci->fw_indicator_address = FW_INDICATOR_ADDRESS;
|
||||
atomic_set(&ar_pci->keep_awake_count, 0);
|
||||
|
@ -2395,9 +2492,18 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
|||
|
||||
spin_lock_init(&ar_pci->ce_lock);
|
||||
|
||||
ar_pci->cacheline_sz = dma_get_cache_alignment();
|
||||
ret = ath10k_do_pci_wake(ar);
|
||||
if (ret) {
|
||||
ath10k_err("Failed to get chip id: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ath10k_core_register(ar);
|
||||
chip_id = ath10k_pci_read32(ar,
|
||||
RTC_SOC_BASE_ADDRESS + SOC_CHIP_ID_ADDRESS);
|
||||
|
||||
ath10k_do_pci_sleep(ar);
|
||||
|
||||
ret = ath10k_core_register(ar, chip_id);
|
||||
if (ret) {
|
||||
ath10k_err("could not register driver core (%d)\n", ret);
|
||||
goto err_iomap;
|
||||
|
@ -2483,9 +2589,6 @@ 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_1_0_FW_DIR "/" QCA988X_HW_1_0_FW_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_1_0_FW_DIR "/" QCA988X_HW_1_0_OTP_FILE);
|
||||
MODULE_FIRMWARE(QCA988X_HW_1_0_FW_DIR "/" QCA988X_HW_1_0_BOARD_DATA_FILE);
|
||||
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_BOARD_DATA_FILE);
|
||||
|
|
|
@ -43,22 +43,23 @@ struct bmi_xfer {
|
|||
u32 resp_len;
|
||||
};
|
||||
|
||||
enum ath10k_pci_compl_state {
|
||||
ATH10K_PCI_COMPL_FREE = 0,
|
||||
ATH10K_PCI_COMPL_SEND,
|
||||
ATH10K_PCI_COMPL_RECV,
|
||||
};
|
||||
|
||||
struct ath10k_pci_compl {
|
||||
struct list_head list;
|
||||
int send_or_recv;
|
||||
struct ce_state *ce_state;
|
||||
struct hif_ce_pipe_info *pipe_info;
|
||||
void *transfer_context;
|
||||
enum ath10k_pci_compl_state state;
|
||||
struct ath10k_ce_pipe *ce_state;
|
||||
struct ath10k_pci_pipe *pipe_info;
|
||||
struct sk_buff *skb;
|
||||
unsigned int nbytes;
|
||||
unsigned int transfer_id;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* compl_state.send_or_recv */
|
||||
#define HIF_CE_COMPLETE_FREE 0
|
||||
#define HIF_CE_COMPLETE_SEND 1
|
||||
#define HIF_CE_COMPLETE_RECV 2
|
||||
|
||||
/*
|
||||
* PCI-specific Target state
|
||||
*
|
||||
|
@ -152,17 +153,16 @@ struct service_to_pipe {
|
|||
|
||||
enum ath10k_pci_features {
|
||||
ATH10K_PCI_FEATURE_MSI_X = 0,
|
||||
ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND = 1,
|
||||
ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 2,
|
||||
ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 1,
|
||||
|
||||
/* keep last */
|
||||
ATH10K_PCI_FEATURE_COUNT
|
||||
};
|
||||
|
||||
/* Per-pipe state. */
|
||||
struct hif_ce_pipe_info {
|
||||
struct ath10k_pci_pipe {
|
||||
/* Handle of underlying Copy Engine */
|
||||
struct ce_state *ce_hdl;
|
||||
struct ath10k_ce_pipe *ce_hdl;
|
||||
|
||||
/* Our pipe number; facilitiates use of pipe_info ptrs. */
|
||||
u8 pipe_num;
|
||||
|
@ -190,7 +190,6 @@ struct ath10k_pci {
|
|||
struct device *dev;
|
||||
struct ath10k *ar;
|
||||
void __iomem *mem;
|
||||
int cacheline_sz;
|
||||
|
||||
DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT);
|
||||
|
||||
|
@ -219,7 +218,7 @@ struct ath10k_pci {
|
|||
|
||||
bool compl_processing;
|
||||
|
||||
struct hif_ce_pipe_info pipe_info[CE_COUNT_MAX];
|
||||
struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
|
||||
|
||||
struct ath10k_hif_cb msg_callbacks_current;
|
||||
|
||||
|
@ -227,16 +226,13 @@ struct ath10k_pci {
|
|||
u32 fw_indicator_address;
|
||||
|
||||
/* Copy Engine used for Diagnostic Accesses */
|
||||
struct ce_state *ce_diag;
|
||||
struct ath10k_ce_pipe *ce_diag;
|
||||
|
||||
/* FIXME: document what this really protects */
|
||||
spinlock_t ce_lock;
|
||||
|
||||
/* Map CE id to ce_state */
|
||||
struct ce_state *ce_id_to_state[CE_COUNT_MAX];
|
||||
|
||||
/* makes sure that dummy reads are atomic */
|
||||
spinlock_t hw_v1_workaround_lock;
|
||||
struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
|
||||
};
|
||||
|
||||
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
||||
|
@ -244,14 +240,18 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
|||
return ar->hif.priv;
|
||||
}
|
||||
|
||||
static inline u32 ath10k_pci_reg_read32(void __iomem *mem, u32 addr)
|
||||
static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
|
||||
{
|
||||
return ioread32(mem + PCIE_LOCAL_BASE_ADDRESS + addr);
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
|
||||
}
|
||||
|
||||
static inline void ath10k_pci_reg_write32(void __iomem *mem, u32 addr, u32 val)
|
||||
static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
|
||||
{
|
||||
iowrite32(val, mem + PCIE_LOCAL_BASE_ADDRESS + addr);
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
|
||||
}
|
||||
|
||||
#define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
|
||||
|
@ -310,23 +310,8 @@ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
|
|||
u32 value)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
void __iomem *addr = ar_pci->mem;
|
||||
|
||||
if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) {
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&ar_pci->hw_v1_workaround_lock, irq_flags);
|
||||
|
||||
ioread32(addr+offset+4); /* 3rd read prior to write */
|
||||
ioread32(addr+offset+4); /* 2nd read prior to write */
|
||||
ioread32(addr+offset+4); /* 1st read prior to write */
|
||||
iowrite32(value, addr+offset);
|
||||
|
||||
spin_unlock_irqrestore(&ar_pci->hw_v1_workaround_lock,
|
||||
irq_flags);
|
||||
} else {
|
||||
iowrite32(value, addr+offset);
|
||||
}
|
||||
iowrite32(value, ar_pci->mem + offset);
|
||||
}
|
||||
|
||||
static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
|
||||
|
@ -336,15 +321,17 @@ static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
|
|||
return ioread32(ar_pci->mem + offset);
|
||||
}
|
||||
|
||||
void ath10k_do_pci_wake(struct ath10k *ar);
|
||||
int ath10k_do_pci_wake(struct ath10k *ar);
|
||||
void ath10k_do_pci_sleep(struct ath10k *ar);
|
||||
|
||||
static inline void ath10k_pci_wake(struct ath10k *ar)
|
||||
static inline int ath10k_pci_wake(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
|
||||
if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
|
||||
ath10k_do_pci_wake(ar);
|
||||
return ath10k_do_pci_wake(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_pci_sleep(struct ath10k *ar)
|
||||
|
|
|
@ -110,6 +110,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
|
|||
if (atomic_add_return(1, &ar->wmi.pending_tx_count) >
|
||||
WMI_MAX_PENDING_TX_COUNT) {
|
||||
/* avoid using up memory when FW hangs */
|
||||
dev_kfree_skb(skb);
|
||||
atomic_dec(&ar->wmi.pending_tx_count);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -315,7 +316,9 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
|
|||
|
||||
static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct wmi_mgmt_rx_event *event = (struct wmi_mgmt_rx_event *)skb->data;
|
||||
struct wmi_mgmt_rx_event_v1 *ev_v1;
|
||||
struct wmi_mgmt_rx_event_v2 *ev_v2;
|
||||
struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_hdr *hdr;
|
||||
u32 rx_status;
|
||||
|
@ -325,13 +328,24 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
u32 rate;
|
||||
u32 buf_len;
|
||||
u16 fc;
|
||||
int pull_len;
|
||||
|
||||
channel = __le32_to_cpu(event->hdr.channel);
|
||||
buf_len = __le32_to_cpu(event->hdr.buf_len);
|
||||
rx_status = __le32_to_cpu(event->hdr.status);
|
||||
snr = __le32_to_cpu(event->hdr.snr);
|
||||
phy_mode = __le32_to_cpu(event->hdr.phy_mode);
|
||||
rate = __le32_to_cpu(event->hdr.rate);
|
||||
if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
|
||||
ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
|
||||
ev_hdr = &ev_v2->hdr.v1;
|
||||
pull_len = sizeof(*ev_v2);
|
||||
} else {
|
||||
ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data;
|
||||
ev_hdr = &ev_v1->hdr;
|
||||
pull_len = sizeof(*ev_v1);
|
||||
}
|
||||
|
||||
channel = __le32_to_cpu(ev_hdr->channel);
|
||||
buf_len = __le32_to_cpu(ev_hdr->buf_len);
|
||||
rx_status = __le32_to_cpu(ev_hdr->status);
|
||||
snr = __le32_to_cpu(ev_hdr->snr);
|
||||
phy_mode = __le32_to_cpu(ev_hdr->phy_mode);
|
||||
rate = __le32_to_cpu(ev_hdr->rate);
|
||||
|
||||
memset(status, 0, sizeof(*status));
|
||||
|
||||
|
@ -358,7 +372,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
|
||||
status->rate_idx = get_rate_idx(rate, status->band);
|
||||
|
||||
skb_pull(skb, sizeof(event->hdr));
|
||||
skb_pull(skb, pull_len);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
fc = le16_to_cpu(hdr->frame_control);
|
||||
|
@ -943,6 +957,9 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
|
|||
ar->phy_capability = __le32_to_cpu(ev->phy_capability);
|
||||
ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
|
||||
|
||||
if (ar->fw_version_build > 636)
|
||||
set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
|
||||
|
||||
if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
|
||||
ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
|
||||
ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
|
||||
|
|
|
@ -1268,7 +1268,7 @@ struct wmi_scan_event {
|
|||
* good idea to pass all the fields in the RX status
|
||||
* descriptor up to the host.
|
||||
*/
|
||||
struct wmi_mgmt_rx_hdr {
|
||||
struct wmi_mgmt_rx_hdr_v1 {
|
||||
__le32 channel;
|
||||
__le32 snr;
|
||||
__le32 rate;
|
||||
|
@ -1277,8 +1277,18 @@ struct wmi_mgmt_rx_hdr {
|
|||
__le32 status; /* %WMI_RX_STATUS_ */
|
||||
} __packed;
|
||||
|
||||
struct wmi_mgmt_rx_event {
|
||||
struct wmi_mgmt_rx_hdr hdr;
|
||||
struct wmi_mgmt_rx_hdr_v2 {
|
||||
struct wmi_mgmt_rx_hdr_v1 v1;
|
||||
__le32 rssi_ctl[4];
|
||||
} __packed;
|
||||
|
||||
struct wmi_mgmt_rx_event_v1 {
|
||||
struct wmi_mgmt_rx_hdr_v1 hdr;
|
||||
u8 buf[0];
|
||||
} __packed;
|
||||
|
||||
struct wmi_mgmt_rx_event_v2 {
|
||||
struct wmi_mgmt_rx_hdr_v2 hdr;
|
||||
u8 buf[0];
|
||||
} __packed;
|
||||
|
||||
|
|
Loading…
Reference in New Issue