On Wed, May 29, 2019 at 01:10:05PM -0500, Eddie James wrote: > The AST2500 has two PCI devices embedded. The XDMA engine can use either > device to perform DMA transfers. Users need the capability to choose > which device to use. This commit therefore adds two sysfs files that > toggle the AST2500 and XDMA engine between the two PCI devices. > > Signed-off-by: Eddie James <eajames@xxxxxxxxxxxxx> > --- > drivers/soc/aspeed/aspeed-xdma.c | 103 +++++++++++++++++++++++++++++++++++++-- > 1 file changed, 100 insertions(+), 3 deletions(-) > > diff --git a/drivers/soc/aspeed/aspeed-xdma.c b/drivers/soc/aspeed/aspeed-xdma.c > index 39f6545..ddd5e1e 100644 > --- a/drivers/soc/aspeed/aspeed-xdma.c > +++ b/drivers/soc/aspeed/aspeed-xdma.c > @@ -143,6 +143,7 @@ struct aspeed_xdma { > void *cmdq_vga_virt; > struct gen_pool *vga_pool; > > + char pcidev[4]; > struct miscdevice misc; > }; > > @@ -165,6 +166,10 @@ struct aspeed_xdma_client { > SCU_PCIE_CONF_VGA_EN_IRQ | SCU_PCIE_CONF_VGA_EN_DMA | > SCU_PCIE_CONF_RSVD; > > +static char *_pcidev = "vga"; > +module_param_named(pcidev, _pcidev, charp, 0600); > +MODULE_PARM_DESC(pcidev, "Default PCI device used by XDMA engine for DMA ops"); > + > static void aspeed_scu_pcie_write(struct aspeed_xdma *ctx, u32 conf) > { > u32 v = 0; > @@ -512,7 +517,7 @@ static int aspeed_xdma_release(struct inode *inode, struct file *file) > .release = aspeed_xdma_release, > }; > > -static int aspeed_xdma_init_mem(struct aspeed_xdma *ctx) > +static int aspeed_xdma_init_mem(struct aspeed_xdma *ctx, u32 conf) > { > int rc; > u32 scu_conf = 0; > @@ -522,7 +527,7 @@ static int aspeed_xdma_init_mem(struct aspeed_xdma *ctx) > const u32 vga_sizes[4] = { 0x800000, 0x1000000, 0x2000000, 0x4000000 }; > void __iomem *sdmc_base = ioremap(0x1e6e0000, 0x100); > > - aspeed_scu_pcie_write(ctx, aspeed_xdma_vga_pcie_conf); > + aspeed_scu_pcie_write(ctx, conf); > > regmap_read(ctx->scu, SCU_STRAP, &scu_conf); > ctx->vga_size = vga_sizes[FIELD_GET(SCU_STRAP_VGA_MEM, scu_conf)]; > @@ -598,10 +603,91 @@ static int aspeed_xdma_init_mem(struct aspeed_xdma *ctx) > return rc; > } > > +static int aspeed_xdma_change_pcie_conf(struct aspeed_xdma *ctx, u32 conf) > +{ > + int rc; > + > + mutex_lock(&ctx->start_lock); > + rc = wait_event_interruptible_timeout(ctx->wait, > + !test_bit(XDMA_IN_PRG, > + &ctx->flags), > + msecs_to_jiffies(1000)); > + if (rc < 0) { > + mutex_unlock(&ctx->start_lock); > + return -EINTR; > + } > + > + /* previous op didn't complete, wake up waiters anyway */ > + if (!rc) > + wake_up_interruptible_all(&ctx->wait); > + > + reset_control_assert(ctx->reset); > + msleep(10); > + > + aspeed_scu_pcie_write(ctx, conf); > + msleep(10); > + > + reset_control_deassert(ctx->reset); > + msleep(10); > + > + aspeed_xdma_init_eng(ctx); > + > + mutex_unlock(&ctx->start_lock); > + > + return 0; > +} > + > +static int aspeed_xdma_pcidev_to_conf(struct aspeed_xdma *ctx, > + const char *pcidev, u32 *conf) > +{ > + if (!strcasecmp(pcidev, "vga")) { > + *conf = aspeed_xdma_vga_pcie_conf; > + return 0; > + } > + > + if (!strcasecmp(pcidev, "bmc")) { > + *conf = aspeed_xdma_bmc_pcie_conf; > + return 0; > + } strncasecmp()? > + > + return -EINVAL; > +} > + > +static ssize_t aspeed_xdma_show_pcidev(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct aspeed_xdma *ctx = dev_get_drvdata(dev); > + > + return snprintf(buf, PAGE_SIZE - 1, "%s", ctx->pcidev); > +} > + > +static ssize_t aspeed_xdma_store_pcidev(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + u32 conf; > + struct aspeed_xdma *ctx = dev_get_drvdata(dev); > + int rc = aspeed_xdma_pcidev_to_conf(ctx, buf, &conf); > + > + if (rc) > + return rc; > + > + rc = aspeed_xdma_change_pcie_conf(ctx, conf); > + if (rc) > + return rc; > + > + strcpy(ctx->pcidev, buf); should we use strncpy() instead? > + return count; > +} > +static DEVICE_ATTR(pcidev, 0644, aspeed_xdma_show_pcidev, > + aspeed_xdma_store_pcidev); > + > static int aspeed_xdma_probe(struct platform_device *pdev) > { > int irq; > int rc; > + u32 conf; > struct resource *res; > struct device *dev = &pdev->dev; > struct aspeed_xdma *ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); > @@ -657,7 +743,14 @@ static int aspeed_xdma_probe(struct platform_device *pdev) > > msleep(10); > > - rc = aspeed_xdma_init_mem(ctx); > + if (aspeed_xdma_pcidev_to_conf(ctx, _pcidev, &conf)) { > + conf = aspeed_xdma_vga_pcie_conf; > + strcpy(ctx->pcidev, "vga"); > + } else { > + strcpy(ctx->pcidev, _pcidev); > + } same... > + > + rc = aspeed_xdma_init_mem(ctx, conf); > if (rc) { > reset_control_assert(ctx->reset); > return rc; > @@ -682,6 +775,8 @@ static int aspeed_xdma_probe(struct platform_device *pdev) > return rc; > } > > + device_create_file(dev, &dev_attr_pcidev); Should we consider using one of the default attributes here instead of device_create_file()? http://kroah.com/log/blog/2013/06/26/how-to-create-a-sysfs-file-correctly/ BTW, was this ABI documented? Is this the same file documented in patch 2? > + > return 0; > } > > @@ -689,6 +784,8 @@ static int aspeed_xdma_remove(struct platform_device *pdev) > { > struct aspeed_xdma *ctx = platform_get_drvdata(pdev); > > + device_remove_file(ctx->dev, &dev_attr_pcidev); > + > misc_deregister(&ctx->misc); > gen_pool_free(ctx->vga_pool, (unsigned long)ctx->cmdq_vga_virt, > XDMA_CMDQ_SIZE); > -- > 1.8.3.1 > -- All the best, Eduardo Valentin