/* * Descriptors queue size. With 32 bytes descriptors, up to 2^14 * descriptors are allowed, with 128 bytes descriptors, up to 2^12 * descriptors are allowed. This driver uses 128 bytes descriptors, * but experimentation has shown that a set of 1024 descriptors is * sufficient to reach a good level of performance.
*/ #define MV_XOR_V2_DESC_NUM 1024
/* * Threshold values for descriptors and timeout, determined by * experimentation as giving a good level of performance.
*/ #define MV_XOR_V2_DONE_IMSG_THRD 0x14 #define MV_XOR_V2_TIMER_THRD 0xB0
/** * struct mv_xor_v2_descriptor - DMA HW descriptor * @desc_id: used by S/W and is not affected by H/W. * @flags: error and status flags * @crc32_result: CRC32 calculation result * @desc_ctrl: operation mode and control flags * @buff_size: amount of bytes to be processed * @fill_pattern_src_addr: Fill-Pattern or Source-Address and * AW-Attributes * @data_buff_addr: Source (and might be RAID6 destination) * addresses of data buffers in RAID5 and RAID6 * @reserved: reserved
*/ struct mv_xor_v2_descriptor {
u16 desc_id;
u16 flags;
u32 crc32_result;
u32 desc_ctrl;
/** * struct mv_xor_v2_device - implements a xor device * @lock: lock for the engine * @clk: reference to the 'core' clock * @reg_clk: reference to the 'reg' clock * @dma_base: memory mapped DMA register base * @glob_base: memory mapped global register base * @irq_tasklet: tasklet used for IRQ handling call-backs * @free_sw_desc: linked list of free SW descriptors * @dmadev: dma device * @dmachan: dma channel * @hw_desq: HW descriptors queue * @hw_desq_virt: virtual address of DESCQ * @sw_desq: SW descriptors queue * @desc_size: HW descriptor size * @npendings: number of pending descriptors (for which tx_submit has * @hw_queue_idx: HW queue index * @irq: The Linux interrupt number * been called, but not yet issue_pending)
*/ struct mv_xor_v2_device {
spinlock_t lock; void __iomem *dma_base; void __iomem *glob_base; struct clk *clk; struct clk *reg_clk; struct tasklet_struct irq_tasklet; struct list_head free_sw_desc; struct dma_device dmadev; struct dma_chan dmachan;
dma_addr_t hw_desq; struct mv_xor_v2_descriptor *hw_desq_virt; struct mv_xor_v2_sw_desc *sw_desq; int desc_size; unsignedint npendings; unsignedint hw_queue_idx; unsignedint irq;
};
/** * struct mv_xor_v2_sw_desc - implements a xor SW descriptor * @idx: descriptor index * @async_tx: support for the async_tx api * @hw_desc: associated HW descriptor * @free_list: node of the free SW descriprots list
*/ struct mv_xor_v2_sw_desc { int idx; struct dma_async_tx_descriptor async_tx; struct mv_xor_v2_descriptor hw_desc; struct list_head free_list;
};
/* * Fill the data buffers to a HW descriptor
*/ staticvoid mv_xor_v2_set_data_buffers(struct mv_xor_v2_device *xor_dev, struct mv_xor_v2_descriptor *desc,
dma_addr_t src, int index)
{ int arr_index = ((index >> 1) * 3);
/* * Fill the buffer's addresses to the descriptor. * * The format of the buffers address for 2 sequential buffers * X and X + 1: * * First word: Buffer-DX-Address-Low[31:0] * Second word: Buffer-DX+1-Address-Low[31:0] * Third word: DX+1-Buffer-Address-High[47:32] [31:16] * DX-Buffer-Address-High[47:32] [15:0]
*/ if ((index & 0x1) == 0) {
desc->data_buff_addr[arr_index] = lower_32_bits(src);
/* * notify the engine of new descriptors, and update the available index.
*/ staticvoid mv_xor_v2_add_desc_to_desq(struct mv_xor_v2_device *xor_dev, int num_of_desc)
{ /* write the number of new descriptors in the DESQ. */
writel(num_of_desc, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ADD_OFF);
}
/* * free HW descriptors
*/ staticvoid mv_xor_v2_free_desc_from_desq(struct mv_xor_v2_device *xor_dev, int num_of_desc)
{ /* write the number of new descriptors in the DESQ. */
writel(num_of_desc, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_DEALLOC_OFF);
}
/* * Set descriptor size * Return the HW descriptor size in bytes
*/ staticint mv_xor_v2_set_desc_size(struct mv_xor_v2_device *xor_dev)
{
writel(MV_XOR_V2_DMA_DESQ_CTRL_128B,
xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_CTRL_OFF);
return MV_XOR_V2_EXT_DESC_SIZE;
}
/* * Set the IMSG threshold
*/ staticinline void mv_xor_v2_enable_imsg_thrd(struct mv_xor_v2_device *xor_dev)
{
u32 reg;
/* Configure threshold of number of descriptors, and enable timer */
reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
reg &= ~MV_XOR_V2_DMA_IMSG_THRD_MASK;
reg |= MV_XOR_V2_DONE_IMSG_THRD;
reg |= MV_XOR_V2_DMA_IMSG_TIMER_EN;
writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
/* get the pending descriptors parameters */
num_of_pending = mv_xor_v2_get_pending_params(xor_dev, &pending_ptr);
/* loop over free descriptors */ for (i = 0; i < num_of_pending; i++) { struct mv_xor_v2_descriptor *next_pending_hw_desc =
xor_dev->hw_desq_virt + pending_ptr;
/* get the SW descriptor related to the HW descriptor */
next_pending_sw_desc =
&xor_dev->sw_desq[next_pending_hw_desc->desc_id];
/* call the callback */ if (next_pending_sw_desc->async_tx.cookie > 0) { /* * update the channel's completed cookie - no * lock is required the IMSG threshold provide * the locking
*/
dma_cookie_complete(&next_pending_sw_desc->async_tx);
/* write the DESQ size to the DMA engine */
writel(MV_XOR_V2_DESC_NUM,
xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_SIZE_OFF);
/* write the DESQ address to the DMA engine*/
writel(lower_32_bits(xor_dev->hw_desq),
xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BALR_OFF);
writel(upper_32_bits(xor_dev->hw_desq),
xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BAHR_OFF);
/* * This is a temporary solution, until we activate the * SMMU. Set the attributes for reading & writing data buffers * & descriptors to: * * - OuterShareable - Snoops will be performed on CPU caches * - Enable cacheable - Bufferable, Modifiable, Other Allocate * and Allocate
*/
reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ARATTR_OFF);
reg &= ~MV_XOR_V2_DMA_DESQ_ATTR_CACHE_MASK;
reg |= MV_XOR_V2_DMA_DESQ_ATTR_OUTER_SHAREABLE |
MV_XOR_V2_DMA_DESQ_ATTR_CACHEABLE;
writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ARATTR_OFF);
/* BW CTRL - set values to optimize the XOR performance: * * - Set WrBurstLen & RdBurstLen - the unit will issue * maximum of 256B write/read transactions. * - Limit the number of outstanding write & read data * (OBB/IBB) requests to the maximal value.
*/
reg = ((MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_VAL <<
MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_RD_SHIFT) |
(MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_VAL <<
MV_XOR_V2_GLOB_BW_CTRL_NUM_OSTD_WR_SHIFT) |
(MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_VAL <<
MV_XOR_V2_GLOB_BW_CTRL_RD_BURST_LEN_SHIFT) |
(MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_VAL <<
MV_XOR_V2_GLOB_BW_CTRL_WR_BURST_LEN_SHIFT));
writel(reg, xor_dev->glob_base + MV_XOR_V2_GLOB_BW_CTRL);
/* * allocate coherent memory for hardware descriptors * note: writecombine gives slightly better performance, but * requires that we explicitly flush the writes
*/
xor_dev->hw_desq_virt =
dma_alloc_coherent(&pdev->dev,
xor_dev->desc_size * MV_XOR_V2_DESC_NUM,
&xor_dev->hw_desq, GFP_KERNEL); if (!xor_dev->hw_desq_virt) {
ret = -ENOMEM; goto free_msi_irqs;
}
/* alloc memory for the SW descriptors */
xor_dev->sw_desq = devm_kcalloc(&pdev->dev,
MV_XOR_V2_DESC_NUM, sizeof(*sw_desc),
GFP_KERNEL); if (!xor_dev->sw_desq) {
ret = -ENOMEM; goto free_hw_desq;
}
spin_lock_init(&xor_dev->lock);
/* init the free SW descriptors list */
INIT_LIST_HEAD(&xor_dev->free_sw_desc);
/* add all SW descriptors to the free list */ for (i = 0; i < MV_XOR_V2_DESC_NUM; i++) { struct mv_xor_v2_sw_desc *sw_desc =
xor_dev->sw_desq + i;
sw_desc->idx = i;
dma_async_tx_descriptor_init(&sw_desc->async_tx,
&xor_dev->dmachan);
sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit;
async_tx_ack(&sw_desc->async_tx);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.