mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
PCI: rockchip: dw: Support get_dma_status for polling DMA status
1.Support get_dma_status for polling DMA status 2.Remove the struct of dw_pcie from dmatest Change-Id: Ifef2b9172234e597354d9ae410d3f39be55cc6a8 Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
This commit is contained in:
@@ -49,44 +49,10 @@ MODULE_PARM_DESC(test_dev, "Choose dma_obj device,(default 0)");
|
||||
|
||||
#define PCIE_DW_MISC_DMATEST_DEV_MAX 5
|
||||
|
||||
#define PCIE_DMA_OFFSET 0x380000
|
||||
|
||||
#define PCIE_DMA_CTRL_OFF 0x8
|
||||
#define PCIE_DMA_WR_ENB 0xc
|
||||
#define PCIE_DMA_WR_CTRL_LO 0x200
|
||||
#define PCIE_DMA_WR_CTRL_HI 0x204
|
||||
#define PCIE_DMA_WR_XFERSIZE 0x208
|
||||
#define PCIE_DMA_WR_SAR_PTR_LO 0x20c
|
||||
#define PCIE_DMA_WR_SAR_PTR_HI 0x210
|
||||
#define PCIE_DMA_WR_DAR_PTR_LO 0x214
|
||||
#define PCIE_DMA_WR_DAR_PTR_HI 0x218
|
||||
#define PCIE_DMA_WR_WEILO 0x18
|
||||
#define PCIE_DMA_WR_WEIHI 0x1c
|
||||
#define PCIE_DMA_WR_DOORBELL 0x10
|
||||
#define PCIE_DMA_WR_INT_STATUS 0x4c
|
||||
#define PCIE_DMA_WR_INT_MASK 0x54
|
||||
#define PCIE_DMA_WR_INT_CLEAR 0x58
|
||||
|
||||
#define PCIE_DMA_RD_ENB 0x2c
|
||||
#define PCIE_DMA_RD_CTRL_LO 0x300
|
||||
#define PCIE_DMA_RD_CTRL_HI 0x304
|
||||
#define PCIE_DMA_RD_XFERSIZE 0x308
|
||||
#define PCIE_DMA_RD_SAR_PTR_LO 0x30c
|
||||
#define PCIE_DMA_RD_SAR_PTR_HI 0x310
|
||||
#define PCIE_DMA_RD_DAR_PTR_LO 0x314
|
||||
#define PCIE_DMA_RD_DAR_PTR_HI 0x318
|
||||
#define PCIE_DMA_RD_WEILO 0x38
|
||||
#define PCIE_DMA_RD_WEIHI 0x3c
|
||||
#define PCIE_DMA_RD_DOORBELL 0x30
|
||||
#define PCIE_DMA_RD_INT_STATUS 0xa0
|
||||
#define PCIE_DMA_RD_INT_MASK 0xa8
|
||||
#define PCIE_DMA_RD_INT_CLEAR 0xac
|
||||
|
||||
#define PCIE_DMA_CHANEL_MAX_NUM 2
|
||||
|
||||
struct pcie_dw_dmatest_dev {
|
||||
struct dma_trx_obj *obj;
|
||||
struct dw_pcie *pci;
|
||||
|
||||
bool irq_en;
|
||||
struct completion rd_done[PCIE_DMA_CHANEL_MAX_NUM];
|
||||
@@ -113,55 +79,12 @@ static void pcie_dw_dmatest_show(void)
|
||||
dev_info(s_dmatest_dev[test_dev].obj->dev, " is current test_dev\n");
|
||||
}
|
||||
|
||||
static int rk_pcie_get_dma_status(struct dw_pcie *pci, u8 chn, enum dma_dir dir)
|
||||
{
|
||||
union int_status status;
|
||||
union int_clear clears;
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(pci->dev, "%s %x %x\n", __func__, dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS),
|
||||
dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS));
|
||||
|
||||
if (dir == DMA_TO_BUS) {
|
||||
status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS);
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(pci->dev, "%s, write abort\n", __func__);
|
||||
clears.abortclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS);
|
||||
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(pci->dev, "%s, read abort %x\n", __func__, status.asdword);
|
||||
clears.abortclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk_pcie_dma_wait_for_finised(struct dma_trx_obj *obj, struct dw_pcie *pci, struct dma_table *table)
|
||||
static int rk_pcie_dma_wait_for_finised(struct dma_trx_obj *obj, struct dma_table *table)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = rk_pcie_get_dma_status(pci, table->chn, table->dir);
|
||||
ret = obj->get_dma_status(obj, table->chn, table->dir);
|
||||
} while (!ret);
|
||||
|
||||
return ret;
|
||||
@@ -172,7 +95,6 @@ static int rk_pcie_dma_frombus(struct pcie_dw_dmatest_dev *dmatest_dev, u32 chn,
|
||||
{
|
||||
struct dma_table *table;
|
||||
struct dma_trx_obj *obj = dmatest_dev->obj;
|
||||
struct dw_pcie *pci = dmatest_dev->pci;
|
||||
int ret;
|
||||
|
||||
if (chn >= PCIE_DMA_CHANEL_MAX_NUM)
|
||||
@@ -202,7 +124,7 @@ static int rk_pcie_dma_frombus(struct pcie_dw_dmatest_dev *dmatest_dev, u32 chn,
|
||||
else if (ret == 0)
|
||||
dev_err(obj->dev, "%s timed out\n", __func__);
|
||||
} else {
|
||||
ret = rk_pcie_dma_wait_for_finised(obj, pci, table);
|
||||
ret = rk_pcie_dma_wait_for_finised(obj, table);
|
||||
}
|
||||
mutex_unlock(&dmatest_dev->rd_lock[chn]);
|
||||
|
||||
@@ -216,7 +138,6 @@ static int rk_pcie_dma_tobus(struct pcie_dw_dmatest_dev *dmatest_dev, u32 chn,
|
||||
{
|
||||
struct dma_table *table;
|
||||
struct dma_trx_obj *obj = dmatest_dev->obj;
|
||||
struct dw_pcie *pci = dmatest_dev->pci;
|
||||
int ret;
|
||||
|
||||
if (chn >= PCIE_DMA_CHANEL_MAX_NUM)
|
||||
@@ -246,7 +167,7 @@ static int rk_pcie_dma_tobus(struct pcie_dw_dmatest_dev *dmatest_dev, u32 chn,
|
||||
else if (ret == 0)
|
||||
dev_err(obj->dev, "%s timed out\n", __func__);
|
||||
} else {
|
||||
ret = rk_pcie_dma_wait_for_finised(obj, pci, table);
|
||||
ret = rk_pcie_dma_wait_for_finised(obj, table);
|
||||
}
|
||||
mutex_unlock(&dmatest_dev->wr_lock[chn]);
|
||||
|
||||
@@ -270,23 +191,22 @@ static int rk_pcie_dma_interrupt_handler_call_back(struct dma_trx_obj *obj, u32
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dma_trx_obj *pcie_dw_dmatest_register(struct dw_pcie *pci, bool irq_en)
|
||||
struct dma_trx_obj *pcie_dw_dmatest_register(struct device *dev, bool irq_en)
|
||||
{
|
||||
struct dma_trx_obj *obj;
|
||||
struct pcie_dw_dmatest_dev *dmatest_dev = &s_dmatest_dev[cur_dmatest_dev];
|
||||
int i;
|
||||
|
||||
obj = devm_kzalloc(pci->dev, sizeof(struct dma_trx_obj), GFP_KERNEL);
|
||||
obj = devm_kzalloc(dev, sizeof(struct dma_trx_obj), GFP_KERNEL);
|
||||
if (!obj)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
obj->dev = pci->dev;
|
||||
obj->dev = dev;
|
||||
obj->priv = dmatest_dev;
|
||||
obj->cb = rk_pcie_dma_interrupt_handler_call_back;
|
||||
|
||||
/* Save for dmatest */
|
||||
dmatest_dev->obj = obj;
|
||||
dmatest_dev->pci = pci;
|
||||
for (i = 0; i < PCIE_DMA_CHANEL_MAX_NUM; i++) {
|
||||
init_completion(&dmatest_dev->rd_done[i]);
|
||||
init_completion(&dmatest_dev->wr_done[i]);
|
||||
|
||||
@@ -5,10 +5,13 @@
|
||||
#ifndef __PCIE_DW_DMATEST_H
|
||||
#define __PCIE_DW_DMATEST_H
|
||||
|
||||
struct dma_trx_obj;
|
||||
struct device;
|
||||
|
||||
#if IS_ENABLED(CONFIG_PCIE_DW_DMATEST)
|
||||
struct dma_trx_obj *pcie_dw_dmatest_register(struct dw_pcie *pci, bool irq_en);
|
||||
struct dma_trx_obj *pcie_dw_dmatest_register(struct device *dev, bool irq_en);
|
||||
#else
|
||||
static inline struct dma_trx_obj *pcie_dw_dmatest_register(struct dw_pcie *pci, bool irq_en)
|
||||
static inline struct dma_trx_obj *pcie_dw_dmatest_register(struct device *dev, bool irq_en)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -616,7 +616,7 @@ static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg)
|
||||
status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS) & (~mask);
|
||||
for (chn = 0; chn < PCIE_DMA_CHANEL_MAX_NUM; chn++) {
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = 0x1 << chn;
|
||||
clears.doneclr = BIT(chn);
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
if (rockchip->dma_obj && rockchip->dma_obj->cb)
|
||||
@@ -625,7 +625,7 @@ static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg)
|
||||
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(pci->dev, "%s, abort\n", __func__);
|
||||
clears.abortclr = 0x1 << chn;
|
||||
clears.abortclr = BIT(chn);
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
}
|
||||
@@ -635,7 +635,7 @@ static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg)
|
||||
status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS) & (~mask);
|
||||
for (chn = 0; chn < PCIE_DMA_CHANEL_MAX_NUM; chn++) {
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = 0x1 << chn;
|
||||
clears.doneclr = BIT(chn);
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
if (rockchip->dma_obj && rockchip->dma_obj->cb)
|
||||
@@ -644,7 +644,7 @@ static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg)
|
||||
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(pci->dev, "%s, abort\n", __func__);
|
||||
clears.abortclr = 0x1 << chn;
|
||||
clears.abortclr = BIT(chn);
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
}
|
||||
@@ -702,7 +702,7 @@ static int rockchip_pcie_init_dma_trx(struct rockchip_pcie *rockchip)
|
||||
if (!rockchip_pcie_udma_enabled(rockchip))
|
||||
return 0;
|
||||
|
||||
rockchip->dma_obj = pcie_dw_dmatest_register(pci, true);
|
||||
rockchip->dma_obj = pcie_dw_dmatest_register(pci->dev, true);
|
||||
if (IS_ERR(rockchip->dma_obj)) {
|
||||
dev_err(rockchip->pci.dev, "failed to prepare dmatest\n");
|
||||
return -EINVAL;
|
||||
@@ -808,6 +808,56 @@ static void rockchip_pcie_config_dma_dwc(struct dma_table *table)
|
||||
table->start.chnl = table->chn;
|
||||
}
|
||||
|
||||
static int rockchip_pcie_get_dma_status(struct dma_trx_obj *obj, u8 chn, enum dma_dir dir)
|
||||
{
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(obj->dev);
|
||||
struct dw_pcie *pci = &rockchip->pci;
|
||||
union int_status status;
|
||||
union int_clear clears;
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(pci->dev, "%s %x %x\n", __func__,
|
||||
dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS),
|
||||
dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS));
|
||||
|
||||
if (dir == DMA_TO_BUS) {
|
||||
status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS);
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = BIT(chn);
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(pci->dev, "%s, write abort\n", __func__);
|
||||
clears.abortclr = BIT(chn);
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS);
|
||||
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = BIT(chn);
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(pci->dev, "%s, read abort %x\n", __func__, status.asdword);
|
||||
clears.abortclr = BIT(chn);
|
||||
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.start_link = rockchip_pcie_start_link,
|
||||
.link_up = rockchip_pcie_link_up,
|
||||
@@ -1050,6 +1100,7 @@ already_linkup:
|
||||
if (rockchip->dma_obj) {
|
||||
rockchip->dma_obj->start_dma_func = rockchip_pcie_start_dma_dwc;
|
||||
rockchip->dma_obj->config_dma_func = rockchip_pcie_config_dma_dwc;
|
||||
rockchip->dma_obj->get_dma_status = rockchip_pcie_get_dma_status;
|
||||
}
|
||||
|
||||
/* Enable client ELBI interrupt */
|
||||
|
||||
@@ -853,7 +853,7 @@ static int rk_pcie_init_dma_trx(struct rk_pcie *rk_pcie)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rk_pcie->dma_obj = pcie_dw_dmatest_register(rk_pcie->pci, true);
|
||||
rk_pcie->dma_obj = pcie_dw_dmatest_register(rk_pcie->pci->dev, true);
|
||||
if (IS_ERR(rk_pcie->dma_obj)) {
|
||||
dev_err(rk_pcie->pci->dev, "failed to prepare dmatest\n");
|
||||
return -EINVAL;
|
||||
|
||||
@@ -190,6 +190,7 @@ struct dma_trx_obj {
|
||||
struct pcie_misc_dev *pcie_dev;
|
||||
void (*start_dma_func)(struct dma_trx_obj *obj, struct dma_table *table);
|
||||
void (*config_dma_func)(struct dma_table *table);
|
||||
int (*get_dma_status)(struct dma_trx_obj *obj, u8 chn, enum dma_dir dir);
|
||||
int (*cb)(struct dma_trx_obj *obj, u32 chn, enum dma_dir dir);
|
||||
ktime_t begin;
|
||||
ktime_t end;
|
||||
|
||||
Reference in New Issue
Block a user