int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) { struct ath10k *ar = pipe->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_ring *dest_ring = pipe->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; unsigned int write_index = dest_ring->write_index; unsigned int sw_index = dest_ring->sw_index; struct ce_desc *base = dest_ring->base_addr_owner_space; struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); u32 ctrl_addr = pipe->ctrl_addr; lockdep_assert_held(&ar_pci->ce_lock); if ((pipe->id != 5) && CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0) return -ENOSPC; desc->addr = __cpu_to_le32(paddr); desc->nbytes = 0; dest_ring->per_transfer_context[write_index] = ctx; write_index = CE_RING_IDX_INCR(nentries_mask, write_index); ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index); dest_ring->write_index = write_index; return 0; }
/* NB: Modeled after ath10k_ce_completed_send_next */ 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 ath10k_ce_ring *src_ring; unsigned int nentries_mask; unsigned int sw_index; unsigned int write_index; int ret; struct ath10k *ar; struct ath10k_pci *ar_pci; src_ring = ce_state->src_ring; if (!src_ring) return -EIO; ar = ce_state->ar; ar_pci = ath10k_pci_priv(ar); spin_lock_bh(&ar_pci->ce_lock); nentries_mask = src_ring->nentries_mask; sw_index = src_ring->sw_index; write_index = src_ring->write_index; if (write_index != sw_index) { struct ce_desc *base = src_ring->base_addr_owner_space; struct ce_desc *desc = CE_SRC_RING_TO_DESC(base, sw_index); /* Return data from completed source descriptor */ *bufferp = __le32_to_cpu(desc->addr); *nbytesp = __le16_to_cpu(desc->nbytes); *transfer_idp = MS(__le16_to_cpu(desc->flags), CE_DESC_FLAGS_META_DATA); if (per_transfer_contextp) *per_transfer_contextp = src_ring->per_transfer_context[sw_index]; /* sanity */ src_ring->per_transfer_context[sw_index] = NULL; /* Update sw_index */ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); src_ring->sw_index = sw_index; ret = 0; } else { ret = -EIO; } spin_unlock_bh(&ar_pci->ce_lock); return ret; }
/* * Guts of ath10k_ce_send. * The caller takes responsibility for any needed locking. */ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, u32 buffer, unsigned int nbytes, unsigned int transfer_id, unsigned int flags) { struct ath10k *ar = ce_state->ar; 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; unsigned int write_index = src_ring->write_index; u32 ctrl_addr = ce_state->ctrl_addr; u32 desc_flags = 0; int ret = 0; if (nbytes > ce_state->src_sz_max) ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n", __func__, nbytes, ce_state->src_sz_max); if (unlikely(CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) <= 0)) { ret = -ENOSR; goto exit; } desc = CE_SRC_RING_TO_DESC(src_ring->base_addr_owner_space, write_index); desc_flags |= SM(transfer_id, CE_DESC_FLAGS_META_DATA); if (flags & CE_SEND_FLAG_GATHER) desc_flags |= CE_DESC_FLAGS_GATHER; if (flags & CE_SEND_FLAG_BYTE_SWAP) desc_flags |= CE_DESC_FLAGS_BYTE_SWAP; sdesc.addr = __cpu_to_le32(buffer); sdesc.nbytes = __cpu_to_le16(nbytes); sdesc.flags = __cpu_to_le16(desc_flags); *desc = sdesc; src_ring->per_transfer_context[write_index] = per_transfer_context; /* Update Source Ring Write Index */ write_index = CE_RING_IDX_INCR(nentries_mask, write_index); /* WORKAROUND */ if (!(flags & CE_SEND_FLAG_GATHER)) ath10k_ce_src_ring_write_index_set(ar, ctrl_addr, write_index); src_ring->write_index = write_index; exit: return ret; }
/* * Guts of ath10k_ce_completed_recv_next. * The caller takes responsibility for any necessary locking. */ 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 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; struct ce_desc *base = dest_ring->base_addr_owner_space; struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, sw_index); struct ce_desc sdesc; u16 nbytes; /* Copy in one go for performance reasons */ sdesc = *desc; nbytes = __le16_to_cpu(sdesc.nbytes); if (nbytes == 0) { /* * This closes a relatively unusual race where the Host * sees the updated DRRI before the update to the * corresponding descriptor has completed. We treat this * as a descriptor that is not yet done. */ return -EIO; } desc->nbytes = 0; /* Return data from completed destination descriptor */ *bufferp = __le32_to_cpu(sdesc.addr); *nbytesp = nbytes; *transfer_idp = MS(__le16_to_cpu(sdesc.flags), CE_DESC_FLAGS_META_DATA); if (__le16_to_cpu(sdesc.flags) & CE_DESC_FLAGS_BYTE_SWAP) *flagsp = CE_RECV_FLAG_SWAPPED; else *flagsp = 0; if (per_transfer_contextp) *per_transfer_contextp = dest_ring->per_transfer_context[sw_index]; /* sanity */ dest_ring->per_transfer_context[sw_index] = NULL; /* Update sw_index */ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); dest_ring->sw_index = sw_index; return 0; }
int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp, u32 *bufferp) { struct ath10k_ce_ring *dest_ring; unsigned int nentries_mask; unsigned int sw_index; unsigned int write_index; int ret; struct ath10k *ar; struct ath10k_pci *ar_pci; dest_ring = ce_state->dest_ring; if (!dest_ring) return -EIO; ar = ce_state->ar; ar_pci = ath10k_pci_priv(ar); spin_lock_bh(&ar_pci->ce_lock); nentries_mask = dest_ring->nentries_mask; sw_index = dest_ring->sw_index; write_index = dest_ring->write_index; if (write_index != sw_index) { struct ce_desc *base = dest_ring->base_addr_owner_space; struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, sw_index); /* Return data from completed destination descriptor */ *bufferp = __le32_to_cpu(desc->addr); if (per_transfer_contextp) *per_transfer_contextp = dest_ring->per_transfer_context[sw_index]; /* sanity */ dest_ring->per_transfer_context[sw_index] = NULL; desc->nbytes = 0; /* Update sw_index */ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); dest_ring->sw_index = sw_index; ret = 0; } else { ret = -EIO; } spin_unlock_bh(&ar_pci->ce_lock); return ret; }
/* * Guts of ath10k_ce_completed_recv_next. * The caller takes responsibility for any necessary locking. */ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp, unsigned int *nbytesp) { 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; struct ce_desc *base = dest_ring->base_addr_owner_space; struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, sw_index); struct ce_desc sdesc; u16 nbytes; /* Copy in one go for performance reasons */ sdesc = *desc; nbytes = __le16_to_cpu(sdesc.nbytes); if (nbytes == 0) { /* * This closes a relatively unusual race where the Host * sees the updated DRRI before the update to the * corresponding descriptor has completed. We treat this * as a descriptor that is not yet done. */ return -EIO; } desc->nbytes = 0; /* Return data from completed destination descriptor */ *nbytesp = nbytes; if (per_transfer_contextp) *per_transfer_contextp = dest_ring->per_transfer_context[sw_index]; /* Copy engine 5 (HTT Rx) will reuse the same transfer context. * So update transfer context all CEs except CE5. */ if (ce_state->id != 5) dest_ring->per_transfer_context[sw_index] = NULL; /* Update sw_index */ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); dest_ring->sw_index = sw_index; return 0; }
int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, void *per_recv_context, u32 buffer) { 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); unsigned int nentries_mask = dest_ring->nentries_mask; unsigned int write_index; unsigned int sw_index; int ret; spin_lock_bh(&ar_pci->ce_lock); write_index = dest_ring->write_index; sw_index = dest_ring->sw_index; 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; struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); /* Update destination descriptor */ desc->addr = __cpu_to_le32(buffer); desc->nbytes = 0; dest_ring->per_transfer_context[write_index] = per_recv_context; /* Update Destination Ring Write Index */ write_index = CE_RING_IDX_INCR(nentries_mask, write_index); ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index); dest_ring->write_index = write_index; ret = 0; } else { ret = -EIO; } ath10k_pci_sleep(ar); out: spin_unlock_bh(&ar_pci->ce_lock); return ret; }
/* * Guts of ath10k_ce_completed_send_next. * The caller takes responsibility for any necessary locking. */ int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp) { 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; unsigned int read_index; if (src_ring->hw_index == sw_index) { /* * The SW completion index has caught up with the cached * version of the HW completion index. * Update the cached HW completion index to see whether * the SW has really caught up to the HW, or if the cached * value of the HW index has become stale. */ read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); if (read_index == 0xffffffff) return -ENODEV; read_index &= nentries_mask; src_ring->hw_index = read_index; } read_index = src_ring->hw_index; if (read_index == sw_index) return -EIO; if (per_transfer_contextp) *per_transfer_contextp = src_ring->per_transfer_context[sw_index]; /* sanity */ src_ring->per_transfer_context[sw_index] = NULL; /* Update sw_index */ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); src_ring->sw_index = sw_index; return 0; }
/* * Guts of ath10k_ce_completed_send_next. * The caller takes responsibility for any necessary locking. */ 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 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; if (src_ring->hw_index == sw_index) { /* * The SW completion index has caught up with the cached * version of the HW completion index. * Update the cached HW completion index to see whether * the SW has really caught up to the HW, or if the cached * value of the HW index has become stale. */ 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)) 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); *nbytesp = __le16_to_cpu(sdesc->nbytes); *transfer_idp = MS(__le16_to_cpu(sdesc->flags), CE_DESC_FLAGS_META_DATA); if (per_transfer_contextp) *per_transfer_contextp = src_ring->per_transfer_context[sw_index]; /* sanity */ src_ring->per_transfer_context[sw_index] = NULL; /* Update sw_index */ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); src_ring->sw_index = sw_index; return 0; }