static struct mv_cesa_tdma_desc * mv_cesa_dma_add_desc(struct mv_cesa_tdma_chain *chain, gfp_t flags) { struct mv_cesa_tdma_desc *new_tdma = NULL; dma_addr_t dma_handle; new_tdma = dma_pool_zalloc(cesa_dev->dma->tdma_desc_pool, flags, &dma_handle); if (!new_tdma) return ERR_PTR(-ENOMEM); new_tdma->cur_dma = dma_handle; if (chain->last) { chain->last->next_dma = cpu_to_le32(dma_handle); chain->last->next = new_tdma; } else { chain->first = new_tdma; } chain->last = new_tdma; return new_tdma; }
static int flexrm_startup(struct mbox_chan *chan) { u64 d; u32 val, off; int ret = 0; dma_addr_t next_addr; struct flexrm_ring *ring = chan->con_priv; /* Allocate BD memory */ ring->bd_base = dma_pool_alloc(ring->mbox->bd_pool, GFP_KERNEL, &ring->bd_dma_base); if (!ring->bd_base) { dev_err(ring->mbox->dev, "can't allocate BD memory for ring%d\n", ring->num); ret = -ENOMEM; goto fail; } /* Configure next table pointer entries in BD memory */ for (off = 0; off < RING_BD_SIZE; off += RING_DESC_SIZE) { next_addr = off + RING_DESC_SIZE; if (next_addr == RING_BD_SIZE) next_addr = 0; next_addr += ring->bd_dma_base; if (RING_BD_ALIGN_CHECK(next_addr)) d = flexrm_next_table_desc(RING_BD_TOGGLE_VALID(off), next_addr); else d = flexrm_null_desc(RING_BD_TOGGLE_INVALID(off)); flexrm_write_desc(ring->bd_base + off, d); } /* Allocate completion memory */ ring->cmpl_base = dma_pool_zalloc(ring->mbox->cmpl_pool, GFP_KERNEL, &ring->cmpl_dma_base); if (!ring->cmpl_base) { dev_err(ring->mbox->dev, "can't allocate completion memory for ring%d\n", ring->num); ret = -ENOMEM; goto fail_free_bd_memory; } /* Request IRQ */ if (ring->irq == UINT_MAX) { dev_err(ring->mbox->dev, "ring%d IRQ not available\n", ring->num); ret = -ENODEV; goto fail_free_cmpl_memory; } ret = request_threaded_irq(ring->irq, flexrm_irq_event, flexrm_irq_thread, 0, dev_name(ring->mbox->dev), ring); if (ret) { dev_err(ring->mbox->dev, "failed to request ring%d IRQ\n", ring->num); goto fail_free_cmpl_memory; } ring->irq_requested = true; /* Set IRQ affinity hint */ ring->irq_aff_hint = CPU_MASK_NONE; val = ring->mbox->num_rings; val = (num_online_cpus() < val) ? val / num_online_cpus() : 1; cpumask_set_cpu((ring->num / val) % num_online_cpus(), &ring->irq_aff_hint); ret = irq_set_affinity_hint(ring->irq, &ring->irq_aff_hint); if (ret) { dev_err(ring->mbox->dev, "failed to set IRQ affinity hint for ring%d\n", ring->num); goto fail_free_irq; } /* Disable/inactivate ring */ writel_relaxed(0x0, ring->regs + RING_CONTROL); /* Program BD start address */ val = BD_START_ADDR_VALUE(ring->bd_dma_base); writel_relaxed(val, ring->regs + RING_BD_START_ADDR); /* BD write pointer will be same as HW write pointer */ ring->bd_write_offset = readl_relaxed(ring->regs + RING_BD_WRITE_PTR); ring->bd_write_offset *= RING_DESC_SIZE; /* Program completion start address */ val = CMPL_START_ADDR_VALUE(ring->cmpl_dma_base); writel_relaxed(val, ring->regs + RING_CMPL_START_ADDR); /* Completion read pointer will be same as HW write pointer */ ring->cmpl_read_offset = readl_relaxed(ring->regs + RING_CMPL_WRITE_PTR); ring->cmpl_read_offset *= RING_DESC_SIZE; /* Read ring Tx, Rx, and Outstanding counts to clear */ readl_relaxed(ring->regs + RING_NUM_REQ_RECV_LS); readl_relaxed(ring->regs + RING_NUM_REQ_RECV_MS); readl_relaxed(ring->regs + RING_NUM_REQ_TRANS_LS); readl_relaxed(ring->regs + RING_NUM_REQ_TRANS_MS); readl_relaxed(ring->regs + RING_NUM_REQ_OUTSTAND); /* Configure RING_MSI_CONTROL */ val = 0; val |= (ring->msi_timer_val << MSI_TIMER_VAL_SHIFT); val |= BIT(MSI_ENABLE_SHIFT); val |= (ring->msi_count_threshold & MSI_COUNT_MASK) << MSI_COUNT_SHIFT; writel_relaxed(val, ring->regs + RING_MSI_CONTROL); /* Enable/activate ring */ val = BIT(CONTROL_ACTIVE_SHIFT); writel_relaxed(val, ring->regs + RING_CONTROL); /* Reset stats to zero */ atomic_set(&ring->msg_send_count, 0); atomic_set(&ring->msg_cmpl_count, 0); return 0; fail_free_irq: free_irq(ring->irq, ring); ring->irq_requested = false; fail_free_cmpl_memory: dma_pool_free(ring->mbox->cmpl_pool, ring->cmpl_base, ring->cmpl_dma_base); ring->cmpl_base = NULL; fail_free_bd_memory: dma_pool_free(ring->mbox->bd_pool, ring->bd_base, ring->bd_dma_base); ring->bd_base = NULL; fail: return ret; }