summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c79
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h6
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c7
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h7
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c19
7 files changed, 102 insertions, 18 deletions
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 769f89e8d14c..9ccd6212b54a 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -96,13 +96,29 @@ static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar,
ce_ctrl_addr + ar->hw_ce_regs->sr_wr_index_addr);
}
+static inline u32 ath10k_ce_src_ring_read_index_get_from_ddr(
+ struct ath10k *ar, u32 ce_id)
+{
+ struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
+
+ return ar_opaque->vaddr_rri_on_ddr[ce_id] & CE_DDR_RRI_MASK;
+}
+
static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar,
u32 ce_ctrl_addr)
{
struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
+ u32 ce_id = COPY_ENGINE_ID(ce_ctrl_addr);
+ struct ath10k_ce_pipe *ce_state = &ar_opaque->ce_states[ce_id];
+ u32 index;
- return ar_opaque->bus_ops->read32(ar,
+ if (ar->rri_on_ddr && (ce_state->attr_flags & CE_ATTR_DIS_INTR))
+ index = ath10k_ce_src_ring_read_index_get_from_ddr(ar, ce_id);
+ else
+ index = ar_opaque->bus_ops->read32(ar,
ce_ctrl_addr + ar->hw_ce_regs->current_srri_addr);
+
+ return index;
}
static inline void ath10k_ce_shadow_src_ring_write_index_set(struct ath10k *ar,
@@ -195,9 +211,19 @@ static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar,
u32 ce_ctrl_addr)
{
struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
+ u32 ce_id = COPY_ENGINE_ID(ce_ctrl_addr);
+ struct ath10k_ce_pipe *ce_state = &ar_opaque->ce_states[ce_id];
+ u32 index;
- return ar_opaque->bus_ops->read32(ar,
+ if (ar->rri_on_ddr && (ce_state->attr_flags & CE_ATTR_DIS_INTR))
+ index = (ar_opaque->vaddr_rri_on_ddr[ce_id] >>
+ CE_DDR_RRI_SHIFT) &
+ CE_DDR_RRI_MASK;
+ else
+ index = ar_opaque->bus_ops->read32(ar,
ce_ctrl_addr + ar->hw_ce_regs->current_drri_addr);
+
+ return index;
}
static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar,
@@ -449,7 +475,7 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
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 sw_index;
unsigned int write_index = src_ring->write_index;
u32 ctrl_addr = ce_state->ctrl_addr;
u32 desc_flags = 0;
@@ -462,6 +488,7 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n",
__func__, nbytes, ce_state->src_sz_max);
+ sw_index = ath10k_ce_src_ring_read_index_get_from_ddr(ar, ce_state->id);
if (unlikely(CE_RING_DELTA(nentries_mask,
write_index, sw_index - 1) <= 0)) {
ret = -ENOSR;
@@ -1235,6 +1262,52 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
return dest_ring;
}
+void ce_config_rri_on_ddr(struct ath10k *ar)
+{
+ struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
+ u32 hi_paddr, low_paddr;
+ u32 ce_base_addr;
+ u32 ctrl1_regs;
+ int i;
+
+ ar_opaque->vaddr_rri_on_ddr =
+ (u32 *)dma_alloc_coherent(ar->dev,
+ (CE_COUNT * sizeof(u32)),
+ &ar_opaque->paddr_rri_on_ddr, GFP_KERNEL);
+
+ if (!ar_opaque->vaddr_rri_on_ddr)
+ return;
+
+ low_paddr = lower_32_bits(ar_opaque->paddr_rri_on_ddr);
+ hi_paddr = upper_32_bits(ar_opaque->paddr_rri_on_ddr) &
+ CE_DESC_FLAGS_GET_MASK;
+
+ ar_opaque->bus_ops->write32(ar, ar->hw_ce_regs->ce_rri_low, low_paddr);
+ ar_opaque->bus_ops->write32(ar, ar->hw_ce_regs->ce_rri_high, hi_paddr);
+
+ for (i = 0; i < CE_COUNT; i++) {
+ ctrl1_regs = ar->hw_ce_regs->ctrl1_regs->addr;
+ ce_base_addr = ath10k_ce_base_address(ar, i);
+ ar_opaque->bus_ops->write32(ar, ce_base_addr + ctrl1_regs,
+ ar_opaque->bus_ops->read32(ar, ce_base_addr + ctrl1_regs) |
+ ar->hw_ce_regs->upd->mask);
+ }
+
+ memset(ar_opaque->vaddr_rri_on_ddr, 0, CE_COUNT * sizeof(u32));
+}
+
+void ce_remove_rri_on_ddr(struct ath10k *ar)
+{
+ struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
+
+ if (!ar_opaque->vaddr_rri_on_ddr)
+ return;
+
+ dma_free_coherent(ar->dev, (CE_COUNT * sizeof(u32)),
+ ar_opaque->vaddr_rri_on_ddr,
+ ar_opaque->paddr_rri_on_ddr);
+}
+
/*
* Initialize a Copy Engine based on caller-supplied attributes.
* This may be called once to initialize both source and destination
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 936f0698c0f0..fe5f5680ca3d 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -42,6 +42,8 @@ struct ath10k_ce_pipe;
#define CE_DESC_FLAGS_GET_MASK 0x1F
#define CE_DESC_37BIT_ADDR_MASK 0x1FFFFFFFFF
+#define CE_DDR_RRI_MASK 0xFFFF
+#define CE_DDR_RRI_SHIFT 16
/* Following desc flags are used in QCA99X0 */
#define CE_DESC_FLAGS_HOST_INT_DIS (1 << 2)
@@ -211,6 +213,8 @@ struct bus_opaque {
spinlock_t ce_lock;
const struct ath10k_bus_ops *bus_ops;
struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
+ u32 *vaddr_rri_on_ddr;
+ dma_addr_t paddr_rri_on_ddr;
};
/*==================Send====================*/
@@ -288,6 +292,8 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
const struct ce_attr *attr);
void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
+void ce_config_rri_on_ddr(struct ath10k *ar);
+void ce_remove_rri_on_ddr(struct ath10k *ar);
/*==================CE Engine Shutdown=======================*/
/*
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 079d77678b1c..1e1df685ffa5 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2374,6 +2374,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
ar->fw_flags = &wcn3990_fw_flags;
ar->shadow_reg_value = &wcn3990_shadow_reg_value;
ar->shadow_reg_address = &wcn3990_shadow_reg_address;
+ ar->rri_on_ddr = true;
break;
default:
ath10k_err(ar, "unsupported core hardware revision %d\n",
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 2ef2e1ec040a..5491826ec05a 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -967,6 +967,7 @@ struct ath10k {
struct completion peer_delete_done;
bool is_bmi;
enum ieee80211_sta_state sta_state;
+ bool rri_on_ddr;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 1437b5d29a17..558214cef688 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -284,6 +284,12 @@ struct ath10k_hw_ce_dst_src_wm_regs wcn3990_wm_dst_ring = {
.wm_high = &wcn3990_dst_wm_high,
};
+static struct ath10k_hw_ce_ctrl1_upd wcn3990_ctrl1_upd = {
+ .shift = 19,
+ .mask = 0x00080000,
+ .enable = 0x00000000,
+};
+
struct ath10k_hw_ce_regs wcn3990_ce_regs = {
.sr_base_addr = 0x00000000,
.sr_size_addr = 0x00000008,
@@ -305,6 +311,7 @@ struct ath10k_hw_ce_regs wcn3990_ce_regs = {
.misc_regs = &wcn3990_misc_reg,
.wm_srcr = &wcn3990_wm_src_ring,
.wm_dstr = &wcn3990_wm_dst_ring,
+ .upd = &wcn3990_ctrl1_upd,
};
struct ath10k_hw_ce_regs_addr_map qcax_src_ring = {
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index a37b956c558f..77c197132421 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -332,6 +332,12 @@ struct ath10k_hw_ce_dst_src_wm_regs {
struct ath10k_hw_ce_regs_addr_map *wm_high;
};
+struct ath10k_hw_ce_ctrl1_upd {
+ u32 shift;
+ u32 mask;
+ u32 enable;
+};
+
struct ath10k_hw_ce_regs {
u32 sr_base_addr;
u32 sr_size_addr;
@@ -355,6 +361,7 @@ struct ath10k_hw_ce_regs {
struct ath10k_hw_ce_host_ie *host_ie;
struct ath10k_hw_ce_dst_src_wm_regs *wm_srcr;
struct ath10k_hw_ce_dst_src_wm_regs *wm_dstr;
+ struct ath10k_hw_ce_ctrl1_upd *upd;
};
extern struct ath10k_hw_ce_regs wcn3990_ce_regs;
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index a1a4812feeed..aead886a582c 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -646,10 +646,6 @@ static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct ath10k_snoc_pipe *snoc_pipe;
struct ath10k_ce_pipe *ce_pipe;
- struct ath10k_ce_ring *src_ring;
- unsigned int nentries_mask;
- unsigned int sw_index;
- unsigned int write_index;
int err, i = 0;
if (!ar_snoc)
@@ -660,19 +656,8 @@ static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
snoc_pipe = &ar_snoc->pipe_info[pipe_id];
ce_pipe = snoc_pipe->ce_hdl;
- src_ring = ce_pipe->src_ring;
spin_lock_bh(&ar_snoc->opaque_ctx.ce_lock);
- nentries_mask = src_ring->nentries_mask;
- sw_index = src_ring->sw_index;
- write_index = src_ring->write_index;
-
- if (unlikely(CE_RING_DELTA(nentries_mask,
- write_index, sw_index - 1) < n_items)) {
- err = -ENOBUFS;
- goto err;
- }
-
for (i = 0; i < n_items - 1; i++) {
ath10k_dbg(ar, ATH10K_DBG_SNOC,
"snoc tx item %d paddr %pad len %d n_items %d\n",
@@ -967,6 +952,8 @@ static void ath10k_snoc_hif_power_down(struct ath10k *ar)
if (!atomic_read(&ar_snoc->pm_ops_inprogress))
ath10k_snoc_qmi_wlan_disable(ar);
+
+ ce_remove_rri_on_ddr(ar);
}
int ath10k_snoc_get_ce_id(struct ath10k *ar, int irq)
@@ -1121,6 +1108,8 @@ static int ath10k_snoc_bus_configure(struct ath10k *ar)
return ret;
}
+ ce_config_rri_on_ddr(ar);
+
return 0;
}