162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// Copyright (C) 2017 Broadcom 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* 562306a36Sopenharmony_ci * Broadcom SBA RAID Driver 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * The Broadcom stream buffer accelerator (SBA) provides offloading 862306a36Sopenharmony_ci * capabilities for RAID operations. The SBA offload engine is accessible 962306a36Sopenharmony_ci * via Broadcom SoC specific ring manager. Two or more offload engines 1062306a36Sopenharmony_ci * can share same Broadcom SoC specific ring manager due to this Broadcom 1162306a36Sopenharmony_ci * SoC specific ring manager driver is implemented as a mailbox controller 1262306a36Sopenharmony_ci * driver and offload engine drivers are implemented as mallbox clients. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Typically, Broadcom SoC specific ring manager will implement larger 1562306a36Sopenharmony_ci * number of hardware rings over one or more SBA hardware devices. By 1662306a36Sopenharmony_ci * design, the internal buffer size of SBA hardware device is limited 1762306a36Sopenharmony_ci * but all offload operations supported by SBA can be broken down into 1862306a36Sopenharmony_ci * multiple small size requests and executed parallely on multiple SBA 1962306a36Sopenharmony_ci * hardware devices for achieving high through-put. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * The Broadcom SBA RAID driver does not require any register programming 2262306a36Sopenharmony_ci * except submitting request to SBA hardware device via mailbox channels. 2362306a36Sopenharmony_ci * This driver implements a DMA device with one DMA channel using a single 2462306a36Sopenharmony_ci * mailbox channel provided by Broadcom SoC specific ring manager driver. 2562306a36Sopenharmony_ci * For having more SBA DMA channels, we can create more SBA device nodes 2662306a36Sopenharmony_ci * in Broadcom SoC specific DTS based on number of hardware rings supported 2762306a36Sopenharmony_ci * by Broadcom SoC ring manager. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <linux/bitops.h> 3162306a36Sopenharmony_ci#include <linux/debugfs.h> 3262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 3362306a36Sopenharmony_ci#include <linux/dmaengine.h> 3462306a36Sopenharmony_ci#include <linux/list.h> 3562306a36Sopenharmony_ci#include <linux/mailbox_client.h> 3662306a36Sopenharmony_ci#include <linux/mailbox/brcm-message.h> 3762306a36Sopenharmony_ci#include <linux/module.h> 3862306a36Sopenharmony_ci#include <linux/of.h> 3962306a36Sopenharmony_ci#include <linux/of_platform.h> 4062306a36Sopenharmony_ci#include <linux/platform_device.h> 4162306a36Sopenharmony_ci#include <linux/slab.h> 4262306a36Sopenharmony_ci#include <linux/raid/pq.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include "dmaengine.h" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* ====== Driver macros and defines ===== */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define SBA_TYPE_SHIFT 48 4962306a36Sopenharmony_ci#define SBA_TYPE_MASK GENMASK(1, 0) 5062306a36Sopenharmony_ci#define SBA_TYPE_A 0x0 5162306a36Sopenharmony_ci#define SBA_TYPE_B 0x2 5262306a36Sopenharmony_ci#define SBA_TYPE_C 0x3 5362306a36Sopenharmony_ci#define SBA_USER_DEF_SHIFT 32 5462306a36Sopenharmony_ci#define SBA_USER_DEF_MASK GENMASK(15, 0) 5562306a36Sopenharmony_ci#define SBA_R_MDATA_SHIFT 24 5662306a36Sopenharmony_ci#define SBA_R_MDATA_MASK GENMASK(7, 0) 5762306a36Sopenharmony_ci#define SBA_C_MDATA_MS_SHIFT 18 5862306a36Sopenharmony_ci#define SBA_C_MDATA_MS_MASK GENMASK(1, 0) 5962306a36Sopenharmony_ci#define SBA_INT_SHIFT 17 6062306a36Sopenharmony_ci#define SBA_INT_MASK BIT(0) 6162306a36Sopenharmony_ci#define SBA_RESP_SHIFT 16 6262306a36Sopenharmony_ci#define SBA_RESP_MASK BIT(0) 6362306a36Sopenharmony_ci#define SBA_C_MDATA_SHIFT 8 6462306a36Sopenharmony_ci#define SBA_C_MDATA_MASK GENMASK(7, 0) 6562306a36Sopenharmony_ci#define SBA_C_MDATA_BNUMx_SHIFT(__bnum) (2 * (__bnum)) 6662306a36Sopenharmony_ci#define SBA_C_MDATA_BNUMx_MASK GENMASK(1, 0) 6762306a36Sopenharmony_ci#define SBA_C_MDATA_DNUM_SHIFT 5 6862306a36Sopenharmony_ci#define SBA_C_MDATA_DNUM_MASK GENMASK(4, 0) 6962306a36Sopenharmony_ci#define SBA_C_MDATA_LS(__v) ((__v) & 0xff) 7062306a36Sopenharmony_ci#define SBA_C_MDATA_MS(__v) (((__v) >> 8) & 0x3) 7162306a36Sopenharmony_ci#define SBA_CMD_SHIFT 0 7262306a36Sopenharmony_ci#define SBA_CMD_MASK GENMASK(3, 0) 7362306a36Sopenharmony_ci#define SBA_CMD_ZERO_BUFFER 0x4 7462306a36Sopenharmony_ci#define SBA_CMD_ZERO_ALL_BUFFERS 0x8 7562306a36Sopenharmony_ci#define SBA_CMD_LOAD_BUFFER 0x9 7662306a36Sopenharmony_ci#define SBA_CMD_XOR 0xa 7762306a36Sopenharmony_ci#define SBA_CMD_GALOIS_XOR 0xb 7862306a36Sopenharmony_ci#define SBA_CMD_WRITE_BUFFER 0xc 7962306a36Sopenharmony_ci#define SBA_CMD_GALOIS 0xe 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define SBA_MAX_REQ_PER_MBOX_CHANNEL 8192 8262306a36Sopenharmony_ci#define SBA_MAX_MSG_SEND_PER_MBOX_CHANNEL 8 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* Driver helper macros */ 8562306a36Sopenharmony_ci#define to_sba_request(tx) \ 8662306a36Sopenharmony_ci container_of(tx, struct sba_request, tx) 8762306a36Sopenharmony_ci#define to_sba_device(dchan) \ 8862306a36Sopenharmony_ci container_of(dchan, struct sba_device, dma_chan) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* ===== Driver data structures ===== */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cienum sba_request_flags { 9362306a36Sopenharmony_ci SBA_REQUEST_STATE_FREE = 0x001, 9462306a36Sopenharmony_ci SBA_REQUEST_STATE_ALLOCED = 0x002, 9562306a36Sopenharmony_ci SBA_REQUEST_STATE_PENDING = 0x004, 9662306a36Sopenharmony_ci SBA_REQUEST_STATE_ACTIVE = 0x008, 9762306a36Sopenharmony_ci SBA_REQUEST_STATE_ABORTED = 0x010, 9862306a36Sopenharmony_ci SBA_REQUEST_STATE_MASK = 0x0ff, 9962306a36Sopenharmony_ci SBA_REQUEST_FENCE = 0x100, 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistruct sba_request { 10362306a36Sopenharmony_ci /* Global state */ 10462306a36Sopenharmony_ci struct list_head node; 10562306a36Sopenharmony_ci struct sba_device *sba; 10662306a36Sopenharmony_ci u32 flags; 10762306a36Sopenharmony_ci /* Chained requests management */ 10862306a36Sopenharmony_ci struct sba_request *first; 10962306a36Sopenharmony_ci struct list_head next; 11062306a36Sopenharmony_ci atomic_t next_pending_count; 11162306a36Sopenharmony_ci /* BRCM message data */ 11262306a36Sopenharmony_ci struct brcm_message msg; 11362306a36Sopenharmony_ci struct dma_async_tx_descriptor tx; 11462306a36Sopenharmony_ci /* SBA commands */ 11562306a36Sopenharmony_ci struct brcm_sba_command cmds[]; 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cienum sba_version { 11962306a36Sopenharmony_ci SBA_VER_1 = 0, 12062306a36Sopenharmony_ci SBA_VER_2 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistruct sba_device { 12462306a36Sopenharmony_ci /* Underlying device */ 12562306a36Sopenharmony_ci struct device *dev; 12662306a36Sopenharmony_ci /* DT configuration parameters */ 12762306a36Sopenharmony_ci enum sba_version ver; 12862306a36Sopenharmony_ci /* Derived configuration parameters */ 12962306a36Sopenharmony_ci u32 max_req; 13062306a36Sopenharmony_ci u32 hw_buf_size; 13162306a36Sopenharmony_ci u32 hw_resp_size; 13262306a36Sopenharmony_ci u32 max_pq_coefs; 13362306a36Sopenharmony_ci u32 max_pq_srcs; 13462306a36Sopenharmony_ci u32 max_cmd_per_req; 13562306a36Sopenharmony_ci u32 max_xor_srcs; 13662306a36Sopenharmony_ci u32 max_resp_pool_size; 13762306a36Sopenharmony_ci u32 max_cmds_pool_size; 13862306a36Sopenharmony_ci /* Maibox client and Mailbox channels */ 13962306a36Sopenharmony_ci struct mbox_client client; 14062306a36Sopenharmony_ci struct mbox_chan *mchan; 14162306a36Sopenharmony_ci struct device *mbox_dev; 14262306a36Sopenharmony_ci /* DMA device and DMA channel */ 14362306a36Sopenharmony_ci struct dma_device dma_dev; 14462306a36Sopenharmony_ci struct dma_chan dma_chan; 14562306a36Sopenharmony_ci /* DMA channel resources */ 14662306a36Sopenharmony_ci void *resp_base; 14762306a36Sopenharmony_ci dma_addr_t resp_dma_base; 14862306a36Sopenharmony_ci void *cmds_base; 14962306a36Sopenharmony_ci dma_addr_t cmds_dma_base; 15062306a36Sopenharmony_ci spinlock_t reqs_lock; 15162306a36Sopenharmony_ci bool reqs_fence; 15262306a36Sopenharmony_ci struct list_head reqs_alloc_list; 15362306a36Sopenharmony_ci struct list_head reqs_pending_list; 15462306a36Sopenharmony_ci struct list_head reqs_active_list; 15562306a36Sopenharmony_ci struct list_head reqs_aborted_list; 15662306a36Sopenharmony_ci struct list_head reqs_free_list; 15762306a36Sopenharmony_ci /* DebugFS directory entries */ 15862306a36Sopenharmony_ci struct dentry *root; 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* ====== Command helper routines ===== */ 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic inline u64 __pure sba_cmd_enc(u64 cmd, u32 val, u32 shift, u32 mask) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci cmd &= ~((u64)mask << shift); 16662306a36Sopenharmony_ci cmd |= ((u64)(val & mask) << shift); 16762306a36Sopenharmony_ci return cmd; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic inline u32 __pure sba_cmd_load_c_mdata(u32 b0) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci return b0 & SBA_C_MDATA_BNUMx_MASK; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic inline u32 __pure sba_cmd_write_c_mdata(u32 b0) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci return b0 & SBA_C_MDATA_BNUMx_MASK; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic inline u32 __pure sba_cmd_xor_c_mdata(u32 b1, u32 b0) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return (b0 & SBA_C_MDATA_BNUMx_MASK) | 18362306a36Sopenharmony_ci ((b1 & SBA_C_MDATA_BNUMx_MASK) << SBA_C_MDATA_BNUMx_SHIFT(1)); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic inline u32 __pure sba_cmd_pq_c_mdata(u32 d, u32 b1, u32 b0) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci return (b0 & SBA_C_MDATA_BNUMx_MASK) | 18962306a36Sopenharmony_ci ((b1 & SBA_C_MDATA_BNUMx_MASK) << SBA_C_MDATA_BNUMx_SHIFT(1)) | 19062306a36Sopenharmony_ci ((d & SBA_C_MDATA_DNUM_MASK) << SBA_C_MDATA_DNUM_SHIFT); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* ====== General helper routines ===== */ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic struct sba_request *sba_alloc_request(struct sba_device *sba) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci bool found = false; 19862306a36Sopenharmony_ci unsigned long flags; 19962306a36Sopenharmony_ci struct sba_request *req = NULL; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 20262306a36Sopenharmony_ci list_for_each_entry(req, &sba->reqs_free_list, node) { 20362306a36Sopenharmony_ci if (async_tx_test_ack(&req->tx)) { 20462306a36Sopenharmony_ci list_move_tail(&req->node, &sba->reqs_alloc_list); 20562306a36Sopenharmony_ci found = true; 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (!found) { 21262306a36Sopenharmony_ci /* 21362306a36Sopenharmony_ci * We have no more free requests so, we peek 21462306a36Sopenharmony_ci * mailbox channels hoping few active requests 21562306a36Sopenharmony_ci * would have completed which will create more 21662306a36Sopenharmony_ci * room for new requests. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci mbox_client_peek_data(sba->mchan); 21962306a36Sopenharmony_ci return NULL; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci req->flags = SBA_REQUEST_STATE_ALLOCED; 22362306a36Sopenharmony_ci req->first = req; 22462306a36Sopenharmony_ci INIT_LIST_HEAD(&req->next); 22562306a36Sopenharmony_ci atomic_set(&req->next_pending_count, 1); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci dma_async_tx_descriptor_init(&req->tx, &sba->dma_chan); 22862306a36Sopenharmony_ci async_tx_ack(&req->tx); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return req; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* Note: Must be called with sba->reqs_lock held */ 23462306a36Sopenharmony_cistatic void _sba_pending_request(struct sba_device *sba, 23562306a36Sopenharmony_ci struct sba_request *req) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci lockdep_assert_held(&sba->reqs_lock); 23862306a36Sopenharmony_ci req->flags &= ~SBA_REQUEST_STATE_MASK; 23962306a36Sopenharmony_ci req->flags |= SBA_REQUEST_STATE_PENDING; 24062306a36Sopenharmony_ci list_move_tail(&req->node, &sba->reqs_pending_list); 24162306a36Sopenharmony_ci if (list_empty(&sba->reqs_active_list)) 24262306a36Sopenharmony_ci sba->reqs_fence = false; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* Note: Must be called with sba->reqs_lock held */ 24662306a36Sopenharmony_cistatic bool _sba_active_request(struct sba_device *sba, 24762306a36Sopenharmony_ci struct sba_request *req) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci lockdep_assert_held(&sba->reqs_lock); 25062306a36Sopenharmony_ci if (list_empty(&sba->reqs_active_list)) 25162306a36Sopenharmony_ci sba->reqs_fence = false; 25262306a36Sopenharmony_ci if (sba->reqs_fence) 25362306a36Sopenharmony_ci return false; 25462306a36Sopenharmony_ci req->flags &= ~SBA_REQUEST_STATE_MASK; 25562306a36Sopenharmony_ci req->flags |= SBA_REQUEST_STATE_ACTIVE; 25662306a36Sopenharmony_ci list_move_tail(&req->node, &sba->reqs_active_list); 25762306a36Sopenharmony_ci if (req->flags & SBA_REQUEST_FENCE) 25862306a36Sopenharmony_ci sba->reqs_fence = true; 25962306a36Sopenharmony_ci return true; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/* Note: Must be called with sba->reqs_lock held */ 26362306a36Sopenharmony_cistatic void _sba_abort_request(struct sba_device *sba, 26462306a36Sopenharmony_ci struct sba_request *req) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci lockdep_assert_held(&sba->reqs_lock); 26762306a36Sopenharmony_ci req->flags &= ~SBA_REQUEST_STATE_MASK; 26862306a36Sopenharmony_ci req->flags |= SBA_REQUEST_STATE_ABORTED; 26962306a36Sopenharmony_ci list_move_tail(&req->node, &sba->reqs_aborted_list); 27062306a36Sopenharmony_ci if (list_empty(&sba->reqs_active_list)) 27162306a36Sopenharmony_ci sba->reqs_fence = false; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/* Note: Must be called with sba->reqs_lock held */ 27562306a36Sopenharmony_cistatic void _sba_free_request(struct sba_device *sba, 27662306a36Sopenharmony_ci struct sba_request *req) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci lockdep_assert_held(&sba->reqs_lock); 27962306a36Sopenharmony_ci req->flags &= ~SBA_REQUEST_STATE_MASK; 28062306a36Sopenharmony_ci req->flags |= SBA_REQUEST_STATE_FREE; 28162306a36Sopenharmony_ci list_move_tail(&req->node, &sba->reqs_free_list); 28262306a36Sopenharmony_ci if (list_empty(&sba->reqs_active_list)) 28362306a36Sopenharmony_ci sba->reqs_fence = false; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void sba_free_chained_requests(struct sba_request *req) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci unsigned long flags; 28962306a36Sopenharmony_ci struct sba_request *nreq; 29062306a36Sopenharmony_ci struct sba_device *sba = req->sba; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci _sba_free_request(sba, req); 29562306a36Sopenharmony_ci list_for_each_entry(nreq, &req->next, next) 29662306a36Sopenharmony_ci _sba_free_request(sba, nreq); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void sba_chain_request(struct sba_request *first, 30262306a36Sopenharmony_ci struct sba_request *req) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci unsigned long flags; 30562306a36Sopenharmony_ci struct sba_device *sba = req->sba; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci list_add_tail(&req->next, &first->next); 31062306a36Sopenharmony_ci req->first = first; 31162306a36Sopenharmony_ci atomic_inc(&first->next_pending_count); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic void sba_cleanup_nonpending_requests(struct sba_device *sba) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci unsigned long flags; 31962306a36Sopenharmony_ci struct sba_request *req, *req1; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Freeup all alloced request */ 32462306a36Sopenharmony_ci list_for_each_entry_safe(req, req1, &sba->reqs_alloc_list, node) 32562306a36Sopenharmony_ci _sba_free_request(sba, req); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* Set all active requests as aborted */ 32862306a36Sopenharmony_ci list_for_each_entry_safe(req, req1, &sba->reqs_active_list, node) 32962306a36Sopenharmony_ci _sba_abort_request(sba, req); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* 33262306a36Sopenharmony_ci * Note: We expect that aborted request will be eventually 33362306a36Sopenharmony_ci * freed by sba_receive_message() 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic void sba_cleanup_pending_requests(struct sba_device *sba) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci unsigned long flags; 34262306a36Sopenharmony_ci struct sba_request *req, *req1; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Freeup all pending request */ 34762306a36Sopenharmony_ci list_for_each_entry_safe(req, req1, &sba->reqs_pending_list, node) 34862306a36Sopenharmony_ci _sba_free_request(sba, req); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic int sba_send_mbox_request(struct sba_device *sba, 35462306a36Sopenharmony_ci struct sba_request *req) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci int ret = 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* Send message for the request */ 35962306a36Sopenharmony_ci req->msg.error = 0; 36062306a36Sopenharmony_ci ret = mbox_send_message(sba->mchan, &req->msg); 36162306a36Sopenharmony_ci if (ret < 0) { 36262306a36Sopenharmony_ci dev_err(sba->dev, "send message failed with error %d", ret); 36362306a36Sopenharmony_ci return ret; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* Check error returned by mailbox controller */ 36762306a36Sopenharmony_ci ret = req->msg.error; 36862306a36Sopenharmony_ci if (ret < 0) { 36962306a36Sopenharmony_ci dev_err(sba->dev, "message error %d", ret); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Signal txdone for mailbox channel */ 37362306a36Sopenharmony_ci mbox_client_txdone(sba->mchan, ret); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci return ret; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/* Note: Must be called with sba->reqs_lock held */ 37962306a36Sopenharmony_cistatic void _sba_process_pending_requests(struct sba_device *sba) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci int ret; 38262306a36Sopenharmony_ci u32 count; 38362306a36Sopenharmony_ci struct sba_request *req; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* Process few pending requests */ 38662306a36Sopenharmony_ci count = SBA_MAX_MSG_SEND_PER_MBOX_CHANNEL; 38762306a36Sopenharmony_ci while (!list_empty(&sba->reqs_pending_list) && count) { 38862306a36Sopenharmony_ci /* Get the first pending request */ 38962306a36Sopenharmony_ci req = list_first_entry(&sba->reqs_pending_list, 39062306a36Sopenharmony_ci struct sba_request, node); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Try to make request active */ 39362306a36Sopenharmony_ci if (!_sba_active_request(sba, req)) 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* Send request to mailbox channel */ 39762306a36Sopenharmony_ci ret = sba_send_mbox_request(sba, req); 39862306a36Sopenharmony_ci if (ret < 0) { 39962306a36Sopenharmony_ci _sba_pending_request(sba, req); 40062306a36Sopenharmony_ci break; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci count--; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void sba_process_received_request(struct sba_device *sba, 40862306a36Sopenharmony_ci struct sba_request *req) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci unsigned long flags; 41162306a36Sopenharmony_ci struct dma_async_tx_descriptor *tx; 41262306a36Sopenharmony_ci struct sba_request *nreq, *first = req->first; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* Process only after all chained requests are received */ 41562306a36Sopenharmony_ci if (!atomic_dec_return(&first->next_pending_count)) { 41662306a36Sopenharmony_ci tx = &first->tx; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci WARN_ON(tx->cookie < 0); 41962306a36Sopenharmony_ci if (tx->cookie > 0) { 42062306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 42162306a36Sopenharmony_ci dma_cookie_complete(tx); 42262306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 42362306a36Sopenharmony_ci dmaengine_desc_get_callback_invoke(tx, NULL); 42462306a36Sopenharmony_ci dma_descriptor_unmap(tx); 42562306a36Sopenharmony_ci tx->callback = NULL; 42662306a36Sopenharmony_ci tx->callback_result = NULL; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci dma_run_dependencies(tx); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* Free all requests chained to first request */ 43462306a36Sopenharmony_ci list_for_each_entry(nreq, &first->next, next) 43562306a36Sopenharmony_ci _sba_free_request(sba, nreq); 43662306a36Sopenharmony_ci INIT_LIST_HEAD(&first->next); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Free the first request */ 43962306a36Sopenharmony_ci _sba_free_request(sba, first); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* Process pending requests */ 44262306a36Sopenharmony_ci _sba_process_pending_requests(sba); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void sba_write_stats_in_seqfile(struct sba_device *sba, 44962306a36Sopenharmony_ci struct seq_file *file) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci unsigned long flags; 45262306a36Sopenharmony_ci struct sba_request *req; 45362306a36Sopenharmony_ci u32 free_count = 0, alloced_count = 0; 45462306a36Sopenharmony_ci u32 pending_count = 0, active_count = 0, aborted_count = 0; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci list_for_each_entry(req, &sba->reqs_free_list, node) 45962306a36Sopenharmony_ci if (async_tx_test_ack(&req->tx)) 46062306a36Sopenharmony_ci free_count++; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci list_for_each_entry(req, &sba->reqs_alloc_list, node) 46362306a36Sopenharmony_ci alloced_count++; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci list_for_each_entry(req, &sba->reqs_pending_list, node) 46662306a36Sopenharmony_ci pending_count++; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci list_for_each_entry(req, &sba->reqs_active_list, node) 46962306a36Sopenharmony_ci active_count++; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci list_for_each_entry(req, &sba->reqs_aborted_list, node) 47262306a36Sopenharmony_ci aborted_count++; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci seq_printf(file, "maximum requests = %d\n", sba->max_req); 47762306a36Sopenharmony_ci seq_printf(file, "free requests = %d\n", free_count); 47862306a36Sopenharmony_ci seq_printf(file, "alloced requests = %d\n", alloced_count); 47962306a36Sopenharmony_ci seq_printf(file, "pending requests = %d\n", pending_count); 48062306a36Sopenharmony_ci seq_printf(file, "active requests = %d\n", active_count); 48162306a36Sopenharmony_ci seq_printf(file, "aborted requests = %d\n", aborted_count); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci/* ====== DMAENGINE callbacks ===== */ 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void sba_free_chan_resources(struct dma_chan *dchan) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci /* 48962306a36Sopenharmony_ci * Channel resources are pre-alloced so we just free-up 49062306a36Sopenharmony_ci * whatever we can so that we can re-use pre-alloced 49162306a36Sopenharmony_ci * channel resources next time. 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_ci sba_cleanup_nonpending_requests(to_sba_device(dchan)); 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic int sba_device_terminate_all(struct dma_chan *dchan) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci /* Cleanup all pending requests */ 49962306a36Sopenharmony_ci sba_cleanup_pending_requests(to_sba_device(dchan)); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic void sba_issue_pending(struct dma_chan *dchan) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci unsigned long flags; 50762306a36Sopenharmony_ci struct sba_device *sba = to_sba_device(dchan); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* Process pending requests */ 51062306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 51162306a36Sopenharmony_ci _sba_process_pending_requests(sba); 51262306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic dma_cookie_t sba_tx_submit(struct dma_async_tx_descriptor *tx) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci unsigned long flags; 51862306a36Sopenharmony_ci dma_cookie_t cookie; 51962306a36Sopenharmony_ci struct sba_device *sba; 52062306a36Sopenharmony_ci struct sba_request *req, *nreq; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (unlikely(!tx)) 52362306a36Sopenharmony_ci return -EINVAL; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci sba = to_sba_device(tx->chan); 52662306a36Sopenharmony_ci req = to_sba_request(tx); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* Assign cookie and mark all chained requests pending */ 52962306a36Sopenharmony_ci spin_lock_irqsave(&sba->reqs_lock, flags); 53062306a36Sopenharmony_ci cookie = dma_cookie_assign(tx); 53162306a36Sopenharmony_ci _sba_pending_request(sba, req); 53262306a36Sopenharmony_ci list_for_each_entry(nreq, &req->next, next) 53362306a36Sopenharmony_ci _sba_pending_request(sba, nreq); 53462306a36Sopenharmony_ci spin_unlock_irqrestore(&sba->reqs_lock, flags); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return cookie; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic enum dma_status sba_tx_status(struct dma_chan *dchan, 54062306a36Sopenharmony_ci dma_cookie_t cookie, 54162306a36Sopenharmony_ci struct dma_tx_state *txstate) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci enum dma_status ret; 54462306a36Sopenharmony_ci struct sba_device *sba = to_sba_device(dchan); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ret = dma_cookie_status(dchan, cookie, txstate); 54762306a36Sopenharmony_ci if (ret == DMA_COMPLETE) 54862306a36Sopenharmony_ci return ret; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci mbox_client_peek_data(sba->mchan); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return dma_cookie_status(dchan, cookie, txstate); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic void sba_fillup_interrupt_msg(struct sba_request *req, 55662306a36Sopenharmony_ci struct brcm_sba_command *cmds, 55762306a36Sopenharmony_ci struct brcm_message *msg) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci u64 cmd; 56062306a36Sopenharmony_ci u32 c_mdata; 56162306a36Sopenharmony_ci dma_addr_t resp_dma = req->tx.phys; 56262306a36Sopenharmony_ci struct brcm_sba_command *cmdsp = cmds; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* Type-B command to load dummy data into buf0 */ 56562306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 56662306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 56762306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, req->sba->hw_resp_size, 56862306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 56962306a36Sopenharmony_ci c_mdata = sba_cmd_load_c_mdata(0); 57062306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 57162306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 57262306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_LOAD_BUFFER, 57362306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 57462306a36Sopenharmony_ci cmdsp->cmd = cmd; 57562306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 57662306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 57762306a36Sopenharmony_ci cmdsp->data = resp_dma; 57862306a36Sopenharmony_ci cmdsp->data_len = req->sba->hw_resp_size; 57962306a36Sopenharmony_ci cmdsp++; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* Type-A command to write buf0 to dummy location */ 58262306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 58362306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 58462306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, req->sba->hw_resp_size, 58562306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 58662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, 0x1, 58762306a36Sopenharmony_ci SBA_RESP_SHIFT, SBA_RESP_MASK); 58862306a36Sopenharmony_ci c_mdata = sba_cmd_write_c_mdata(0); 58962306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 59062306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 59162306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_WRITE_BUFFER, 59262306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 59362306a36Sopenharmony_ci cmdsp->cmd = cmd; 59462306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 59562306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 59662306a36Sopenharmony_ci if (req->sba->hw_resp_size) { 59762306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_RESP; 59862306a36Sopenharmony_ci cmdsp->resp = resp_dma; 59962306a36Sopenharmony_ci cmdsp->resp_len = req->sba->hw_resp_size; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_OUTPUT; 60262306a36Sopenharmony_ci cmdsp->data = resp_dma; 60362306a36Sopenharmony_ci cmdsp->data_len = req->sba->hw_resp_size; 60462306a36Sopenharmony_ci cmdsp++; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* Fillup brcm_message */ 60762306a36Sopenharmony_ci msg->type = BRCM_MESSAGE_SBA; 60862306a36Sopenharmony_ci msg->sba.cmds = cmds; 60962306a36Sopenharmony_ci msg->sba.cmds_count = cmdsp - cmds; 61062306a36Sopenharmony_ci msg->ctx = req; 61162306a36Sopenharmony_ci msg->error = 0; 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 61562306a36Sopenharmony_cisba_prep_dma_interrupt(struct dma_chan *dchan, unsigned long flags) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct sba_request *req = NULL; 61862306a36Sopenharmony_ci struct sba_device *sba = to_sba_device(dchan); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* Alloc new request */ 62162306a36Sopenharmony_ci req = sba_alloc_request(sba); 62262306a36Sopenharmony_ci if (!req) 62362306a36Sopenharmony_ci return NULL; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* 62662306a36Sopenharmony_ci * Force fence so that no requests are submitted 62762306a36Sopenharmony_ci * until DMA callback for this request is invoked. 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_ci req->flags |= SBA_REQUEST_FENCE; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* Fillup request message */ 63262306a36Sopenharmony_ci sba_fillup_interrupt_msg(req, req->cmds, &req->msg); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* Init async_tx descriptor */ 63562306a36Sopenharmony_ci req->tx.flags = flags; 63662306a36Sopenharmony_ci req->tx.cookie = -EBUSY; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci return &req->tx; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic void sba_fillup_memcpy_msg(struct sba_request *req, 64262306a36Sopenharmony_ci struct brcm_sba_command *cmds, 64362306a36Sopenharmony_ci struct brcm_message *msg, 64462306a36Sopenharmony_ci dma_addr_t msg_offset, size_t msg_len, 64562306a36Sopenharmony_ci dma_addr_t dst, dma_addr_t src) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci u64 cmd; 64862306a36Sopenharmony_ci u32 c_mdata; 64962306a36Sopenharmony_ci dma_addr_t resp_dma = req->tx.phys; 65062306a36Sopenharmony_ci struct brcm_sba_command *cmdsp = cmds; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci /* Type-B command to load data into buf0 */ 65362306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 65462306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 65562306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 65662306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 65762306a36Sopenharmony_ci c_mdata = sba_cmd_load_c_mdata(0); 65862306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 65962306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 66062306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_LOAD_BUFFER, 66162306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 66262306a36Sopenharmony_ci cmdsp->cmd = cmd; 66362306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 66462306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 66562306a36Sopenharmony_ci cmdsp->data = src + msg_offset; 66662306a36Sopenharmony_ci cmdsp->data_len = msg_len; 66762306a36Sopenharmony_ci cmdsp++; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* Type-A command to write buf0 */ 67062306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 67162306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 67262306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 67362306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 67462306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, 0x1, 67562306a36Sopenharmony_ci SBA_RESP_SHIFT, SBA_RESP_MASK); 67662306a36Sopenharmony_ci c_mdata = sba_cmd_write_c_mdata(0); 67762306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 67862306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 67962306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_WRITE_BUFFER, 68062306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 68162306a36Sopenharmony_ci cmdsp->cmd = cmd; 68262306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 68362306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 68462306a36Sopenharmony_ci if (req->sba->hw_resp_size) { 68562306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_RESP; 68662306a36Sopenharmony_ci cmdsp->resp = resp_dma; 68762306a36Sopenharmony_ci cmdsp->resp_len = req->sba->hw_resp_size; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_OUTPUT; 69062306a36Sopenharmony_ci cmdsp->data = dst + msg_offset; 69162306a36Sopenharmony_ci cmdsp->data_len = msg_len; 69262306a36Sopenharmony_ci cmdsp++; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* Fillup brcm_message */ 69562306a36Sopenharmony_ci msg->type = BRCM_MESSAGE_SBA; 69662306a36Sopenharmony_ci msg->sba.cmds = cmds; 69762306a36Sopenharmony_ci msg->sba.cmds_count = cmdsp - cmds; 69862306a36Sopenharmony_ci msg->ctx = req; 69962306a36Sopenharmony_ci msg->error = 0; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic struct sba_request * 70362306a36Sopenharmony_cisba_prep_dma_memcpy_req(struct sba_device *sba, 70462306a36Sopenharmony_ci dma_addr_t off, dma_addr_t dst, dma_addr_t src, 70562306a36Sopenharmony_ci size_t len, unsigned long flags) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct sba_request *req = NULL; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* Alloc new request */ 71062306a36Sopenharmony_ci req = sba_alloc_request(sba); 71162306a36Sopenharmony_ci if (!req) 71262306a36Sopenharmony_ci return NULL; 71362306a36Sopenharmony_ci if (flags & DMA_PREP_FENCE) 71462306a36Sopenharmony_ci req->flags |= SBA_REQUEST_FENCE; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* Fillup request message */ 71762306a36Sopenharmony_ci sba_fillup_memcpy_msg(req, req->cmds, &req->msg, 71862306a36Sopenharmony_ci off, len, dst, src); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* Init async_tx descriptor */ 72162306a36Sopenharmony_ci req->tx.flags = flags; 72262306a36Sopenharmony_ci req->tx.cookie = -EBUSY; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci return req; 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 72862306a36Sopenharmony_cisba_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst, dma_addr_t src, 72962306a36Sopenharmony_ci size_t len, unsigned long flags) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci size_t req_len; 73262306a36Sopenharmony_ci dma_addr_t off = 0; 73362306a36Sopenharmony_ci struct sba_device *sba = to_sba_device(dchan); 73462306a36Sopenharmony_ci struct sba_request *first = NULL, *req; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Create chained requests where each request is upto hw_buf_size */ 73762306a36Sopenharmony_ci while (len) { 73862306a36Sopenharmony_ci req_len = (len < sba->hw_buf_size) ? len : sba->hw_buf_size; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci req = sba_prep_dma_memcpy_req(sba, off, dst, src, 74162306a36Sopenharmony_ci req_len, flags); 74262306a36Sopenharmony_ci if (!req) { 74362306a36Sopenharmony_ci if (first) 74462306a36Sopenharmony_ci sba_free_chained_requests(first); 74562306a36Sopenharmony_ci return NULL; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (first) 74962306a36Sopenharmony_ci sba_chain_request(first, req); 75062306a36Sopenharmony_ci else 75162306a36Sopenharmony_ci first = req; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci off += req_len; 75462306a36Sopenharmony_ci len -= req_len; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return (first) ? &first->tx : NULL; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic void sba_fillup_xor_msg(struct sba_request *req, 76162306a36Sopenharmony_ci struct brcm_sba_command *cmds, 76262306a36Sopenharmony_ci struct brcm_message *msg, 76362306a36Sopenharmony_ci dma_addr_t msg_offset, size_t msg_len, 76462306a36Sopenharmony_ci dma_addr_t dst, dma_addr_t *src, u32 src_cnt) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci u64 cmd; 76762306a36Sopenharmony_ci u32 c_mdata; 76862306a36Sopenharmony_ci unsigned int i; 76962306a36Sopenharmony_ci dma_addr_t resp_dma = req->tx.phys; 77062306a36Sopenharmony_ci struct brcm_sba_command *cmdsp = cmds; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Type-B command to load data into buf0 */ 77362306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 77462306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 77562306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 77662306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 77762306a36Sopenharmony_ci c_mdata = sba_cmd_load_c_mdata(0); 77862306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 77962306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 78062306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_LOAD_BUFFER, 78162306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 78262306a36Sopenharmony_ci cmdsp->cmd = cmd; 78362306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 78462306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 78562306a36Sopenharmony_ci cmdsp->data = src[0] + msg_offset; 78662306a36Sopenharmony_ci cmdsp->data_len = msg_len; 78762306a36Sopenharmony_ci cmdsp++; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* Type-B commands to xor data with buf0 and put it back in buf0 */ 79062306a36Sopenharmony_ci for (i = 1; i < src_cnt; i++) { 79162306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 79262306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 79362306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 79462306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 79562306a36Sopenharmony_ci c_mdata = sba_cmd_xor_c_mdata(0, 0); 79662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 79762306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 79862306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_XOR, 79962306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 80062306a36Sopenharmony_ci cmdsp->cmd = cmd; 80162306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 80262306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 80362306a36Sopenharmony_ci cmdsp->data = src[i] + msg_offset; 80462306a36Sopenharmony_ci cmdsp->data_len = msg_len; 80562306a36Sopenharmony_ci cmdsp++; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* Type-A command to write buf0 */ 80962306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 81062306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 81162306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 81262306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 81362306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, 0x1, 81462306a36Sopenharmony_ci SBA_RESP_SHIFT, SBA_RESP_MASK); 81562306a36Sopenharmony_ci c_mdata = sba_cmd_write_c_mdata(0); 81662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 81762306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 81862306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_WRITE_BUFFER, 81962306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 82062306a36Sopenharmony_ci cmdsp->cmd = cmd; 82162306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 82262306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 82362306a36Sopenharmony_ci if (req->sba->hw_resp_size) { 82462306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_RESP; 82562306a36Sopenharmony_ci cmdsp->resp = resp_dma; 82662306a36Sopenharmony_ci cmdsp->resp_len = req->sba->hw_resp_size; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_OUTPUT; 82962306a36Sopenharmony_ci cmdsp->data = dst + msg_offset; 83062306a36Sopenharmony_ci cmdsp->data_len = msg_len; 83162306a36Sopenharmony_ci cmdsp++; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* Fillup brcm_message */ 83462306a36Sopenharmony_ci msg->type = BRCM_MESSAGE_SBA; 83562306a36Sopenharmony_ci msg->sba.cmds = cmds; 83662306a36Sopenharmony_ci msg->sba.cmds_count = cmdsp - cmds; 83762306a36Sopenharmony_ci msg->ctx = req; 83862306a36Sopenharmony_ci msg->error = 0; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cistatic struct sba_request * 84262306a36Sopenharmony_cisba_prep_dma_xor_req(struct sba_device *sba, 84362306a36Sopenharmony_ci dma_addr_t off, dma_addr_t dst, dma_addr_t *src, 84462306a36Sopenharmony_ci u32 src_cnt, size_t len, unsigned long flags) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci struct sba_request *req = NULL; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* Alloc new request */ 84962306a36Sopenharmony_ci req = sba_alloc_request(sba); 85062306a36Sopenharmony_ci if (!req) 85162306a36Sopenharmony_ci return NULL; 85262306a36Sopenharmony_ci if (flags & DMA_PREP_FENCE) 85362306a36Sopenharmony_ci req->flags |= SBA_REQUEST_FENCE; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci /* Fillup request message */ 85662306a36Sopenharmony_ci sba_fillup_xor_msg(req, req->cmds, &req->msg, 85762306a36Sopenharmony_ci off, len, dst, src, src_cnt); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci /* Init async_tx descriptor */ 86062306a36Sopenharmony_ci req->tx.flags = flags; 86162306a36Sopenharmony_ci req->tx.cookie = -EBUSY; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return req; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 86762306a36Sopenharmony_cisba_prep_dma_xor(struct dma_chan *dchan, dma_addr_t dst, dma_addr_t *src, 86862306a36Sopenharmony_ci u32 src_cnt, size_t len, unsigned long flags) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci size_t req_len; 87162306a36Sopenharmony_ci dma_addr_t off = 0; 87262306a36Sopenharmony_ci struct sba_device *sba = to_sba_device(dchan); 87362306a36Sopenharmony_ci struct sba_request *first = NULL, *req; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Sanity checks */ 87662306a36Sopenharmony_ci if (unlikely(src_cnt > sba->max_xor_srcs)) 87762306a36Sopenharmony_ci return NULL; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* Create chained requests where each request is upto hw_buf_size */ 88062306a36Sopenharmony_ci while (len) { 88162306a36Sopenharmony_ci req_len = (len < sba->hw_buf_size) ? len : sba->hw_buf_size; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci req = sba_prep_dma_xor_req(sba, off, dst, src, src_cnt, 88462306a36Sopenharmony_ci req_len, flags); 88562306a36Sopenharmony_ci if (!req) { 88662306a36Sopenharmony_ci if (first) 88762306a36Sopenharmony_ci sba_free_chained_requests(first); 88862306a36Sopenharmony_ci return NULL; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (first) 89262306a36Sopenharmony_ci sba_chain_request(first, req); 89362306a36Sopenharmony_ci else 89462306a36Sopenharmony_ci first = req; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci off += req_len; 89762306a36Sopenharmony_ci len -= req_len; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return (first) ? &first->tx : NULL; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic void sba_fillup_pq_msg(struct sba_request *req, 90462306a36Sopenharmony_ci bool pq_continue, 90562306a36Sopenharmony_ci struct brcm_sba_command *cmds, 90662306a36Sopenharmony_ci struct brcm_message *msg, 90762306a36Sopenharmony_ci dma_addr_t msg_offset, size_t msg_len, 90862306a36Sopenharmony_ci dma_addr_t *dst_p, dma_addr_t *dst_q, 90962306a36Sopenharmony_ci const u8 *scf, dma_addr_t *src, u32 src_cnt) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci u64 cmd; 91262306a36Sopenharmony_ci u32 c_mdata; 91362306a36Sopenharmony_ci unsigned int i; 91462306a36Sopenharmony_ci dma_addr_t resp_dma = req->tx.phys; 91562306a36Sopenharmony_ci struct brcm_sba_command *cmdsp = cmds; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (pq_continue) { 91862306a36Sopenharmony_ci /* Type-B command to load old P into buf0 */ 91962306a36Sopenharmony_ci if (dst_p) { 92062306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 92162306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 92262306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 92362306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 92462306a36Sopenharmony_ci c_mdata = sba_cmd_load_c_mdata(0); 92562306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 92662306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 92762306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_LOAD_BUFFER, 92862306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 92962306a36Sopenharmony_ci cmdsp->cmd = cmd; 93062306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 93162306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 93262306a36Sopenharmony_ci cmdsp->data = *dst_p + msg_offset; 93362306a36Sopenharmony_ci cmdsp->data_len = msg_len; 93462306a36Sopenharmony_ci cmdsp++; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* Type-B command to load old Q into buf1 */ 93862306a36Sopenharmony_ci if (dst_q) { 93962306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 94062306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 94162306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 94262306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 94362306a36Sopenharmony_ci c_mdata = sba_cmd_load_c_mdata(1); 94462306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 94562306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 94662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_LOAD_BUFFER, 94762306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 94862306a36Sopenharmony_ci cmdsp->cmd = cmd; 94962306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 95062306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 95162306a36Sopenharmony_ci cmdsp->data = *dst_q + msg_offset; 95262306a36Sopenharmony_ci cmdsp->data_len = msg_len; 95362306a36Sopenharmony_ci cmdsp++; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci } else { 95662306a36Sopenharmony_ci /* Type-A command to zero all buffers */ 95762306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 95862306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 95962306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 96062306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 96162306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_ZERO_ALL_BUFFERS, 96262306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 96362306a36Sopenharmony_ci cmdsp->cmd = cmd; 96462306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 96562306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 96662306a36Sopenharmony_ci cmdsp++; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci /* Type-B commands for generate P onto buf0 and Q onto buf1 */ 97062306a36Sopenharmony_ci for (i = 0; i < src_cnt; i++) { 97162306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 97262306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 97362306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 97462306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 97562306a36Sopenharmony_ci c_mdata = sba_cmd_pq_c_mdata(raid6_gflog[scf[i]], 1, 0); 97662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 97762306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 97862306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_MS(c_mdata), 97962306a36Sopenharmony_ci SBA_C_MDATA_MS_SHIFT, SBA_C_MDATA_MS_MASK); 98062306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_GALOIS_XOR, 98162306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 98262306a36Sopenharmony_ci cmdsp->cmd = cmd; 98362306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 98462306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 98562306a36Sopenharmony_ci cmdsp->data = src[i] + msg_offset; 98662306a36Sopenharmony_ci cmdsp->data_len = msg_len; 98762306a36Sopenharmony_ci cmdsp++; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* Type-A command to write buf0 */ 99162306a36Sopenharmony_ci if (dst_p) { 99262306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 99362306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 99462306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 99562306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 99662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, 0x1, 99762306a36Sopenharmony_ci SBA_RESP_SHIFT, SBA_RESP_MASK); 99862306a36Sopenharmony_ci c_mdata = sba_cmd_write_c_mdata(0); 99962306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 100062306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 100162306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_WRITE_BUFFER, 100262306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 100362306a36Sopenharmony_ci cmdsp->cmd = cmd; 100462306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 100562306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 100662306a36Sopenharmony_ci if (req->sba->hw_resp_size) { 100762306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_RESP; 100862306a36Sopenharmony_ci cmdsp->resp = resp_dma; 100962306a36Sopenharmony_ci cmdsp->resp_len = req->sba->hw_resp_size; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_OUTPUT; 101262306a36Sopenharmony_ci cmdsp->data = *dst_p + msg_offset; 101362306a36Sopenharmony_ci cmdsp->data_len = msg_len; 101462306a36Sopenharmony_ci cmdsp++; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* Type-A command to write buf1 */ 101862306a36Sopenharmony_ci if (dst_q) { 101962306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 102062306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 102162306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 102262306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 102362306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, 0x1, 102462306a36Sopenharmony_ci SBA_RESP_SHIFT, SBA_RESP_MASK); 102562306a36Sopenharmony_ci c_mdata = sba_cmd_write_c_mdata(1); 102662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 102762306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 102862306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_WRITE_BUFFER, 102962306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 103062306a36Sopenharmony_ci cmdsp->cmd = cmd; 103162306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 103262306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 103362306a36Sopenharmony_ci if (req->sba->hw_resp_size) { 103462306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_RESP; 103562306a36Sopenharmony_ci cmdsp->resp = resp_dma; 103662306a36Sopenharmony_ci cmdsp->resp_len = req->sba->hw_resp_size; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_OUTPUT; 103962306a36Sopenharmony_ci cmdsp->data = *dst_q + msg_offset; 104062306a36Sopenharmony_ci cmdsp->data_len = msg_len; 104162306a36Sopenharmony_ci cmdsp++; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* Fillup brcm_message */ 104562306a36Sopenharmony_ci msg->type = BRCM_MESSAGE_SBA; 104662306a36Sopenharmony_ci msg->sba.cmds = cmds; 104762306a36Sopenharmony_ci msg->sba.cmds_count = cmdsp - cmds; 104862306a36Sopenharmony_ci msg->ctx = req; 104962306a36Sopenharmony_ci msg->error = 0; 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic struct sba_request * 105362306a36Sopenharmony_cisba_prep_dma_pq_req(struct sba_device *sba, dma_addr_t off, 105462306a36Sopenharmony_ci dma_addr_t *dst_p, dma_addr_t *dst_q, dma_addr_t *src, 105562306a36Sopenharmony_ci u32 src_cnt, const u8 *scf, size_t len, unsigned long flags) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci struct sba_request *req = NULL; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci /* Alloc new request */ 106062306a36Sopenharmony_ci req = sba_alloc_request(sba); 106162306a36Sopenharmony_ci if (!req) 106262306a36Sopenharmony_ci return NULL; 106362306a36Sopenharmony_ci if (flags & DMA_PREP_FENCE) 106462306a36Sopenharmony_ci req->flags |= SBA_REQUEST_FENCE; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci /* Fillup request messages */ 106762306a36Sopenharmony_ci sba_fillup_pq_msg(req, dmaf_continue(flags), 106862306a36Sopenharmony_ci req->cmds, &req->msg, 106962306a36Sopenharmony_ci off, len, dst_p, dst_q, scf, src, src_cnt); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* Init async_tx descriptor */ 107262306a36Sopenharmony_ci req->tx.flags = flags; 107362306a36Sopenharmony_ci req->tx.cookie = -EBUSY; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return req; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic void sba_fillup_pq_single_msg(struct sba_request *req, 107962306a36Sopenharmony_ci bool pq_continue, 108062306a36Sopenharmony_ci struct brcm_sba_command *cmds, 108162306a36Sopenharmony_ci struct brcm_message *msg, 108262306a36Sopenharmony_ci dma_addr_t msg_offset, size_t msg_len, 108362306a36Sopenharmony_ci dma_addr_t *dst_p, dma_addr_t *dst_q, 108462306a36Sopenharmony_ci dma_addr_t src, u8 scf) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci u64 cmd; 108762306a36Sopenharmony_ci u32 c_mdata; 108862306a36Sopenharmony_ci u8 pos, dpos = raid6_gflog[scf]; 108962306a36Sopenharmony_ci dma_addr_t resp_dma = req->tx.phys; 109062306a36Sopenharmony_ci struct brcm_sba_command *cmdsp = cmds; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (!dst_p) 109362306a36Sopenharmony_ci goto skip_p; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (pq_continue) { 109662306a36Sopenharmony_ci /* Type-B command to load old P into buf0 */ 109762306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 109862306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 109962306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 110062306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 110162306a36Sopenharmony_ci c_mdata = sba_cmd_load_c_mdata(0); 110262306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 110362306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 110462306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_LOAD_BUFFER, 110562306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 110662306a36Sopenharmony_ci cmdsp->cmd = cmd; 110762306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 110862306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 110962306a36Sopenharmony_ci cmdsp->data = *dst_p + msg_offset; 111062306a36Sopenharmony_ci cmdsp->data_len = msg_len; 111162306a36Sopenharmony_ci cmdsp++; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* 111462306a36Sopenharmony_ci * Type-B commands to xor data with buf0 and put it 111562306a36Sopenharmony_ci * back in buf0 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 111862306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 111962306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 112062306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 112162306a36Sopenharmony_ci c_mdata = sba_cmd_xor_c_mdata(0, 0); 112262306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 112362306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 112462306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_XOR, 112562306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 112662306a36Sopenharmony_ci cmdsp->cmd = cmd; 112762306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 112862306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 112962306a36Sopenharmony_ci cmdsp->data = src + msg_offset; 113062306a36Sopenharmony_ci cmdsp->data_len = msg_len; 113162306a36Sopenharmony_ci cmdsp++; 113262306a36Sopenharmony_ci } else { 113362306a36Sopenharmony_ci /* Type-B command to load old P into buf0 */ 113462306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 113562306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 113662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 113762306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 113862306a36Sopenharmony_ci c_mdata = sba_cmd_load_c_mdata(0); 113962306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 114062306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 114162306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_LOAD_BUFFER, 114262306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 114362306a36Sopenharmony_ci cmdsp->cmd = cmd; 114462306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 114562306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 114662306a36Sopenharmony_ci cmdsp->data = src + msg_offset; 114762306a36Sopenharmony_ci cmdsp->data_len = msg_len; 114862306a36Sopenharmony_ci cmdsp++; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci /* Type-A command to write buf0 */ 115262306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 115362306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 115462306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 115562306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 115662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, 0x1, 115762306a36Sopenharmony_ci SBA_RESP_SHIFT, SBA_RESP_MASK); 115862306a36Sopenharmony_ci c_mdata = sba_cmd_write_c_mdata(0); 115962306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 116062306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 116162306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_WRITE_BUFFER, 116262306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 116362306a36Sopenharmony_ci cmdsp->cmd = cmd; 116462306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 116562306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 116662306a36Sopenharmony_ci if (req->sba->hw_resp_size) { 116762306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_RESP; 116862306a36Sopenharmony_ci cmdsp->resp = resp_dma; 116962306a36Sopenharmony_ci cmdsp->resp_len = req->sba->hw_resp_size; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_OUTPUT; 117262306a36Sopenharmony_ci cmdsp->data = *dst_p + msg_offset; 117362306a36Sopenharmony_ci cmdsp->data_len = msg_len; 117462306a36Sopenharmony_ci cmdsp++; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ciskip_p: 117762306a36Sopenharmony_ci if (!dst_q) 117862306a36Sopenharmony_ci goto skip_q; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* Type-A command to zero all buffers */ 118162306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 118262306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 118362306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 118462306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 118562306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_ZERO_ALL_BUFFERS, 118662306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 118762306a36Sopenharmony_ci cmdsp->cmd = cmd; 118862306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 118962306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 119062306a36Sopenharmony_ci cmdsp++; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (dpos == 255) 119362306a36Sopenharmony_ci goto skip_q_computation; 119462306a36Sopenharmony_ci pos = (dpos < req->sba->max_pq_coefs) ? 119562306a36Sopenharmony_ci dpos : (req->sba->max_pq_coefs - 1); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci /* 119862306a36Sopenharmony_ci * Type-B command to generate initial Q from data 119962306a36Sopenharmony_ci * and store output into buf0 120062306a36Sopenharmony_ci */ 120162306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 120262306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 120362306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 120462306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 120562306a36Sopenharmony_ci c_mdata = sba_cmd_pq_c_mdata(pos, 0, 0); 120662306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 120762306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 120862306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_MS(c_mdata), 120962306a36Sopenharmony_ci SBA_C_MDATA_MS_SHIFT, SBA_C_MDATA_MS_MASK); 121062306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_GALOIS, 121162306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 121262306a36Sopenharmony_ci cmdsp->cmd = cmd; 121362306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 121462306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 121562306a36Sopenharmony_ci cmdsp->data = src + msg_offset; 121662306a36Sopenharmony_ci cmdsp->data_len = msg_len; 121762306a36Sopenharmony_ci cmdsp++; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci dpos -= pos; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci /* Multiple Type-A command to generate final Q */ 122262306a36Sopenharmony_ci while (dpos) { 122362306a36Sopenharmony_ci pos = (dpos < req->sba->max_pq_coefs) ? 122462306a36Sopenharmony_ci dpos : (req->sba->max_pq_coefs - 1); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci /* 122762306a36Sopenharmony_ci * Type-A command to generate Q with buf0 and 122862306a36Sopenharmony_ci * buf1 store result in buf0 122962306a36Sopenharmony_ci */ 123062306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 123162306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 123262306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 123362306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 123462306a36Sopenharmony_ci c_mdata = sba_cmd_pq_c_mdata(pos, 0, 1); 123562306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 123662306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 123762306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_MS(c_mdata), 123862306a36Sopenharmony_ci SBA_C_MDATA_MS_SHIFT, SBA_C_MDATA_MS_MASK); 123962306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_GALOIS, 124062306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 124162306a36Sopenharmony_ci cmdsp->cmd = cmd; 124262306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 124362306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 124462306a36Sopenharmony_ci cmdsp++; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci dpos -= pos; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ciskip_q_computation: 125062306a36Sopenharmony_ci if (pq_continue) { 125162306a36Sopenharmony_ci /* 125262306a36Sopenharmony_ci * Type-B command to XOR previous output with 125362306a36Sopenharmony_ci * buf0 and write it into buf0 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_B, 125662306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 125762306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 125862306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 125962306a36Sopenharmony_ci c_mdata = sba_cmd_xor_c_mdata(0, 0); 126062306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 126162306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 126262306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_XOR, 126362306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 126462306a36Sopenharmony_ci cmdsp->cmd = cmd; 126562306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 126662306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_B; 126762306a36Sopenharmony_ci cmdsp->data = *dst_q + msg_offset; 126862306a36Sopenharmony_ci cmdsp->data_len = msg_len; 126962306a36Sopenharmony_ci cmdsp++; 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci /* Type-A command to write buf0 */ 127362306a36Sopenharmony_ci cmd = sba_cmd_enc(0x0, SBA_TYPE_A, 127462306a36Sopenharmony_ci SBA_TYPE_SHIFT, SBA_TYPE_MASK); 127562306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, msg_len, 127662306a36Sopenharmony_ci SBA_USER_DEF_SHIFT, SBA_USER_DEF_MASK); 127762306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, 0x1, 127862306a36Sopenharmony_ci SBA_RESP_SHIFT, SBA_RESP_MASK); 127962306a36Sopenharmony_ci c_mdata = sba_cmd_write_c_mdata(0); 128062306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_C_MDATA_LS(c_mdata), 128162306a36Sopenharmony_ci SBA_C_MDATA_SHIFT, SBA_C_MDATA_MASK); 128262306a36Sopenharmony_ci cmd = sba_cmd_enc(cmd, SBA_CMD_WRITE_BUFFER, 128362306a36Sopenharmony_ci SBA_CMD_SHIFT, SBA_CMD_MASK); 128462306a36Sopenharmony_ci cmdsp->cmd = cmd; 128562306a36Sopenharmony_ci *cmdsp->cmd_dma = cpu_to_le64(cmd); 128662306a36Sopenharmony_ci cmdsp->flags = BRCM_SBA_CMD_TYPE_A; 128762306a36Sopenharmony_ci if (req->sba->hw_resp_size) { 128862306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_RESP; 128962306a36Sopenharmony_ci cmdsp->resp = resp_dma; 129062306a36Sopenharmony_ci cmdsp->resp_len = req->sba->hw_resp_size; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci cmdsp->flags |= BRCM_SBA_CMD_HAS_OUTPUT; 129362306a36Sopenharmony_ci cmdsp->data = *dst_q + msg_offset; 129462306a36Sopenharmony_ci cmdsp->data_len = msg_len; 129562306a36Sopenharmony_ci cmdsp++; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ciskip_q: 129862306a36Sopenharmony_ci /* Fillup brcm_message */ 129962306a36Sopenharmony_ci msg->type = BRCM_MESSAGE_SBA; 130062306a36Sopenharmony_ci msg->sba.cmds = cmds; 130162306a36Sopenharmony_ci msg->sba.cmds_count = cmdsp - cmds; 130262306a36Sopenharmony_ci msg->ctx = req; 130362306a36Sopenharmony_ci msg->error = 0; 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cistatic struct sba_request * 130762306a36Sopenharmony_cisba_prep_dma_pq_single_req(struct sba_device *sba, dma_addr_t off, 130862306a36Sopenharmony_ci dma_addr_t *dst_p, dma_addr_t *dst_q, 130962306a36Sopenharmony_ci dma_addr_t src, u8 scf, size_t len, 131062306a36Sopenharmony_ci unsigned long flags) 131162306a36Sopenharmony_ci{ 131262306a36Sopenharmony_ci struct sba_request *req = NULL; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci /* Alloc new request */ 131562306a36Sopenharmony_ci req = sba_alloc_request(sba); 131662306a36Sopenharmony_ci if (!req) 131762306a36Sopenharmony_ci return NULL; 131862306a36Sopenharmony_ci if (flags & DMA_PREP_FENCE) 131962306a36Sopenharmony_ci req->flags |= SBA_REQUEST_FENCE; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* Fillup request messages */ 132262306a36Sopenharmony_ci sba_fillup_pq_single_msg(req, dmaf_continue(flags), 132362306a36Sopenharmony_ci req->cmds, &req->msg, off, len, 132462306a36Sopenharmony_ci dst_p, dst_q, src, scf); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* Init async_tx descriptor */ 132762306a36Sopenharmony_ci req->tx.flags = flags; 132862306a36Sopenharmony_ci req->tx.cookie = -EBUSY; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci return req; 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 133462306a36Sopenharmony_cisba_prep_dma_pq(struct dma_chan *dchan, dma_addr_t *dst, dma_addr_t *src, 133562306a36Sopenharmony_ci u32 src_cnt, const u8 *scf, size_t len, unsigned long flags) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci u32 i, dst_q_index; 133862306a36Sopenharmony_ci size_t req_len; 133962306a36Sopenharmony_ci bool slow = false; 134062306a36Sopenharmony_ci dma_addr_t off = 0; 134162306a36Sopenharmony_ci dma_addr_t *dst_p = NULL, *dst_q = NULL; 134262306a36Sopenharmony_ci struct sba_device *sba = to_sba_device(dchan); 134362306a36Sopenharmony_ci struct sba_request *first = NULL, *req; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci /* Sanity checks */ 134662306a36Sopenharmony_ci if (unlikely(src_cnt > sba->max_pq_srcs)) 134762306a36Sopenharmony_ci return NULL; 134862306a36Sopenharmony_ci for (i = 0; i < src_cnt; i++) 134962306a36Sopenharmony_ci if (sba->max_pq_coefs <= raid6_gflog[scf[i]]) 135062306a36Sopenharmony_ci slow = true; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci /* Figure-out P and Q destination addresses */ 135362306a36Sopenharmony_ci if (!(flags & DMA_PREP_PQ_DISABLE_P)) 135462306a36Sopenharmony_ci dst_p = &dst[0]; 135562306a36Sopenharmony_ci if (!(flags & DMA_PREP_PQ_DISABLE_Q)) 135662306a36Sopenharmony_ci dst_q = &dst[1]; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci /* Create chained requests where each request is upto hw_buf_size */ 135962306a36Sopenharmony_ci while (len) { 136062306a36Sopenharmony_ci req_len = (len < sba->hw_buf_size) ? len : sba->hw_buf_size; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (slow) { 136362306a36Sopenharmony_ci dst_q_index = src_cnt; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci if (dst_q) { 136662306a36Sopenharmony_ci for (i = 0; i < src_cnt; i++) { 136762306a36Sopenharmony_ci if (*dst_q == src[i]) { 136862306a36Sopenharmony_ci dst_q_index = i; 136962306a36Sopenharmony_ci break; 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if (dst_q_index < src_cnt) { 137562306a36Sopenharmony_ci i = dst_q_index; 137662306a36Sopenharmony_ci req = sba_prep_dma_pq_single_req(sba, 137762306a36Sopenharmony_ci off, dst_p, dst_q, src[i], scf[i], 137862306a36Sopenharmony_ci req_len, flags | DMA_PREP_FENCE); 137962306a36Sopenharmony_ci if (!req) 138062306a36Sopenharmony_ci goto fail; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (first) 138362306a36Sopenharmony_ci sba_chain_request(first, req); 138462306a36Sopenharmony_ci else 138562306a36Sopenharmony_ci first = req; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci flags |= DMA_PREP_CONTINUE; 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci for (i = 0; i < src_cnt; i++) { 139162306a36Sopenharmony_ci if (dst_q_index == i) 139262306a36Sopenharmony_ci continue; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci req = sba_prep_dma_pq_single_req(sba, 139562306a36Sopenharmony_ci off, dst_p, dst_q, src[i], scf[i], 139662306a36Sopenharmony_ci req_len, flags | DMA_PREP_FENCE); 139762306a36Sopenharmony_ci if (!req) 139862306a36Sopenharmony_ci goto fail; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (first) 140162306a36Sopenharmony_ci sba_chain_request(first, req); 140262306a36Sopenharmony_ci else 140362306a36Sopenharmony_ci first = req; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci flags |= DMA_PREP_CONTINUE; 140662306a36Sopenharmony_ci } 140762306a36Sopenharmony_ci } else { 140862306a36Sopenharmony_ci req = sba_prep_dma_pq_req(sba, off, 140962306a36Sopenharmony_ci dst_p, dst_q, src, src_cnt, 141062306a36Sopenharmony_ci scf, req_len, flags); 141162306a36Sopenharmony_ci if (!req) 141262306a36Sopenharmony_ci goto fail; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (first) 141562306a36Sopenharmony_ci sba_chain_request(first, req); 141662306a36Sopenharmony_ci else 141762306a36Sopenharmony_ci first = req; 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci off += req_len; 142162306a36Sopenharmony_ci len -= req_len; 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return (first) ? &first->tx : NULL; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_cifail: 142762306a36Sopenharmony_ci if (first) 142862306a36Sopenharmony_ci sba_free_chained_requests(first); 142962306a36Sopenharmony_ci return NULL; 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci/* ====== Mailbox callbacks ===== */ 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_cistatic void sba_receive_message(struct mbox_client *cl, void *msg) 143562306a36Sopenharmony_ci{ 143662306a36Sopenharmony_ci struct brcm_message *m = msg; 143762306a36Sopenharmony_ci struct sba_request *req = m->ctx; 143862306a36Sopenharmony_ci struct sba_device *sba = req->sba; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* Error count if message has error */ 144162306a36Sopenharmony_ci if (m->error < 0) 144262306a36Sopenharmony_ci dev_err(sba->dev, "%s got message with error %d", 144362306a36Sopenharmony_ci dma_chan_name(&sba->dma_chan), m->error); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci /* Process received request */ 144662306a36Sopenharmony_ci sba_process_received_request(sba, req); 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci/* ====== Debugfs callbacks ====== */ 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_cistatic int sba_debugfs_stats_show(struct seq_file *file, void *offset) 145262306a36Sopenharmony_ci{ 145362306a36Sopenharmony_ci struct sba_device *sba = dev_get_drvdata(file->private); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci /* Write stats in file */ 145662306a36Sopenharmony_ci sba_write_stats_in_seqfile(sba, file); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci return 0; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci/* ====== Platform driver routines ===== */ 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_cistatic int sba_prealloc_channel_resources(struct sba_device *sba) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci int i, j, ret = 0; 146662306a36Sopenharmony_ci struct sba_request *req = NULL; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci sba->resp_base = dma_alloc_coherent(sba->mbox_dev, 146962306a36Sopenharmony_ci sba->max_resp_pool_size, 147062306a36Sopenharmony_ci &sba->resp_dma_base, GFP_KERNEL); 147162306a36Sopenharmony_ci if (!sba->resp_base) 147262306a36Sopenharmony_ci return -ENOMEM; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci sba->cmds_base = dma_alloc_coherent(sba->mbox_dev, 147562306a36Sopenharmony_ci sba->max_cmds_pool_size, 147662306a36Sopenharmony_ci &sba->cmds_dma_base, GFP_KERNEL); 147762306a36Sopenharmony_ci if (!sba->cmds_base) { 147862306a36Sopenharmony_ci ret = -ENOMEM; 147962306a36Sopenharmony_ci goto fail_free_resp_pool; 148062306a36Sopenharmony_ci } 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci spin_lock_init(&sba->reqs_lock); 148362306a36Sopenharmony_ci sba->reqs_fence = false; 148462306a36Sopenharmony_ci INIT_LIST_HEAD(&sba->reqs_alloc_list); 148562306a36Sopenharmony_ci INIT_LIST_HEAD(&sba->reqs_pending_list); 148662306a36Sopenharmony_ci INIT_LIST_HEAD(&sba->reqs_active_list); 148762306a36Sopenharmony_ci INIT_LIST_HEAD(&sba->reqs_aborted_list); 148862306a36Sopenharmony_ci INIT_LIST_HEAD(&sba->reqs_free_list); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci for (i = 0; i < sba->max_req; i++) { 149162306a36Sopenharmony_ci req = devm_kzalloc(sba->dev, 149262306a36Sopenharmony_ci struct_size(req, cmds, sba->max_cmd_per_req), 149362306a36Sopenharmony_ci GFP_KERNEL); 149462306a36Sopenharmony_ci if (!req) { 149562306a36Sopenharmony_ci ret = -ENOMEM; 149662306a36Sopenharmony_ci goto fail_free_cmds_pool; 149762306a36Sopenharmony_ci } 149862306a36Sopenharmony_ci INIT_LIST_HEAD(&req->node); 149962306a36Sopenharmony_ci req->sba = sba; 150062306a36Sopenharmony_ci req->flags = SBA_REQUEST_STATE_FREE; 150162306a36Sopenharmony_ci INIT_LIST_HEAD(&req->next); 150262306a36Sopenharmony_ci atomic_set(&req->next_pending_count, 0); 150362306a36Sopenharmony_ci for (j = 0; j < sba->max_cmd_per_req; j++) { 150462306a36Sopenharmony_ci req->cmds[j].cmd = 0; 150562306a36Sopenharmony_ci req->cmds[j].cmd_dma = sba->cmds_base + 150662306a36Sopenharmony_ci (i * sba->max_cmd_per_req + j) * sizeof(u64); 150762306a36Sopenharmony_ci req->cmds[j].cmd_dma_addr = sba->cmds_dma_base + 150862306a36Sopenharmony_ci (i * sba->max_cmd_per_req + j) * sizeof(u64); 150962306a36Sopenharmony_ci req->cmds[j].flags = 0; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci memset(&req->msg, 0, sizeof(req->msg)); 151262306a36Sopenharmony_ci dma_async_tx_descriptor_init(&req->tx, &sba->dma_chan); 151362306a36Sopenharmony_ci async_tx_ack(&req->tx); 151462306a36Sopenharmony_ci req->tx.tx_submit = sba_tx_submit; 151562306a36Sopenharmony_ci req->tx.phys = sba->resp_dma_base + i * sba->hw_resp_size; 151662306a36Sopenharmony_ci list_add_tail(&req->node, &sba->reqs_free_list); 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci return 0; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_cifail_free_cmds_pool: 152262306a36Sopenharmony_ci dma_free_coherent(sba->mbox_dev, 152362306a36Sopenharmony_ci sba->max_cmds_pool_size, 152462306a36Sopenharmony_ci sba->cmds_base, sba->cmds_dma_base); 152562306a36Sopenharmony_cifail_free_resp_pool: 152662306a36Sopenharmony_ci dma_free_coherent(sba->mbox_dev, 152762306a36Sopenharmony_ci sba->max_resp_pool_size, 152862306a36Sopenharmony_ci sba->resp_base, sba->resp_dma_base); 152962306a36Sopenharmony_ci return ret; 153062306a36Sopenharmony_ci} 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_cistatic void sba_freeup_channel_resources(struct sba_device *sba) 153362306a36Sopenharmony_ci{ 153462306a36Sopenharmony_ci dmaengine_terminate_all(&sba->dma_chan); 153562306a36Sopenharmony_ci dma_free_coherent(sba->mbox_dev, sba->max_cmds_pool_size, 153662306a36Sopenharmony_ci sba->cmds_base, sba->cmds_dma_base); 153762306a36Sopenharmony_ci dma_free_coherent(sba->mbox_dev, sba->max_resp_pool_size, 153862306a36Sopenharmony_ci sba->resp_base, sba->resp_dma_base); 153962306a36Sopenharmony_ci sba->resp_base = NULL; 154062306a36Sopenharmony_ci sba->resp_dma_base = 0; 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_cistatic int sba_async_register(struct sba_device *sba) 154462306a36Sopenharmony_ci{ 154562306a36Sopenharmony_ci int ret; 154662306a36Sopenharmony_ci struct dma_device *dma_dev = &sba->dma_dev; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci /* Initialize DMA channel cookie */ 154962306a36Sopenharmony_ci sba->dma_chan.device = dma_dev; 155062306a36Sopenharmony_ci dma_cookie_init(&sba->dma_chan); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci /* Initialize DMA device capability mask */ 155362306a36Sopenharmony_ci dma_cap_zero(dma_dev->cap_mask); 155462306a36Sopenharmony_ci dma_cap_set(DMA_INTERRUPT, dma_dev->cap_mask); 155562306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask); 155662306a36Sopenharmony_ci dma_cap_set(DMA_XOR, dma_dev->cap_mask); 155762306a36Sopenharmony_ci dma_cap_set(DMA_PQ, dma_dev->cap_mask); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci /* 156062306a36Sopenharmony_ci * Set mailbox channel device as the base device of 156162306a36Sopenharmony_ci * our dma_device because the actual memory accesses 156262306a36Sopenharmony_ci * will be done by mailbox controller 156362306a36Sopenharmony_ci */ 156462306a36Sopenharmony_ci dma_dev->dev = sba->mbox_dev; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci /* Set base prep routines */ 156762306a36Sopenharmony_ci dma_dev->device_free_chan_resources = sba_free_chan_resources; 156862306a36Sopenharmony_ci dma_dev->device_terminate_all = sba_device_terminate_all; 156962306a36Sopenharmony_ci dma_dev->device_issue_pending = sba_issue_pending; 157062306a36Sopenharmony_ci dma_dev->device_tx_status = sba_tx_status; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci /* Set interrupt routine */ 157362306a36Sopenharmony_ci if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask)) 157462306a36Sopenharmony_ci dma_dev->device_prep_dma_interrupt = sba_prep_dma_interrupt; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci /* Set memcpy routine */ 157762306a36Sopenharmony_ci if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) 157862306a36Sopenharmony_ci dma_dev->device_prep_dma_memcpy = sba_prep_dma_memcpy; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci /* Set xor routine and capability */ 158162306a36Sopenharmony_ci if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { 158262306a36Sopenharmony_ci dma_dev->device_prep_dma_xor = sba_prep_dma_xor; 158362306a36Sopenharmony_ci dma_dev->max_xor = sba->max_xor_srcs; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci /* Set pq routine and capability */ 158762306a36Sopenharmony_ci if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { 158862306a36Sopenharmony_ci dma_dev->device_prep_dma_pq = sba_prep_dma_pq; 158962306a36Sopenharmony_ci dma_set_maxpq(dma_dev, sba->max_pq_srcs, 0); 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci /* Initialize DMA device channel list */ 159362306a36Sopenharmony_ci INIT_LIST_HEAD(&dma_dev->channels); 159462306a36Sopenharmony_ci list_add_tail(&sba->dma_chan.device_node, &dma_dev->channels); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci /* Register with Linux async DMA framework*/ 159762306a36Sopenharmony_ci ret = dma_async_device_register(dma_dev); 159862306a36Sopenharmony_ci if (ret) { 159962306a36Sopenharmony_ci dev_err(sba->dev, "async device register error %d", ret); 160062306a36Sopenharmony_ci return ret; 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci dev_info(sba->dev, "%s capabilities: %s%s%s%s\n", 160462306a36Sopenharmony_ci dma_chan_name(&sba->dma_chan), 160562306a36Sopenharmony_ci dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "interrupt " : "", 160662306a36Sopenharmony_ci dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "memcpy " : "", 160762306a36Sopenharmony_ci dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "", 160862306a36Sopenharmony_ci dma_has_cap(DMA_PQ, dma_dev->cap_mask) ? "pq " : ""); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci return 0; 161162306a36Sopenharmony_ci} 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_cistatic int sba_probe(struct platform_device *pdev) 161462306a36Sopenharmony_ci{ 161562306a36Sopenharmony_ci int ret = 0; 161662306a36Sopenharmony_ci struct sba_device *sba; 161762306a36Sopenharmony_ci struct platform_device *mbox_pdev; 161862306a36Sopenharmony_ci struct of_phandle_args args; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci /* Allocate main SBA struct */ 162162306a36Sopenharmony_ci sba = devm_kzalloc(&pdev->dev, sizeof(*sba), GFP_KERNEL); 162262306a36Sopenharmony_ci if (!sba) 162362306a36Sopenharmony_ci return -ENOMEM; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci sba->dev = &pdev->dev; 162662306a36Sopenharmony_ci platform_set_drvdata(pdev, sba); 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci /* Number of mailbox channels should be atleast 1 */ 162962306a36Sopenharmony_ci ret = of_count_phandle_with_args(pdev->dev.of_node, 163062306a36Sopenharmony_ci "mboxes", "#mbox-cells"); 163162306a36Sopenharmony_ci if (ret <= 0) 163262306a36Sopenharmony_ci return -ENODEV; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci /* Determine SBA version from DT compatible string */ 163562306a36Sopenharmony_ci if (of_device_is_compatible(sba->dev->of_node, "brcm,iproc-sba")) 163662306a36Sopenharmony_ci sba->ver = SBA_VER_1; 163762306a36Sopenharmony_ci else if (of_device_is_compatible(sba->dev->of_node, 163862306a36Sopenharmony_ci "brcm,iproc-sba-v2")) 163962306a36Sopenharmony_ci sba->ver = SBA_VER_2; 164062306a36Sopenharmony_ci else 164162306a36Sopenharmony_ci return -ENODEV; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci /* Derived Configuration parameters */ 164462306a36Sopenharmony_ci switch (sba->ver) { 164562306a36Sopenharmony_ci case SBA_VER_1: 164662306a36Sopenharmony_ci sba->hw_buf_size = 4096; 164762306a36Sopenharmony_ci sba->hw_resp_size = 8; 164862306a36Sopenharmony_ci sba->max_pq_coefs = 6; 164962306a36Sopenharmony_ci sba->max_pq_srcs = 6; 165062306a36Sopenharmony_ci break; 165162306a36Sopenharmony_ci case SBA_VER_2: 165262306a36Sopenharmony_ci sba->hw_buf_size = 4096; 165362306a36Sopenharmony_ci sba->hw_resp_size = 8; 165462306a36Sopenharmony_ci sba->max_pq_coefs = 30; 165562306a36Sopenharmony_ci /* 165662306a36Sopenharmony_ci * We can support max_pq_srcs == max_pq_coefs because 165762306a36Sopenharmony_ci * we are limited by number of SBA commands that we can 165862306a36Sopenharmony_ci * fit in one message for underlying ring manager HW. 165962306a36Sopenharmony_ci */ 166062306a36Sopenharmony_ci sba->max_pq_srcs = 12; 166162306a36Sopenharmony_ci break; 166262306a36Sopenharmony_ci default: 166362306a36Sopenharmony_ci return -EINVAL; 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci sba->max_req = SBA_MAX_REQ_PER_MBOX_CHANNEL; 166662306a36Sopenharmony_ci sba->max_cmd_per_req = sba->max_pq_srcs + 3; 166762306a36Sopenharmony_ci sba->max_xor_srcs = sba->max_cmd_per_req - 1; 166862306a36Sopenharmony_ci sba->max_resp_pool_size = sba->max_req * sba->hw_resp_size; 166962306a36Sopenharmony_ci sba->max_cmds_pool_size = sba->max_req * 167062306a36Sopenharmony_ci sba->max_cmd_per_req * sizeof(u64); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci /* Setup mailbox client */ 167362306a36Sopenharmony_ci sba->client.dev = &pdev->dev; 167462306a36Sopenharmony_ci sba->client.rx_callback = sba_receive_message; 167562306a36Sopenharmony_ci sba->client.tx_block = false; 167662306a36Sopenharmony_ci sba->client.knows_txdone = true; 167762306a36Sopenharmony_ci sba->client.tx_tout = 0; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci /* Request mailbox channel */ 168062306a36Sopenharmony_ci sba->mchan = mbox_request_channel(&sba->client, 0); 168162306a36Sopenharmony_ci if (IS_ERR(sba->mchan)) { 168262306a36Sopenharmony_ci ret = PTR_ERR(sba->mchan); 168362306a36Sopenharmony_ci goto fail_free_mchan; 168462306a36Sopenharmony_ci } 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci /* Find-out underlying mailbox device */ 168762306a36Sopenharmony_ci ret = of_parse_phandle_with_args(pdev->dev.of_node, 168862306a36Sopenharmony_ci "mboxes", "#mbox-cells", 0, &args); 168962306a36Sopenharmony_ci if (ret) 169062306a36Sopenharmony_ci goto fail_free_mchan; 169162306a36Sopenharmony_ci mbox_pdev = of_find_device_by_node(args.np); 169262306a36Sopenharmony_ci of_node_put(args.np); 169362306a36Sopenharmony_ci if (!mbox_pdev) { 169462306a36Sopenharmony_ci ret = -ENODEV; 169562306a36Sopenharmony_ci goto fail_free_mchan; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci sba->mbox_dev = &mbox_pdev->dev; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci /* Prealloc channel resource */ 170062306a36Sopenharmony_ci ret = sba_prealloc_channel_resources(sba); 170162306a36Sopenharmony_ci if (ret) 170262306a36Sopenharmony_ci goto fail_free_mchan; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci /* Check availability of debugfs */ 170562306a36Sopenharmony_ci if (!debugfs_initialized()) 170662306a36Sopenharmony_ci goto skip_debugfs; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci /* Create debugfs root entry */ 170962306a36Sopenharmony_ci sba->root = debugfs_create_dir(dev_name(sba->dev), NULL); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci /* Create debugfs stats entry */ 171262306a36Sopenharmony_ci debugfs_create_devm_seqfile(sba->dev, "stats", sba->root, 171362306a36Sopenharmony_ci sba_debugfs_stats_show); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ciskip_debugfs: 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci /* Register DMA device with Linux async framework */ 171862306a36Sopenharmony_ci ret = sba_async_register(sba); 171962306a36Sopenharmony_ci if (ret) 172062306a36Sopenharmony_ci goto fail_free_resources; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci /* Print device info */ 172362306a36Sopenharmony_ci dev_info(sba->dev, "%s using SBAv%d mailbox channel from %s", 172462306a36Sopenharmony_ci dma_chan_name(&sba->dma_chan), sba->ver+1, 172562306a36Sopenharmony_ci dev_name(sba->mbox_dev)); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci return 0; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_cifail_free_resources: 173062306a36Sopenharmony_ci debugfs_remove_recursive(sba->root); 173162306a36Sopenharmony_ci sba_freeup_channel_resources(sba); 173262306a36Sopenharmony_cifail_free_mchan: 173362306a36Sopenharmony_ci mbox_free_channel(sba->mchan); 173462306a36Sopenharmony_ci return ret; 173562306a36Sopenharmony_ci} 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_cistatic int sba_remove(struct platform_device *pdev) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci struct sba_device *sba = platform_get_drvdata(pdev); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci dma_async_device_unregister(&sba->dma_dev); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci debugfs_remove_recursive(sba->root); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci sba_freeup_channel_resources(sba); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci mbox_free_channel(sba->mchan); 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci return 0; 175062306a36Sopenharmony_ci} 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_cistatic const struct of_device_id sba_of_match[] = { 175362306a36Sopenharmony_ci { .compatible = "brcm,iproc-sba", }, 175462306a36Sopenharmony_ci { .compatible = "brcm,iproc-sba-v2", }, 175562306a36Sopenharmony_ci {}, 175662306a36Sopenharmony_ci}; 175762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sba_of_match); 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_cistatic struct platform_driver sba_driver = { 176062306a36Sopenharmony_ci .probe = sba_probe, 176162306a36Sopenharmony_ci .remove = sba_remove, 176262306a36Sopenharmony_ci .driver = { 176362306a36Sopenharmony_ci .name = "bcm-sba-raid", 176462306a36Sopenharmony_ci .of_match_table = sba_of_match, 176562306a36Sopenharmony_ci }, 176662306a36Sopenharmony_ci}; 176762306a36Sopenharmony_cimodule_platform_driver(sba_driver); 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ciMODULE_DESCRIPTION("Broadcom SBA RAID driver"); 177062306a36Sopenharmony_ciMODULE_AUTHOR("Anup Patel <anup.patel@broadcom.com>"); 177162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1772