From 6827153a016ca9b9b7da8b58f9691f40ca826fc3 Mon Sep 17 00:00:00 2001 From: welseywesley Date: Fri, 1 Jun 2018 22:56:26 +0800 Subject: [PATCH 1/3] macro, registers and data structure for dma mrpc 1. macro definition for dma mrpc enable bit 2. registers include: enable, dma target address, vector, and version 3. data structure of dma mrpc output --- linux/switchtec.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/linux/switchtec.h b/linux/switchtec.h index e3cb8b8..9417874 100644 --- a/linux/switchtec.h +++ b/linux/switchtec.h @@ -33,6 +33,7 @@ #define SWITCHTEC_EVENT_EN_IRQ BIT(3) #define SWITCHTEC_EVENT_FATAL BIT(4) +#define SWITCHTEC_DMA_MRPC_EN BIT(0) enum { SWITCHTEC_GAS_MRPC_OFFSET = 0x0000, SWITCHTEC_GAS_TOP_CFG_OFFSET = 0x1000, @@ -50,6 +51,10 @@ struct mrpc_regs { u32 cmd; u32 status; u32 ret_value; + u32 dma_en; + u64 dma_addr; + u32 dma_vector; + u32 dma_ver; } __packed; enum mrpc_status { @@ -359,6 +364,14 @@ struct pff_csr_regs { struct switchtec_ntb; +struct dma_mrpc_output{ + u32 status; + u32 cmd_id; + u32 rtn_code; + u32 output_size; + u8 data[SWITCHTEC_MRPC_PAYLOAD_SIZE]; +}; + struct switchtec_dev { struct pci_dev *pdev; struct device dev; @@ -398,6 +411,9 @@ struct switchtec_dev { u8 link_event_count[SWITCHTEC_MAX_PFF_CSR]; struct switchtec_ntb *sndev; + + struct dma_mrpc_output *dma_mrpc; + dma_addr_t dma_mrpc_dma_addr; }; static inline struct switchtec_dev *to_stdev(struct device *dev) From ad09a383da1d8d203cf8d50ee39f18ca780611ba Mon Sep 17 00:00:00 2001 From: welseywesley Date: Fri, 1 Jun 2018 22:57:24 +0800 Subject: [PATCH 2/3] dma mrpc implementation 1. add dma output target virtual and bus addrss member in switchtec_dev struct 2. in mrpc completion function, collect the result from different source 3. release dma output buffer and disable mrpc dma function in stdev_release 4. add isr for dma mrpc 5. according to the dma version register value, allocate dma buffer, enable dma function and register interrupt service routine --- switchtec.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/switchtec.c b/switchtec.c index b759228..0a468c9 100644 --- a/switchtec.c +++ b/switchtec.c @@ -174,7 +174,11 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev) stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, list); - stuser->status = ioread32(&stdev->mmio_mrpc->status); + if (stdev->dma_mrpc) + stuser->status = stdev->dma_mrpc->status; + else + stuser->status = ioread32(&stdev->mmio_mrpc->status); + if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS) return; @@ -184,13 +188,19 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev) if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE) goto out; - stuser->return_code = ioread32(&stdev->mmio_mrpc->ret_value); + if (stdev->dma_mrpc) + stuser->return_code = stdev->dma_mrpc->rtn_code; + else + stuser->return_code = ioread32(&stdev->mmio_mrpc->ret_value); if (stuser->return_code != 0) goto out; - memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data, - stuser->read_len); - + if (stdev->dma_mrpc) + memcpy(stuser->data, &stdev->dma_mrpc->data, + stuser->read_len); + else + memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data, + stuser->read_len); out: complete_all(&stuser->comp); list_del_init(&stuser->list); @@ -225,7 +235,10 @@ static void mrpc_timeout_work(struct work_struct *work) mutex_lock(&stdev->mrpc_mutex); - status = ioread32(&stdev->mmio_mrpc->status); + if (stdev->dma_mrpc) + status = stdev->dma_mrpc->status; + else + status = ioread32(&stdev->mmio_mrpc->status); if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) { schedule_delayed_work(&stdev->mrpc_timeout, msecs_to_jiffies(500)); @@ -233,7 +246,6 @@ static void mrpc_timeout_work(struct work_struct *work) } mrpc_complete_cmd(stdev); - out: mutex_unlock(&stdev->mrpc_mutex); } @@ -1019,10 +1031,22 @@ static void enable_link_state_events(struct switchtec_dev *stdev) } } +static void enable_dma_mrpc(struct switchtec_dev *stdev) +{ + writeq(stdev->dma_mrpc_dma_addr, &stdev->mmio_mrpc->dma_addr); + iowrite32(SWITCHTEC_DMA_MRPC_EN, &stdev->mmio_mrpc->dma_en); +} + static void stdev_release(struct device *dev) { struct switchtec_dev *stdev = to_stdev(dev); + if (stdev->dma_mrpc){ + iowrite32(0, &stdev->mmio_mrpc->dma_en); + writeq(0, &stdev->mmio_mrpc->dma_addr); + dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc), + stdev->dma_mrpc, stdev->dma_mrpc_dma_addr); + } kfree(stdev); } @@ -1178,10 +1202,27 @@ static irqreturn_t switchtec_event_isr(int irq, void *dev) return ret; } + +static irqreturn_t switchtec_dma_mrpc_isr(int irq, void *dev) +{ + struct switchtec_dev *stdev = dev; + irqreturn_t ret = IRQ_NONE; + + iowrite32(SWITCHTEC_EVENT_CLEAR | + SWITCHTEC_EVENT_EN_IRQ, + &stdev->mmio_part_cfg->mrpc_comp_hdr); + schedule_work(&stdev->mrpc_work); + + ret = IRQ_HANDLED; + return ret; +} + static int switchtec_init_isr(struct switchtec_dev *stdev) { int nvecs; int event_irq; + int dma_mrpc_irq; + int rc; nvecs = pci_alloc_irq_vectors(stdev->pdev, 1, 4, PCI_IRQ_MSIX | PCI_IRQ_MSI); @@ -1196,9 +1237,29 @@ static int switchtec_init_isr(struct switchtec_dev *stdev) if (event_irq < 0) return event_irq; - return devm_request_irq(&stdev->pdev->dev, event_irq, + rc = devm_request_irq(&stdev->pdev->dev, event_irq, switchtec_event_isr, 0, KBUILD_MODNAME, stdev); + + if (rc) + return rc; + + if (!stdev->dma_mrpc) + return rc; + + dma_mrpc_irq = ioread32(&stdev->mmio_mrpc->dma_vector); + if ( dma_mrpc_irq < 0 || dma_mrpc_irq >= nvecs) + return -EFAULT; + + dma_mrpc_irq = pci_irq_vector(stdev->pdev, dma_mrpc_irq); + if (event_irq < 0) + return dma_mrpc_irq; + + rc = devm_request_irq(&stdev->pdev->dev, dma_mrpc_irq, + switchtec_dma_mrpc_isr, 0, + KBUILD_MODNAME, stdev); + + return rc; } static void init_pff(struct switchtec_dev *stdev) @@ -1264,6 +1325,14 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, pci_set_drvdata(pdev, stdev); + if(!(ioread32(&stdev->mmio_mrpc->dma_ver)? true : false)) + return 0; + + stdev->dma_mrpc = dma_zalloc_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc), + &stdev->dma_mrpc_dma_addr, GFP_KERNEL); + if (stdev->dma_mrpc == NULL) + return -ENOMEM; + return 0; } @@ -1295,6 +1364,9 @@ static int switchtec_pci_probe(struct pci_dev *pdev, &stdev->mmio_part_cfg->mrpc_comp_hdr); enable_link_state_events(stdev); + if (stdev->dma_mrpc) + enable_dma_mrpc(stdev); + rc = cdev_device_add(&stdev->cdev, &stdev->dev); if (rc) goto err_devadd; @@ -1320,7 +1392,6 @@ static void switchtec_pci_remove(struct pci_dev *pdev) cdev_device_del(&stdev->cdev, &stdev->dev); ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); dev_info(&stdev->dev, "unregistered.\n"); - stdev_kill(stdev); put_device(&stdev->dev); } From 1c90fd7e011648c432e6767d5fb6fc78fa28c426 Mon Sep 17 00:00:00 2001 From: welseywesley Date: Fri, 1 Jun 2018 23:17:18 +0800 Subject: [PATCH 3/3] add module parameter use_dma_mrpc dma mrpc or legacy mrpc is controllable by this parameter --- switchtec.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/switchtec.c b/switchtec.c index 0a468c9..8dab67c 100644 --- a/switchtec.c +++ b/switchtec.c @@ -33,6 +33,11 @@ static int max_devices = 16; module_param(max_devices, int, 0644); MODULE_PARM_DESC(max_devices, "max number of switchtec device instances"); +static bool use_dma_mrpc = 1; +module_param(use_dma_mrpc, bool, 0644); +MODULE_PARM_DESC(use_dma_mrpc, + "Enable the use of the DMA MRPC feature"); + static dev_t switchtec_devt; static DEFINE_IDA(switchtec_minor_ida); @@ -1325,6 +1330,9 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, pci_set_drvdata(pdev, stdev); + if (!use_dma_mrpc) + return 0; + if(!(ioread32(&stdev->mmio_mrpc->dma_ver)? true : false)) return 0;