|
@@ -58,7 +58,6 @@ static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {
|
|
|
static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
|
|
|
u32 *data);
|
|
|
|
|
|
-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 ath10k_pci_pipe *pipe_info,
|
|
|
int num);
|
|
@@ -73,7 +72,6 @@ static void ath10k_pci_free_irq(struct ath10k *ar);
|
|
|
static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
|
|
|
struct ath10k_ce_pipe *rx_pipe,
|
|
|
struct bmi_xfer *xfer);
|
|
|
-static void ath10k_pci_cleanup_ce(struct ath10k *ar);
|
|
|
|
|
|
static const struct ce_attr host_ce_config_wlan[] = {
|
|
|
/* CE0: host->target HTC control and raw streams */
|
|
@@ -678,34 +676,12 @@ void ath10k_do_pci_sleep(struct ath10k *ar)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * FIXME: Handle OOM properly.
|
|
|
- */
|
|
|
-static inline
|
|
|
-struct ath10k_pci_compl *get_free_compl(struct ath10k_pci_pipe *pipe_info)
|
|
|
-{
|
|
|
- struct ath10k_pci_compl *compl = NULL;
|
|
|
-
|
|
|
- spin_lock_bh(&pipe_info->pipe_lock);
|
|
|
- if (list_empty(&pipe_info->compl_free)) {
|
|
|
- ath10k_warn("Completion buffers are full\n");
|
|
|
- goto exit;
|
|
|
- }
|
|
|
- compl = list_first_entry(&pipe_info->compl_free,
|
|
|
- struct ath10k_pci_compl, list);
|
|
|
- list_del(&compl->list);
|
|
|
-exit:
|
|
|
- spin_unlock_bh(&pipe_info->pipe_lock);
|
|
|
- return compl;
|
|
|
-}
|
|
|
-
|
|
|
/* Called by lower (CE) layer when a send to Target completes. */
|
|
|
static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
|
|
|
{
|
|
|
struct ath10k *ar = ce_state->ar;
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
- struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id];
|
|
|
- struct ath10k_pci_compl *compl;
|
|
|
+ struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
|
|
|
void *transfer_context;
|
|
|
u32 ce_data;
|
|
|
unsigned int nbytes;
|
|
@@ -718,27 +694,8 @@ static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
|
|
|
if (transfer_context == NULL)
|
|
|
continue;
|
|
|
|
|
|
- compl = get_free_compl(pipe_info);
|
|
|
- if (!compl)
|
|
|
- break;
|
|
|
-
|
|
|
- compl->state = ATH10K_PCI_COMPL_SEND;
|
|
|
- compl->ce_state = ce_state;
|
|
|
- compl->pipe_info = pipe_info;
|
|
|
- compl->skb = transfer_context;
|
|
|
- compl->nbytes = nbytes;
|
|
|
- compl->transfer_id = transfer_id;
|
|
|
- compl->flags = 0;
|
|
|
-
|
|
|
- /*
|
|
|
- * Add the completion to the processing queue.
|
|
|
- */
|
|
|
- spin_lock_bh(&ar_pci->compl_lock);
|
|
|
- list_add_tail(&compl->list, &ar_pci->compl_process);
|
|
|
- spin_unlock_bh(&ar_pci->compl_lock);
|
|
|
+ cb->tx_completion(ar, transfer_context, transfer_id);
|
|
|
}
|
|
|
-
|
|
|
- ath10k_pci_process_ce(ar);
|
|
|
}
|
|
|
|
|
|
/* Called by lower (CE) layer when data is received from the Target. */
|
|
@@ -747,42 +704,40 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
|
|
|
struct ath10k *ar = ce_state->ar;
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id];
|
|
|
- struct ath10k_pci_compl *compl;
|
|
|
+ struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
|
|
|
struct sk_buff *skb;
|
|
|
void *transfer_context;
|
|
|
u32 ce_data;
|
|
|
- unsigned int nbytes;
|
|
|
+ unsigned int nbytes, max_nbytes;
|
|
|
unsigned int transfer_id;
|
|
|
unsigned int flags;
|
|
|
+ int err;
|
|
|
|
|
|
while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
|
|
|
&ce_data, &nbytes, &transfer_id,
|
|
|
&flags) == 0) {
|
|
|
- compl = get_free_compl(pipe_info);
|
|
|
- if (!compl)
|
|
|
- break;
|
|
|
-
|
|
|
- compl->state = ATH10K_PCI_COMPL_RECV;
|
|
|
- compl->ce_state = ce_state;
|
|
|
- compl->pipe_info = pipe_info;
|
|
|
- compl->skb = transfer_context;
|
|
|
- compl->nbytes = nbytes;
|
|
|
- compl->transfer_id = transfer_id;
|
|
|
- compl->flags = flags;
|
|
|
+ err = ath10k_pci_post_rx_pipe(pipe_info, 1);
|
|
|
+ if (unlikely(err)) {
|
|
|
+ /* FIXME: retry */
|
|
|
+ ath10k_warn("failed to replenish CE rx ring %d: %d\n",
|
|
|
+ pipe_info->pipe_num, err);
|
|
|
+ }
|
|
|
|
|
|
skb = transfer_context;
|
|
|
+ max_nbytes = skb->len + skb_tailroom(skb);
|
|
|
dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
|
|
|
- skb->len + skb_tailroom(skb),
|
|
|
- DMA_FROM_DEVICE);
|
|
|
- /*
|
|
|
- * Add the completion to the processing queue.
|
|
|
- */
|
|
|
- spin_lock_bh(&ar_pci->compl_lock);
|
|
|
- list_add_tail(&compl->list, &ar_pci->compl_process);
|
|
|
- spin_unlock_bh(&ar_pci->compl_lock);
|
|
|
- }
|
|
|
+ max_nbytes, DMA_FROM_DEVICE);
|
|
|
|
|
|
- ath10k_pci_process_ce(ar);
|
|
|
+ if (unlikely(max_nbytes < nbytes)) {
|
|
|
+ ath10k_warn("rxed more than expected (nbytes %d, max %d)",
|
|
|
+ nbytes, max_nbytes);
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ skb_put(skb, nbytes);
|
|
|
+ cb->rx_completion(ar, skb, pipe_info->pipe_num);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
|
@@ -931,52 +886,6 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
|
|
|
sizeof(ar_pci->msg_callbacks_current));
|
|
|
}
|
|
|
|
|
|
-static int ath10k_pci_alloc_compl(struct ath10k *ar)
|
|
|
-{
|
|
|
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
|
- const struct ce_attr *attr;
|
|
|
- struct ath10k_pci_pipe *pipe_info;
|
|
|
- struct ath10k_pci_compl *compl;
|
|
|
- int i, pipe_num, completions;
|
|
|
-
|
|
|
- spin_lock_init(&ar_pci->compl_lock);
|
|
|
- INIT_LIST_HEAD(&ar_pci->compl_process);
|
|
|
-
|
|
|
- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
|
|
|
- pipe_info = &ar_pci->pipe_info[pipe_num];
|
|
|
-
|
|
|
- spin_lock_init(&pipe_info->pipe_lock);
|
|
|
- INIT_LIST_HEAD(&pipe_info->compl_free);
|
|
|
-
|
|
|
- /* Handle Diagnostic CE specially */
|
|
|
- if (pipe_info->ce_hdl == ar_pci->ce_diag)
|
|
|
- continue;
|
|
|
-
|
|
|
- attr = &host_ce_config_wlan[pipe_num];
|
|
|
- completions = 0;
|
|
|
-
|
|
|
- if (attr->src_nentries)
|
|
|
- completions += attr->src_nentries;
|
|
|
-
|
|
|
- if (attr->dest_nentries)
|
|
|
- completions += attr->dest_nentries;
|
|
|
-
|
|
|
- for (i = 0; i < completions; i++) {
|
|
|
- compl = kmalloc(sizeof(*compl), GFP_KERNEL);
|
|
|
- if (!compl) {
|
|
|
- ath10k_warn("No memory for completion state\n");
|
|
|
- ath10k_pci_cleanup_ce(ar);
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
-
|
|
|
- compl->state = ATH10K_PCI_COMPL_FREE;
|
|
|
- list_add_tail(&compl->list, &pipe_info->compl_free);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int ath10k_pci_setup_ce_irq(struct ath10k *ar)
|
|
|
{
|
|
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
@@ -1021,131 +930,6 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
|
|
|
tasklet_kill(&ar_pci->pipe_info[i].intr);
|
|
|
}
|
|
|
|
|
|
-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 ath10k_pci_pipe *pipe_info;
|
|
|
- struct sk_buff *netbuf;
|
|
|
- int pipe_num;
|
|
|
-
|
|
|
- /* Free pending completions. */
|
|
|
- spin_lock_bh(&ar_pci->compl_lock);
|
|
|
- if (!list_empty(&ar_pci->compl_process))
|
|
|
- ath10k_warn("pending completions still present! possible memory leaks.\n");
|
|
|
-
|
|
|
- list_for_each_entry_safe(compl, tmp, &ar_pci->compl_process, list) {
|
|
|
- list_del(&compl->list);
|
|
|
- netbuf = compl->skb;
|
|
|
- dev_kfree_skb_any(netbuf);
|
|
|
- kfree(compl);
|
|
|
- }
|
|
|
- spin_unlock_bh(&ar_pci->compl_lock);
|
|
|
-
|
|
|
- /* Free unused completions for each pipe. */
|
|
|
- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
|
|
|
- pipe_info = &ar_pci->pipe_info[pipe_num];
|
|
|
-
|
|
|
- spin_lock_bh(&pipe_info->pipe_lock);
|
|
|
- list_for_each_entry_safe(compl, tmp,
|
|
|
- &pipe_info->compl_free, list) {
|
|
|
- list_del(&compl->list);
|
|
|
- kfree(compl);
|
|
|
- }
|
|
|
- spin_unlock_bh(&pipe_info->pipe_lock);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void ath10k_pci_process_ce(struct ath10k *ar)
|
|
|
-{
|
|
|
- struct ath10k_pci *ar_pci = ar->hif.priv;
|
|
|
- struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
|
|
|
- struct ath10k_pci_compl *compl;
|
|
|
- struct sk_buff *skb;
|
|
|
- unsigned int nbytes;
|
|
|
- int ret, send_done = 0;
|
|
|
-
|
|
|
- /* Upper layers aren't ready to handle tx/rx completions in parallel so
|
|
|
- * we must serialize all completion processing. */
|
|
|
-
|
|
|
- spin_lock_bh(&ar_pci->compl_lock);
|
|
|
- if (ar_pci->compl_processing) {
|
|
|
- spin_unlock_bh(&ar_pci->compl_lock);
|
|
|
- return;
|
|
|
- }
|
|
|
- ar_pci->compl_processing = true;
|
|
|
- spin_unlock_bh(&ar_pci->compl_lock);
|
|
|
-
|
|
|
- for (;;) {
|
|
|
- spin_lock_bh(&ar_pci->compl_lock);
|
|
|
- if (list_empty(&ar_pci->compl_process)) {
|
|
|
- spin_unlock_bh(&ar_pci->compl_lock);
|
|
|
- break;
|
|
|
- }
|
|
|
- compl = list_first_entry(&ar_pci->compl_process,
|
|
|
- struct ath10k_pci_compl, list);
|
|
|
- list_del(&compl->list);
|
|
|
- spin_unlock_bh(&ar_pci->compl_lock);
|
|
|
-
|
|
|
- switch (compl->state) {
|
|
|
- case ATH10K_PCI_COMPL_SEND:
|
|
|
- cb->tx_completion(ar,
|
|
|
- compl->skb,
|
|
|
- compl->transfer_id);
|
|
|
- send_done = 1;
|
|
|
- break;
|
|
|
- case ATH10K_PCI_COMPL_RECV:
|
|
|
- ret = ath10k_pci_post_rx_pipe(compl->pipe_info, 1);
|
|
|
- if (ret) {
|
|
|
- ath10k_warn("failed to post RX buffer for pipe %d: %d\n",
|
|
|
- compl->pipe_info->pipe_num, ret);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- skb = compl->skb;
|
|
|
- nbytes = compl->nbytes;
|
|
|
-
|
|
|
- ath10k_dbg(ATH10K_DBG_PCI,
|
|
|
- "ath10k_pci_ce_recv_data netbuf=%p nbytes=%d\n",
|
|
|
- skb, nbytes);
|
|
|
- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL,
|
|
|
- "ath10k rx: ", skb->data, nbytes);
|
|
|
-
|
|
|
- if (skb->len + skb_tailroom(skb) >= nbytes) {
|
|
|
- skb_trim(skb, 0);
|
|
|
- skb_put(skb, nbytes);
|
|
|
- cb->rx_completion(ar, skb,
|
|
|
- compl->pipe_info->pipe_num);
|
|
|
- } else {
|
|
|
- ath10k_warn("rxed more than expected (nbytes %d, max %d)",
|
|
|
- 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->state = ATH10K_PCI_COMPL_FREE;
|
|
|
-
|
|
|
- /*
|
|
|
- * Add completion back to the pipe's free list.
|
|
|
- */
|
|
|
- spin_lock_bh(&compl->pipe_info->pipe_lock);
|
|
|
- list_add_tail(&compl->list, &compl->pipe_info->compl_free);
|
|
|
- spin_unlock_bh(&compl->pipe_info->pipe_lock);
|
|
|
- }
|
|
|
-
|
|
|
- spin_lock_bh(&ar_pci->compl_lock);
|
|
|
- ar_pci->compl_processing = false;
|
|
|
- spin_unlock_bh(&ar_pci->compl_lock);
|
|
|
-}
|
|
|
-
|
|
|
/* TODO - temporary mapping while we have too few CE's */
|
|
|
static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
|
|
|
u16 service_id, u8 *ul_pipe,
|
|
@@ -1317,17 +1101,11 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
|
|
|
ath10k_pci_free_early_irq(ar);
|
|
|
ath10k_pci_kill_tasklet(ar);
|
|
|
|
|
|
- ret = ath10k_pci_alloc_compl(ar);
|
|
|
- if (ret) {
|
|
|
- ath10k_warn("failed to allocate CE completions: %d\n", ret);
|
|
|
- goto err_early_irq;
|
|
|
- }
|
|
|
-
|
|
|
ret = ath10k_pci_request_irq(ar);
|
|
|
if (ret) {
|
|
|
ath10k_warn("failed to post RX buffers for all pipes: %d\n",
|
|
|
ret);
|
|
|
- goto err_free_compl;
|
|
|
+ goto err_early_irq;
|
|
|
}
|
|
|
|
|
|
ret = ath10k_pci_setup_ce_irq(ar);
|
|
@@ -1351,9 +1129,6 @@ err_stop:
|
|
|
ath10k_ce_disable_interrupts(ar);
|
|
|
ath10k_pci_free_irq(ar);
|
|
|
ath10k_pci_kill_tasklet(ar);
|
|
|
- ath10k_pci_process_ce(ar);
|
|
|
-err_free_compl:
|
|
|
- ath10k_pci_cleanup_ce(ar);
|
|
|
err_early_irq:
|
|
|
/* Though there should be no interrupts (device was reset)
|
|
|
* power_down() expects the early IRQ to be installed as per the
|
|
@@ -1494,8 +1269,6 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
|
|
|
* not DMA nor interrupt. We process the leftovers and then free
|
|
|
* everything else up. */
|
|
|
|
|
|
- ath10k_pci_process_ce(ar);
|
|
|
- ath10k_pci_cleanup_ce(ar);
|
|
|
ath10k_pci_buffer_cleanup(ar);
|
|
|
|
|
|
/* Make the sure the device won't access any structures on the host by
|