diff options
Diffstat (limited to 'drivers/soc/ti/k3-ringacc.c')
| -rw-r--r-- | drivers/soc/ti/k3-ringacc.c | 727 |
1 files changed, 573 insertions, 154 deletions
diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c index 5fb2ee2ac978..7602b8a909b0 100644 --- a/drivers/soc/ti/k3-ringacc.c +++ b/drivers/soc/ti/k3-ringacc.c @@ -7,9 +7,11 @@ #include <linux/dma-mapping.h> #include <linux/io.h> -#include <linux/init.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/sys_soc.h> +#include <linux/dma/ti-cppi5.h> #include <linux/soc/ti/k3-ringacc.h> #include <linux/soc/ti/ti_sci_protocol.h> #include <linux/soc/ti/ti_sci_inta_msi.h> @@ -20,6 +22,7 @@ static LIST_HEAD(k3_ringacc_list); static DEFINE_MUTEX(k3_ringacc_list_lock); #define K3_RINGACC_CFG_RING_SIZE_ELCNT_MASK GENMASK(19, 0) +#define K3_DMARING_CFG_RING_SIZE_ELCNT_MASK GENMASK(15, 0) /** * struct k3_ring_rt_regs - The RA realtime Control/Status Registers region @@ -42,7 +45,13 @@ struct k3_ring_rt_regs { u32 hwindx; }; -#define K3_RINGACC_RT_REGS_STEP 0x1000 +#define K3_RINGACC_RT_REGS_STEP 0x1000 +#define K3_DMARING_RT_REGS_STEP 0x2000 +#define K3_DMARING_RT_REGS_REVERSE_OFS 0x1000 +#define K3_RINGACC_RT_OCC_MASK GENMASK(20, 0) +#define K3_DMARING_RT_OCC_TDOWN_COMPLETE BIT(31) +#define K3_DMARING_RT_DB_ENTRY_MASK GENMASK(7, 0) +#define K3_DMARING_RT_DB_TDOWN_ACK BIT(31) /** * struct k3_ring_fifo_regs - The Ring Accelerator Queues Registers region @@ -109,6 +118,23 @@ struct k3_ring_ops { }; /** + * struct k3_ring_state - Internal state tracking structure + * + * @free: Number of free entries + * @occ: Occupancy + * @windex: Write index + * @rindex: Read index + * @tdown_complete: Tear down complete state + */ +struct k3_ring_state { + u32 free; + u32 occ; + u32 windex; + u32 rindex; + u32 tdown_complete:1; +}; + +/** * struct k3_ring - RA Ring descriptor * * @rt: Ring control/status registers @@ -121,14 +147,13 @@ struct k3_ring_ops { * @elm_size: Size of the ring element * @mode: Ring mode * @flags: flags - * @free: Number of free elements - * @occ: Ring occupancy - * @windex: Write index (only for @K3_RINGACC_RING_MODE_RING) - * @rindex: Read index (only for @K3_RINGACC_RING_MODE_RING) + * @state: Ring state * @ring_id: Ring Id * @parent: Pointer on struct @k3_ringacc * @use_count: Use count for shared rings * @proxy_id: RA Ring Proxy Id (only if @K3_RINGACC_RING_USE_PROXY) + * @dma_dev: device to be used for DMA API (allocation, mapping) + * @asel: Address Space Select value for physical addresses */ struct k3_ring { struct k3_ring_rt_regs __iomem *rt; @@ -136,21 +161,26 @@ struct k3_ring { struct k3_ringacc_proxy_target_regs __iomem *proxy; dma_addr_t ring_mem_dma; void *ring_mem_virt; - struct k3_ring_ops *ops; + const struct k3_ring_ops *ops; u32 size; enum k3_ring_size elm_size; enum k3_ring_mode mode; u32 flags; #define K3_RING_FLAG_BUSY BIT(1) #define K3_RING_FLAG_SHARED BIT(2) - u32 free; - u32 occ; - u32 windex; - u32 rindex; +#define K3_RING_FLAG_REVERSE BIT(3) + struct k3_ring_state state; u32 ring_id; struct k3_ringacc *parent; u32 use_count; int proxy_id; + struct device *dma_dev; + u32 asel; +#define K3_ADDRESS_ASEL_SHIFT 48 +}; + +struct k3_ringacc_ops { + int (*init)(struct platform_device *pdev, struct k3_ringacc *ringacc); }; /** @@ -162,7 +192,7 @@ struct k3_ring { * @num_rings: number of ring in RA * @rings_inuse: bitfield for ring usage tracking * @rm_gp_range: general purpose rings range from tisci - * @dma_ring_reset_quirk: DMA reset w/a enable + * @dma_ring_reset_quirk: DMA reset workaround enable * @num_proxies: number of RA proxies * @proxy_inuse: bitfield for proxy usage tracking * @rings: array of rings descriptors (struct @k3_ring) @@ -171,6 +201,8 @@ struct k3_ring { * @tisci: pointer ti-sci handle * @tisci_ring_ops: ti-sci rings ops * @tisci_dev_id: ti-sci device id + * @ops: SoC specific ringacc operation + * @dma_rings: indicate DMA ring (dual ring within BCDMA/PKTDMA) */ struct k3_ringacc { struct device *dev; @@ -191,8 +223,35 @@ struct k3_ringacc { const struct ti_sci_handle *tisci; const struct ti_sci_rm_ringacc_ops *tisci_ring_ops; u32 tisci_dev_id; + + const struct k3_ringacc_ops *ops; + bool dma_rings; }; +/** + * struct k3_ringacc_soc_data - Rings accelerator SoC data + * + * @dma_ring_reset_quirk: DMA reset workaround enable + */ +struct k3_ringacc_soc_data { + unsigned dma_ring_reset_quirk:1; +}; + +static int k3_ringacc_ring_read_occ(struct k3_ring *ring) +{ + return readl(&ring->rt->occ) & K3_RINGACC_RT_OCC_MASK; +} + +static void k3_ringacc_ring_update_occ(struct k3_ring *ring) +{ + u32 val; + + val = readl(&ring->rt->occ); + + ring->state.occ = val & K3_RINGACC_RT_OCC_MASK; + ring->state.tdown_complete = !!(val & K3_DMARING_RT_OCC_TDOWN_COMPLETE); +} + static long k3_ringacc_ring_get_fifo_pos(struct k3_ring *ring) { return K3_RINGACC_FIFO_WINDOW_SIZE_BYTES - @@ -206,18 +265,30 @@ static void *k3_ringacc_get_elm_addr(struct k3_ring *ring, u32 idx) static int k3_ringacc_ring_push_mem(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_pop_mem(struct k3_ring *ring, void *elem); +static int k3_dmaring_fwd_pop(struct k3_ring *ring, void *elem); +static int k3_dmaring_reverse_pop(struct k3_ring *ring, void *elem); -static struct k3_ring_ops k3_ring_mode_ring_ops = { +static const struct k3_ring_ops k3_ring_mode_ring_ops = { .push_tail = k3_ringacc_ring_push_mem, .pop_head = k3_ringacc_ring_pop_mem, }; +static const struct k3_ring_ops k3_dmaring_fwd_ops = { + .push_tail = k3_ringacc_ring_push_mem, + .pop_head = k3_dmaring_fwd_pop, +}; + +static const struct k3_ring_ops k3_dmaring_reverse_ops = { + /* Reverse side of the DMA ring can only be popped by SW */ + .pop_head = k3_dmaring_reverse_pop, +}; + static int k3_ringacc_ring_push_io(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_pop_io(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_push_head_io(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_pop_tail_io(struct k3_ring *ring, void *elem); -static struct k3_ring_ops k3_ring_mode_msg_ops = { +static const struct k3_ring_ops k3_ring_mode_msg_ops = { .push_tail = k3_ringacc_ring_push_io, .push_head = k3_ringacc_ring_push_head_io, .pop_tail = k3_ringacc_ring_pop_tail_io, @@ -229,7 +300,7 @@ static int k3_ringacc_ring_push_tail_proxy(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_pop_head_proxy(struct k3_ring *ring, void *elem); static int k3_ringacc_ring_pop_tail_proxy(struct k3_ring *ring, void *elem); -static struct k3_ring_ops k3_ring_mode_proxy_ops = { +static const struct k3_ring_ops k3_ring_mode_proxy_ops = { .push_tail = k3_ringacc_ring_push_tail_proxy, .push_head = k3_ringacc_ring_push_head_proxy, .pop_tail = k3_ringacc_ring_pop_tail_proxy, @@ -245,6 +316,7 @@ static void k3_ringacc_ring_dump(struct k3_ring *ring) &ring->ring_mem_dma); dev_dbg(dev, "dump elmsize %d, size %d, mode %d, proxy_id %d\n", ring->elm_size, ring->size, ring->mode, ring->proxy_id); + dev_dbg(dev, "dump flags %08X\n", ring->flags); dev_dbg(dev, "dump ring_rt_regs: db%08x\n", readl(&ring->rt->db)); dev_dbg(dev, "dump occ%08x\n", readl(&ring->rt->occ)); @@ -264,6 +336,9 @@ struct k3_ring *k3_ringacc_request_ring(struct k3_ringacc *ringacc, mutex_lock(&ringacc->req_lock); + if (!try_module_get(ringacc->dev->driver->owner)) + goto err_module_get; + if (id == K3_RINGACC_RING_ID_ANY) { /* Request for any general purpose ring */ struct ti_sci_resource_desc *gp_rings = @@ -286,8 +361,8 @@ struct k3_ring *k3_ringacc_request_ring(struct k3_ringacc *ringacc, goto out; if (flags & K3_RINGACC_RING_USE_PROXY) { - proxy_id = find_next_zero_bit(ringacc->proxy_inuse, - ringacc->num_proxies, 0); + proxy_id = find_first_zero_bit(ringacc->proxy_inuse, + ringacc->num_proxies); if (proxy_id == ringacc->num_proxies) goto error; } @@ -308,27 +383,95 @@ out: return &ringacc->rings[id]; error: + module_put(ringacc->dev->driver->owner); + +err_module_get: mutex_unlock(&ringacc->req_lock); return NULL; } EXPORT_SYMBOL_GPL(k3_ringacc_request_ring); +static int k3_dmaring_request_dual_ring(struct k3_ringacc *ringacc, int fwd_id, + struct k3_ring **fwd_ring, + struct k3_ring **compl_ring) +{ + int ret = 0; + + /* + * DMA rings must be requested by ID, completion ring is the reverse + * side of the forward ring + */ + if (fwd_id < 0) + return -EINVAL; + + mutex_lock(&ringacc->req_lock); + + if (!try_module_get(ringacc->dev->driver->owner)) { + ret = -EINVAL; + goto err_module_get; + } + + if (test_bit(fwd_id, ringacc->rings_inuse)) { + ret = -EBUSY; + goto error; + } + + *fwd_ring = &ringacc->rings[fwd_id]; + *compl_ring = &ringacc->rings[fwd_id + ringacc->num_rings]; + set_bit(fwd_id, ringacc->rings_inuse); + ringacc->rings[fwd_id].use_count++; + dev_dbg(ringacc->dev, "Giving ring#%d\n", fwd_id); + + mutex_unlock(&ringacc->req_lock); + return 0; + +error: + module_put(ringacc->dev->driver->owner); +err_module_get: + mutex_unlock(&ringacc->req_lock); + return ret; +} + +int k3_ringacc_request_rings_pair(struct k3_ringacc *ringacc, + int fwd_id, int compl_id, + struct k3_ring **fwd_ring, + struct k3_ring **compl_ring) +{ + int ret = 0; + + if (!fwd_ring || !compl_ring) + return -EINVAL; + + if (ringacc->dma_rings) + return k3_dmaring_request_dual_ring(ringacc, fwd_id, + fwd_ring, compl_ring); + + *fwd_ring = k3_ringacc_request_ring(ringacc, fwd_id, 0); + if (!(*fwd_ring)) + return -ENODEV; + + *compl_ring = k3_ringacc_request_ring(ringacc, compl_id, 0); + if (!(*compl_ring)) { + k3_ringacc_ring_free(*fwd_ring); + ret = -ENODEV; + } + + return ret; +} +EXPORT_SYMBOL_GPL(k3_ringacc_request_rings_pair); + static void k3_ringacc_ring_reset_sci(struct k3_ring *ring) { + struct ti_sci_msg_rm_ring_cfg ring_cfg = { 0 }; struct k3_ringacc *ringacc = ring->parent; int ret; - ret = ringacc->tisci_ring_ops->config( - ringacc->tisci, - TI_SCI_MSG_VALUE_RM_RING_COUNT_VALID, - ringacc->tisci_dev_id, - ring->ring_id, - 0, - 0, - ring->size, - 0, - 0, - 0); + ring_cfg.nav_id = ringacc->tisci_dev_id; + ring_cfg.index = ring->ring_id; + ring_cfg.valid_params = TI_SCI_MSG_VALUE_RM_RING_COUNT_VALID; + ring_cfg.count = ring->size; + + ret = ringacc->tisci_ring_ops->set_cfg(ringacc->tisci, &ring_cfg); if (ret) dev_err(ringacc->dev, "TISCI reset ring fail (%d) ring_idx %d\n", ret, ring->ring_id); @@ -339,10 +482,7 @@ void k3_ringacc_ring_reset(struct k3_ring *ring) if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) return; - ring->occ = 0; - ring->free = 0; - ring->rindex = 0; - ring->windex = 0; + memset(&ring->state, 0, sizeof(ring->state)); k3_ringacc_ring_reset_sci(ring); } @@ -351,20 +491,16 @@ EXPORT_SYMBOL_GPL(k3_ringacc_ring_reset); static void k3_ringacc_ring_reconfig_qmode_sci(struct k3_ring *ring, enum k3_ring_mode mode) { + struct ti_sci_msg_rm_ring_cfg ring_cfg = { 0 }; struct k3_ringacc *ringacc = ring->parent; int ret; - ret = ringacc->tisci_ring_ops->config( - ringacc->tisci, - TI_SCI_MSG_VALUE_RM_RING_MODE_VALID, - ringacc->tisci_dev_id, - ring->ring_id, - 0, - 0, - 0, - mode, - 0, - 0); + ring_cfg.nav_id = ringacc->tisci_dev_id; + ring_cfg.index = ring->ring_id; + ring_cfg.valid_params = TI_SCI_MSG_VALUE_RM_RING_MODE_VALID; + ring_cfg.mode = mode; + + ret = ringacc->tisci_ring_ops->set_cfg(ringacc->tisci, &ring_cfg); if (ret) dev_err(ringacc->dev, "TISCI reconf qmode fail (%d) ring_idx %d\n", ret, ring->ring_id); @@ -379,7 +515,7 @@ void k3_ringacc_ring_reset_dma(struct k3_ring *ring, u32 occ) goto reset; if (!occ) - occ = readl(&ring->rt->occ); + occ = k3_ringacc_ring_read_occ(ring); if (occ) { u32 db_ring_cnt, db_ring_cnt_cur; @@ -431,20 +567,15 @@ EXPORT_SYMBOL_GPL(k3_ringacc_ring_reset_dma); static void k3_ringacc_ring_free_sci(struct k3_ring *ring) { + struct ti_sci_msg_rm_ring_cfg ring_cfg = { 0 }; struct k3_ringacc *ringacc = ring->parent; int ret; - ret = ringacc->tisci_ring_ops->config( - ringacc->tisci, - TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER, - ringacc->tisci_dev_id, - ring->ring_id, - 0, - 0, - 0, - 0, - 0, - 0); + ring_cfg.nav_id = ringacc->tisci_dev_id; + ring_cfg.index = ring->ring_id; + ring_cfg.valid_params = TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER; + + ret = ringacc->tisci_ring_ops->set_cfg(ringacc->tisci, &ring_cfg); if (ret) dev_err(ringacc->dev, "TISCI ring free fail (%d) ring_idx %d\n", ret, ring->ring_id); @@ -459,6 +590,13 @@ int k3_ringacc_ring_free(struct k3_ring *ring) ringacc = ring->parent; + /* + * DMA rings: rings shared memory and configuration, only forward ring + * is configured and reverse ring considered as slave. + */ + if (ringacc->dma_rings && (ring->flags & K3_RING_FLAG_REVERSE)) + return 0; + dev_dbg(ring->parent->dev, "flags: 0x%08x\n", ring->flags); if (!test_bit(ring->ring_id, ringacc->rings_inuse)) @@ -474,11 +612,14 @@ int k3_ringacc_ring_free(struct k3_ring *ring) k3_ringacc_ring_free_sci(ring); - dma_free_coherent(ringacc->dev, + dma_free_coherent(ring->dma_dev, ring->size * (4 << ring->elm_size), ring->ring_mem_virt, ring->ring_mem_dma); ring->flags = 0; ring->ops = NULL; + ring->dma_dev = NULL; + ring->asel = 0; + if (ring->proxy_id != K3_RINGACC_PROXY_NOT_USED) { clear_bit(ring->proxy_id, ringacc->proxy_inuse); ring->proxy = NULL; @@ -488,6 +629,8 @@ int k3_ringacc_ring_free(struct k3_ring *ring) no_init: clear_bit(ring->ring_id, ringacc->rings_inuse); + module_put(ringacc->dev->driver->owner); + out: mutex_unlock(&ringacc->req_lock); return 0; @@ -519,7 +662,7 @@ int k3_ringacc_get_ring_irq_num(struct k3_ring *ring) if (!ring) return -EINVAL; - irq_num = ti_sci_inta_msi_get_virq(ring->parent->dev, ring->ring_id); + irq_num = msi_get_virq(ring->parent->dev, ring->ring_id); if (irq_num <= 0) irq_num = -EINVAL; return irq_num; @@ -528,39 +671,128 @@ EXPORT_SYMBOL_GPL(k3_ringacc_get_ring_irq_num); static int k3_ringacc_ring_cfg_sci(struct k3_ring *ring) { + struct ti_sci_msg_rm_ring_cfg ring_cfg = { 0 }; struct k3_ringacc *ringacc = ring->parent; - u32 ring_idx; int ret; if (!ringacc->tisci) return -EINVAL; - ring_idx = ring->ring_id; - ret = ringacc->tisci_ring_ops->config( - ringacc->tisci, - TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER, - ringacc->tisci_dev_id, - ring_idx, - lower_32_bits(ring->ring_mem_dma), - upper_32_bits(ring->ring_mem_dma), - ring->size, - ring->mode, - ring->elm_size, - 0); + ring_cfg.nav_id = ringacc->tisci_dev_id; + ring_cfg.index = ring->ring_id; + ring_cfg.valid_params = TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER; + ring_cfg.addr_lo = lower_32_bits(ring->ring_mem_dma); + ring_cfg.addr_hi = upper_32_bits(ring->ring_mem_dma); + ring_cfg.count = ring->size; + ring_cfg.mode = ring->mode; + ring_cfg.size = ring->elm_size; + ring_cfg.asel = ring->asel; + + ret = ringacc->tisci_ring_ops->set_cfg(ringacc->tisci, &ring_cfg); if (ret) dev_err(ringacc->dev, "TISCI config ring fail (%d) ring_idx %d\n", - ret, ring_idx); + ret, ring->ring_id); return ret; } +static int k3_dmaring_cfg(struct k3_ring *ring, struct k3_ring_cfg *cfg) +{ + struct k3_ringacc *ringacc; + struct k3_ring *reverse_ring; + int ret = 0; + + if (cfg->elm_size != K3_RINGACC_RING_ELSIZE_8 || + cfg->mode != K3_RINGACC_RING_MODE_RING || + cfg->size & ~K3_DMARING_CFG_RING_SIZE_ELCNT_MASK) + return -EINVAL; + + ringacc = ring->parent; + + /* + * DMA rings: rings shared memory and configuration, only forward ring + * is configured and reverse ring considered as slave. + */ + if (ringacc->dma_rings && (ring->flags & K3_RING_FLAG_REVERSE)) + return 0; + + if (!test_bit(ring->ring_id, ringacc->rings_inuse)) + return -EINVAL; + + ring->size = cfg->size; + ring->elm_size = cfg->elm_size; + ring->mode = cfg->mode; + ring->asel = cfg->asel; + ring->dma_dev = cfg->dma_dev; + if (!ring->dma_dev) { + dev_warn(ringacc->dev, "dma_dev is not provided for ring%d\n", + ring->ring_id); + ring->dma_dev = ringacc->dev; + } + + memset(&ring->state, 0, sizeof(ring->state)); + + ring->ops = &k3_dmaring_fwd_ops; + + ring->ring_mem_virt = dma_alloc_coherent(ring->dma_dev, + ring->size * (4 << ring->elm_size), + &ring->ring_mem_dma, GFP_KERNEL); + if (!ring->ring_mem_virt) { + dev_err(ringacc->dev, "Failed to alloc ring mem\n"); + ret = -ENOMEM; + goto err_free_ops; + } + + ret = k3_ringacc_ring_cfg_sci(ring); + if (ret) + goto err_free_mem; + + ring->flags |= K3_RING_FLAG_BUSY; + + k3_ringacc_ring_dump(ring); + + /* DMA rings: configure reverse ring */ + reverse_ring = &ringacc->rings[ring->ring_id + ringacc->num_rings]; + reverse_ring->size = cfg->size; + reverse_ring->elm_size = cfg->elm_size; + reverse_ring->mode = cfg->mode; + reverse_ring->asel = cfg->asel; + memset(&reverse_ring->state, 0, sizeof(reverse_ring->state)); + reverse_ring->ops = &k3_dmaring_reverse_ops; + + reverse_ring->ring_mem_virt = ring->ring_mem_virt; + reverse_ring->ring_mem_dma = ring->ring_mem_dma; + reverse_ring->flags |= K3_RING_FLAG_BUSY; + k3_ringacc_ring_dump(reverse_ring); + + return 0; + +err_free_mem: + dma_free_coherent(ring->dma_dev, + ring->size * (4 << ring->elm_size), + ring->ring_mem_virt, + ring->ring_mem_dma); +err_free_ops: + ring->ops = NULL; + ring->proxy = NULL; + ring->dma_dev = NULL; + ring->asel = 0; + return ret; +} + int k3_ringacc_ring_cfg(struct k3_ring *ring, struct k3_ring_cfg *cfg) { - struct k3_ringacc *ringacc = ring->parent; + struct k3_ringacc *ringacc; int ret = 0; if (!ring || !cfg) return -EINVAL; + + ringacc = ring->parent; + + if (ringacc->dma_rings) + return k3_dmaring_cfg(ring, cfg); + if (cfg->elm_size > K3_RINGACC_RING_ELSIZE_256 || cfg->mode >= K3_RINGACC_RING_MODE_INVALID || cfg->size & ~K3_RINGACC_CFG_RING_SIZE_ELCNT_MASK || @@ -590,10 +822,7 @@ int k3_ringacc_ring_cfg(struct k3_ring *ring, struct k3_ring_cfg *cfg) ring->size = cfg->size; ring->elm_size = cfg->elm_size; ring->mode = cfg->mode; - ring->occ = 0; - ring->free = 0; - ring->rindex = 0; - ring->windex = 0; + memset(&ring->state, 0, sizeof(ring->state)); if (ring->proxy_id != K3_RINGACC_PROXY_NOT_USED) ring->proxy = ringacc->proxy_target_base + @@ -602,8 +831,12 @@ int k3_ringacc_ring_cfg(struct k3_ring *ring, struct k3_ring_cfg *cfg) switch (ring->mode) { case K3_RINGACC_RING_MODE_RING: ring->ops = &k3_ring_mode_ring_ops; + ring->dma_dev = cfg->dma_dev; + if (!ring->dma_dev) + ring->dma_dev = ringacc->dev; break; case K3_RINGACC_RING_MODE_MESSAGE: + ring->dma_dev = ringacc->dev; if (ring->proxy) ring->ops = &k3_ring_mode_proxy_ops; else @@ -613,11 +846,11 @@ int k3_ringacc_ring_cfg(struct k3_ring *ring, struct k3_ring_cfg *cfg) ring->ops = NULL; ret = -EINVAL; goto err_free_proxy; - }; + } - ring->ring_mem_virt = dma_alloc_coherent(ringacc->dev, - ring->size * (4 << ring->elm_size), - &ring->ring_mem_dma, GFP_KERNEL); + ring->ring_mem_virt = dma_alloc_coherent(ring->dma_dev, + ring->size * (4 << ring->elm_size), + &ring->ring_mem_dma, GFP_KERNEL); if (!ring->ring_mem_virt) { dev_err(ringacc->dev, "Failed to alloc ring mem\n"); ret = -ENOMEM; @@ -638,12 +871,13 @@ int k3_ringacc_ring_cfg(struct k3_ring *ring, struct k3_ring_cfg *cfg) return 0; err_free_mem: - dma_free_coherent(ringacc->dev, + dma_free_coherent(ring->dma_dev, ring->size * (4 << ring->elm_size), ring->ring_mem_virt, ring->ring_mem_dma); err_free_ops: ring->ops = NULL; + ring->dma_dev = NULL; err_free_proxy: ring->proxy = NULL; return ret; @@ -664,10 +898,10 @@ u32 k3_ringacc_ring_get_free(struct k3_ring *ring) if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) return -EINVAL; - if (!ring->free) - ring->free = ring->size - readl(&ring->rt->occ); + if (!ring->state.free) + ring->state.free = ring->size - k3_ringacc_ring_read_occ(ring); - return ring->free; + return ring->state.free; } EXPORT_SYMBOL_GPL(k3_ringacc_ring_get_free); @@ -676,7 +910,7 @@ u32 k3_ringacc_ring_get_occ(struct k3_ring *ring) if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) return -EINVAL; - return readl(&ring->rt->occ); + return k3_ringacc_ring_read_occ(ring); } EXPORT_SYMBOL_GPL(k3_ringacc_ring_get_occ); @@ -738,7 +972,7 @@ static int k3_ringacc_ring_access_proxy(struct k3_ring *ring, void *elem, "proxy:memcpy_fromio(x): --> ptr(%p), mode:%d\n", ptr, access_mode); memcpy_fromio(elem, ptr, (4 << ring->elm_size)); - ring->occ--; + ring->state.occ--; break; case K3_RINGACC_ACCESS_MODE_PUSH_TAIL: case K3_RINGACC_ACCESS_MODE_PUSH_HEAD: @@ -746,14 +980,14 @@ static int k3_ringacc_ring_access_proxy(struct k3_ring *ring, void *elem, "proxy:memcpy_toio(x): --> ptr(%p), mode:%d\n", ptr, access_mode); memcpy_toio(ptr, elem, (4 << ring->elm_size)); - ring->free--; + ring->state.free--; break; default: return -EINVAL; } - dev_dbg(ring->parent->dev, "proxy: free%d occ%d\n", ring->free, - ring->occ); + dev_dbg(ring->parent->dev, "proxy: free%d occ%d\n", ring->state.free, + ring->state.occ); return 0; } @@ -808,7 +1042,7 @@ static int k3_ringacc_ring_access_io(struct k3_ring *ring, void *elem, "memcpy_fromio(x): --> ptr(%p), mode:%d\n", ptr, access_mode); memcpy_fromio(elem, ptr, (4 << ring->elm_size)); - ring->occ--; + ring->state.occ--; break; case K3_RINGACC_ACCESS_MODE_PUSH_TAIL: case K3_RINGACC_ACCESS_MODE_PUSH_HEAD: @@ -816,14 +1050,15 @@ static int k3_ringacc_ring_access_io(struct k3_ring *ring, void *elem, "memcpy_toio(x): --> ptr(%p), mode:%d\n", ptr, access_mode); memcpy_toio(ptr, elem, (4 << ring->elm_size)); - ring->free--; + ring->state.free--; break; default: return -EINVAL; } - dev_dbg(ring->parent->dev, "free%d index%d occ%d index%d\n", ring->free, - ring->windex, ring->occ, ring->rindex); + dev_dbg(ring->parent->dev, "free%d index%d occ%d index%d\n", + ring->state.free, ring->state.windex, ring->state.occ, + ring->state.rindex); return 0; } @@ -851,20 +1086,91 @@ static int k3_ringacc_ring_pop_tail_io(struct k3_ring *ring, void *elem) K3_RINGACC_ACCESS_MODE_POP_HEAD); } +/* + * The element is 48 bits of address + ASEL bits in the ring. + * ASEL is used by the DMAs and should be removed for the kernel as it is not + * part of the physical memory address. + */ +static void k3_dmaring_remove_asel_from_elem(u64 *elem) +{ + *elem &= GENMASK_ULL(K3_ADDRESS_ASEL_SHIFT - 1, 0); +} + +static int k3_dmaring_fwd_pop(struct k3_ring *ring, void *elem) +{ + void *elem_ptr; + u32 elem_idx; + + /* + * DMA rings: forward ring is always tied DMA channel and HW does not + * maintain any state data required for POP operation and its unknown + * how much elements were consumed by HW. So, to actually + * do POP, the read pointer has to be recalculated every time. + */ + ring->state.occ = k3_ringacc_ring_read_occ(ring); + if (ring->state.windex >= ring->state.occ) + elem_idx = ring->state.windex - ring->state.occ; + else + elem_idx = ring->size - (ring->state.occ - ring->state.windex); + + elem_ptr = k3_ringacc_get_elm_addr(ring, elem_idx); + memcpy(elem, elem_ptr, (4 << ring->elm_size)); + k3_dmaring_remove_asel_from_elem(elem); + + ring->state.occ--; + writel(-1, &ring->rt->db); + + dev_dbg(ring->parent->dev, "%s: occ%d Windex%d Rindex%d pos_ptr%px\n", + __func__, ring->state.occ, ring->state.windex, elem_idx, + elem_ptr); + return 0; +} + +static int k3_dmaring_reverse_pop(struct k3_ring *ring, void *elem) +{ + void *elem_ptr; + + elem_ptr = k3_ringacc_get_elm_addr(ring, ring->state.rindex); + + if (ring->state.occ) { + memcpy(elem, elem_ptr, (4 << ring->elm_size)); + k3_dmaring_remove_asel_from_elem(elem); + + ring->state.rindex = (ring->state.rindex + 1) % ring->size; + ring->state.occ--; + writel(-1 & K3_DMARING_RT_DB_ENTRY_MASK, &ring->rt->db); + } else if (ring->state.tdown_complete) { + dma_addr_t *value = elem; + + *value = CPPI5_TDCM_MARKER; + writel(K3_DMARING_RT_DB_TDOWN_ACK, &ring->rt->db); + ring->state.tdown_complete = false; + } + + dev_dbg(ring->parent->dev, "%s: occ%d index%d pos_ptr%px\n", + __func__, ring->state.occ, ring->state.rindex, elem_ptr); + return 0; +} + static int k3_ringacc_ring_push_mem(struct k3_ring *ring, void *elem) { void *elem_ptr; - elem_ptr = k3_ringacc_get_elm_addr(ring, ring->windex); + elem_ptr = k3_ringacc_get_elm_addr(ring, ring->state.windex); memcpy(elem_ptr, elem, (4 << ring->elm_size)); + if (ring->parent->dma_rings) { + u64 *addr = elem_ptr; - ring->windex = (ring->windex + 1) % ring->size; - ring->free--; + *addr |= ((u64)ring->asel << K3_ADDRESS_ASEL_SHIFT); + } + + ring->state.windex = (ring->state.windex + 1) % ring->size; + ring->state.free--; writel(1, &ring->rt->db); dev_dbg(ring->parent->dev, "ring_push_mem: free%d index%d\n", - ring->free, ring->windex); + ring->state.free, ring->state.windex); return 0; } @@ -873,16 +1179,16 @@ static int k3_ringacc_ring_pop_mem(struct k3_ring *ring, void *elem) { void *elem_ptr; - elem_ptr = k3_ringacc_get_elm_addr(ring, ring->rindex); + elem_ptr = k3_ringacc_get_elm_addr(ring, ring->state.rindex); memcpy(elem, elem_ptr, (4 << ring->elm_size)); - ring->rindex = (ring->rindex + 1) % ring->size; - ring->occ--; + ring->state.rindex = (ring->state.rindex + 1) % ring->size; + ring->state.occ--; writel(-1, &ring->rt->db); dev_dbg(ring->parent->dev, "ring_pop_mem: occ%d index%d pos_ptr%p\n", - ring->occ, ring->rindex, elem_ptr); + ring->state.occ, ring->state.rindex, elem_ptr); return 0; } @@ -893,8 +1199,8 @@ int k3_ringacc_ring_push(struct k3_ring *ring, void *elem) if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) return -EINVAL; - dev_dbg(ring->parent->dev, "ring_push: free%d index%d\n", ring->free, - ring->windex); + dev_dbg(ring->parent->dev, "ring_push: free%d index%d\n", + ring->state.free, ring->state.windex); if (k3_ringacc_ring_is_full(ring)) return -ENOMEM; @@ -914,7 +1220,7 @@ int k3_ringacc_ring_push_head(struct k3_ring *ring, void *elem) return -EINVAL; dev_dbg(ring->parent->dev, "ring_push_head: free%d index%d\n", - ring->free, ring->windex); + ring->state.free, ring->state.windex); if (k3_ringacc_ring_is_full(ring)) return -ENOMEM; @@ -933,13 +1239,13 @@ int k3_ringacc_ring_pop(struct k3_ring *ring, void *elem) if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) return -EINVAL; - if (!ring->occ) - ring->occ = k3_ringacc_ring_get_occ(ring); + if (!ring->state.occ) + k3_ringacc_ring_update_occ(ring); - dev_dbg(ring->parent->dev, "ring_pop: occ%d index%d\n", ring->occ, - ring->rindex); + dev_dbg(ring->parent->dev, "ring_pop: occ%d index%d\n", ring->state.occ, + ring->state.rindex); - if (!ring->occ) + if (!ring->state.occ && !ring->state.tdown_complete) return -ENODATA; if (ring->ops && ring->ops->pop_head) @@ -956,13 +1262,13 @@ int k3_ringacc_ring_pop_tail(struct k3_ring *ring, void *elem) if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) return -EINVAL; - if (!ring->occ) - ring->occ = k3_ringacc_ring_get_occ(ring); + if (!ring->state.occ) + k3_ringacc_ring_update_occ(ring); - dev_dbg(ring->parent->dev, "ring_pop_tail: occ%d index%d\n", ring->occ, - ring->rindex); + dev_dbg(ring->parent->dev, "ring_pop_tail: occ%d index%d\n", + ring->state.occ, ring->state.rindex); - if (!ring->occ) + if (!ring->state.occ) return -ENODATA; if (ring->ops && ring->ops->pop_tail) @@ -985,7 +1291,7 @@ struct k3_ringacc *of_k3_ringacc_get_by_phandle(struct device_node *np, mutex_lock(&k3_ringacc_list_lock); list_for_each_entry(entry, &k3_ringacc_list, list) - if (entry->dev->of_node == ringacc_np) { + if (device_match_of_node(entry->dev, ringacc_np)) { ringacc = entry; break; } @@ -1014,9 +1320,6 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc) return ret; } - ringacc->dma_ring_reset_quirk = - of_property_read_bool(node, "ti,dma-ring-reset-quirk"); - ringacc->tisci = ti_sci_get_by_phandle(node, "ti,sci"); if (IS_ERR(ringacc->tisci)) { ret = PTR_ERR(ringacc->tisci); @@ -1047,50 +1350,56 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc) ringacc->rm_gp_range); } -static int k3_ringacc_probe(struct platform_device *pdev) +static const struct k3_ringacc_soc_data k3_ringacc_soc_data_sr1 = { + .dma_ring_reset_quirk = 1, +}; + +static const struct soc_device_attribute k3_ringacc_socinfo[] = { + { .family = "AM65X", + .revision = "SR1.0", + .data = &k3_ringacc_soc_data_sr1 + }, + {/* sentinel */} +}; + +static int k3_ringacc_init(struct platform_device *pdev, + struct k3_ringacc *ringacc) { - struct k3_ringacc *ringacc; + const struct soc_device_attribute *soc; void __iomem *base_fifo, *base_rt; struct device *dev = &pdev->dev; - struct resource *res; int ret, i; - ringacc = devm_kzalloc(dev, sizeof(*ringacc), GFP_KERNEL); - if (!ringacc) - return -ENOMEM; - - ringacc->dev = dev; - mutex_init(&ringacc->req_lock); - - dev->msi_domain = of_msi_get_domain(dev, dev->of_node, + dev->msi.domain = of_msi_get_domain(dev, dev->of_node, DOMAIN_BUS_TI_SCI_INTA_MSI); - if (!dev->msi_domain) { - dev_err(dev, "Failed to get MSI domain\n"); + if (!dev->msi.domain) return -EPROBE_DEFER; - } ret = k3_ringacc_probe_dt(ringacc); if (ret) return ret; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt"); - base_rt = devm_ioremap_resource(dev, res); + soc = soc_device_match(k3_ringacc_socinfo); + if (soc && soc->data) { + const struct k3_ringacc_soc_data *soc_data = soc->data; + + ringacc->dma_ring_reset_quirk = soc_data->dma_ring_reset_quirk; + } + + base_rt = devm_platform_ioremap_resource_byname(pdev, "rt"); if (IS_ERR(base_rt)) return PTR_ERR(base_rt); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fifos"); - base_fifo = devm_ioremap_resource(dev, res); + base_fifo = devm_platform_ioremap_resource_byname(pdev, "fifos"); if (IS_ERR(base_fifo)) return PTR_ERR(base_fifo); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "proxy_gcfg"); - ringacc->proxy_gcfg = devm_ioremap_resource(dev, res); + ringacc->proxy_gcfg = devm_platform_ioremap_resource_byname(pdev, "proxy_gcfg"); if (IS_ERR(ringacc->proxy_gcfg)) return PTR_ERR(ringacc->proxy_gcfg); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "proxy_target"); - ringacc->proxy_target_base = devm_ioremap_resource(dev, res); + ringacc->proxy_target_base = devm_platform_ioremap_resource_byname(pdev, + "proxy_target"); if (IS_ERR(ringacc->proxy_target_base)) return PTR_ERR(ringacc->proxy_target_base); @@ -1101,12 +1410,10 @@ static int k3_ringacc_probe(struct platform_device *pdev) sizeof(*ringacc->rings) * ringacc->num_rings, GFP_KERNEL); - ringacc->rings_inuse = devm_kcalloc(dev, - BITS_TO_LONGS(ringacc->num_rings), - sizeof(unsigned long), GFP_KERNEL); - ringacc->proxy_inuse = devm_kcalloc(dev, - BITS_TO_LONGS(ringacc->num_proxies), - sizeof(unsigned long), GFP_KERNEL); + ringacc->rings_inuse = devm_bitmap_zalloc(dev, ringacc->num_rings, + GFP_KERNEL); + ringacc->proxy_inuse = devm_bitmap_zalloc(dev, ringacc->num_proxies, + GFP_KERNEL); if (!ringacc->rings || !ringacc->rings_inuse || !ringacc->proxy_inuse) return -ENOMEM; @@ -1120,14 +1427,9 @@ static int k3_ringacc_probe(struct platform_device *pdev) ringacc->rings[i].ring_id = i; ringacc->rings[i].proxy_id = K3_RINGACC_PROXY_NOT_USED; } - dev_set_drvdata(dev, ringacc); ringacc->tisci_ring_ops = &ringacc->tisci->ops.rm_ring_ops; - mutex_lock(&k3_ringacc_list_lock); - list_add_tail(&ringacc->list, &k3_ringacc_list); - mutex_unlock(&k3_ringacc_list_lock); - dev_info(dev, "Ring Accelerator probed rings:%u, gp-rings[%u,%u] sci-dev-id:%u\n", ringacc->num_rings, ringacc->rm_gp_range->desc[0].start, @@ -1137,21 +1439,138 @@ static int k3_ringacc_probe(struct platform_device *pdev) ringacc->dma_ring_reset_quirk ? "enabled" : "disabled"); dev_info(dev, "RA Proxy rev. %08x, num_proxies:%u\n", readl(&ringacc->proxy_gcfg->revision), ringacc->num_proxies); + return 0; } +struct ringacc_match_data { + struct k3_ringacc_ops ops; +}; + +static struct ringacc_match_data k3_ringacc_data = { + .ops = { + .init = k3_ringacc_init, + }, +}; + /* Match table for of_platform binding */ static const struct of_device_id k3_ringacc_of_match[] = { - { .compatible = "ti,am654-navss-ringacc", }, + { .compatible = "ti,am654-navss-ringacc", .data = &k3_ringacc_data, }, {}, }; +MODULE_DEVICE_TABLE(of, k3_ringacc_of_match); + +struct k3_ringacc *k3_ringacc_dmarings_init(struct platform_device *pdev, + struct k3_ringacc_init_data *data) +{ + struct device *dev = &pdev->dev; + struct k3_ringacc *ringacc; + void __iomem *base_rt; + int i; + + ringacc = devm_kzalloc(dev, sizeof(*ringacc), GFP_KERNEL); + if (!ringacc) + return ERR_PTR(-ENOMEM); + + ringacc->dev = dev; + ringacc->dma_rings = true; + ringacc->num_rings = data->num_rings; + ringacc->tisci = data->tisci; + ringacc->tisci_dev_id = data->tisci_dev_id; + + mutex_init(&ringacc->req_lock); + + base_rt = devm_platform_ioremap_resource_byname(pdev, "ringrt"); + if (IS_ERR(base_rt)) + return ERR_CAST(base_rt); + + ringacc->rings = devm_kzalloc(dev, + sizeof(*ringacc->rings) * + ringacc->num_rings * 2, + GFP_KERNEL); + ringacc->rings_inuse = devm_bitmap_zalloc(dev, ringacc->num_rings, + GFP_KERNEL); + + if (!ringacc->rings || !ringacc->rings_inuse) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < ringacc->num_rings; i++) { + struct k3_ring *ring = &ringacc->rings[i]; + + ring->rt = base_rt + K3_DMARING_RT_REGS_STEP * i; + ring->parent = ringacc; + ring->ring_id = i; + ring->proxy_id = K3_RINGACC_PROXY_NOT_USED; + + ring = &ringacc->rings[ringacc->num_rings + i]; + ring->rt = base_rt + K3_DMARING_RT_REGS_STEP * i + + K3_DMARING_RT_REGS_REVERSE_OFS; + ring->parent = ringacc; + ring->ring_id = i; + ring->proxy_id = K3_RINGACC_PROXY_NOT_USED; + ring->flags = K3_RING_FLAG_REVERSE; + } + + ringacc->tisci_ring_ops = &ringacc->tisci->ops.rm_ring_ops; + + dev_info(dev, "Number of rings: %u\n", ringacc->num_rings); + + return ringacc; +} +EXPORT_SYMBOL_GPL(k3_ringacc_dmarings_init); + +static int k3_ringacc_probe(struct platform_device *pdev) +{ + const struct ringacc_match_data *match_data; + struct device *dev = &pdev->dev; + struct k3_ringacc *ringacc; + int ret; + + match_data = of_device_get_match_data(&pdev->dev); + if (!match_data) + return -ENODEV; + + ringacc = devm_kzalloc(dev, sizeof(*ringacc), GFP_KERNEL); + if (!ringacc) + return -ENOMEM; + + ringacc->dev = dev; + mutex_init(&ringacc->req_lock); + ringacc->ops = &match_data->ops; + + ret = ringacc->ops->init(pdev, ringacc); + if (ret) + return ret; + + dev_set_drvdata(dev, ringacc); + + mutex_lock(&k3_ringacc_list_lock); + list_add_tail(&ringacc->list, &k3_ringacc_list); + mutex_unlock(&k3_ringacc_list_lock); + + return 0; +} + +static void k3_ringacc_remove(struct platform_device *pdev) +{ + struct k3_ringacc *ringacc = dev_get_drvdata(&pdev->dev); + + mutex_lock(&k3_ringacc_list_lock); + list_del(&ringacc->list); + mutex_unlock(&k3_ringacc_list_lock); +} static struct platform_driver k3_ringacc_driver = { .probe = k3_ringacc_probe, + .remove = k3_ringacc_remove, .driver = { .name = "k3-ringacc", .of_match_table = k3_ringacc_of_match, .suppress_bind_attrs = true, }, }; -builtin_platform_driver(k3_ringacc_driver); +module_platform_driver(k3_ringacc_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TI Ringacc driver for K3 SOCs"); +MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>"); |
