Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S964835AbbLQO6X (ORCPT ); Thu, 17 Dec 2015 09:58:23 -0500 Received: from mga03.intel.com ([134.134.136.65]:18912 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S966244AbbLQO6U (ORCPT ); Thu, 17 Dec 2015 09:58:20 -0500 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.20,441,1444719600"; d="scan'208";a="843285830" Message-ID: <1450364294.30729.134.camel@linux.intel.com> Subject: Re: [PATCH 1/3] ata: sata_dwc_460ex: use "dmas" DT property to find dma channel From: Andy Shevchenko To: Mans Rullgard , Tejun Heo , linux-ide@vger.kernel.org, linux-kernel@vger.kernel.org Date: Thu, 17 Dec 2015 16:58:14 +0200 In-Reply-To: <1450221935-6034-1-git-send-email-mans@mansr.com> References: <1450221935-6034-1-git-send-email-mans@mansr.com> Organization: Intel Finland Oy Content-Type: text/plain; charset="UTF-8" X-Mailer: Evolution 3.18.2-1 Mime-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 10473 Lines: 390 On Tue, 2015-12-15 at 23:25 +0000, Mans Rullgard wrote: > Currently this driver only works with a DesignWare DMA engine which > it > registers manually using the second "reg" address range and interrupt > number from the DT node. > > This patch makes the driver instead use the "dmas" property if > present, > otherwise optionally falling back on the old way so existing device > trees can continue to work. > > With this change, there is no longer any reason to depend on the > 460EX > machine type so drop that from Kconfig. Looks good for me (from dw_dmac usage prospective). > > Signed-off-by: Mans Rullgard > --- >  drivers/ata/Kconfig          |  10 ++- >  drivers/ata/sata_dwc_460ex.c | 192 +++++++++++++++++++++++++++---- > ------------ >  2 files changed, 131 insertions(+), 71 deletions(-) > > diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig > index 3fc2a56..193c673 100644 > --- a/drivers/ata/Kconfig > +++ b/drivers/ata/Kconfig > @@ -296,14 +296,20 @@ config ATA_PIIX >   >  config SATA_DWC >   tristate "DesignWare Cores SATA support" > - depends on 460EX > - select DW_DMAC >   help >     This option enables support for the on-chip SATA > controller of the >     AppliedMicro processor 460EX. >   >     If unsure, say N. >   > +config SATA_DWC_OLD_DMA > + bool "Support old device trees" > + depends on SATA_DWC && 460EX > + select DW_DMAC > + help > +   This option enables support for old device trees without > the > +   "dmas" property. > + >  config SATA_DWC_DEBUG >   bool "Debugging driver version" >   depends on SATA_DWC > diff --git a/drivers/ata/sata_dwc_460ex.c > b/drivers/ata/sata_dwc_460ex.c > index 9020349..9985749 100644 > --- a/drivers/ata/sata_dwc_460ex.c > +++ b/drivers/ata/sata_dwc_460ex.c > @@ -30,6 +30,7 @@ >  #include >  #include >  #include > +#include >  #include >  #include >  #include > @@ -42,10 +43,6 @@ >  #include >  #include >   > -/* Supported DMA engine drivers */ > -#include > -#include > - >  /* These two are defined in "libata.h" */ >  #undef DRV_NAME >  #undef DRV_VERSION > @@ -148,7 +145,9 @@ struct sata_dwc_device { >   struct ata_host *host; >   u8 __iomem *reg_base; >   struct sata_dwc_regs *sata_dwc_regs; /* DW > Synopsys SATA specific */ > +#ifdef CONFIG_SATA_DWC_OLD_DMA >   struct dw_dma_chip *dma; > +#endif >  }; >   >  #define SATA_DWC_QCMD_MAX 32 > @@ -159,7 +158,6 @@ struct sata_dwc_device_port { >   int dma_pending[SATA_DWC_QCMD_MAX]; >   >   /* DMA info */ > - struct dw_dma_slave *dws; >   struct dma_chan *chan; >   struct dma_async_tx_descriptor *desc[SATA_DWC_QCMD_MA > X]; >   u32 dma_interrupt_count; > @@ -198,13 +196,6 @@ struct sata_dwc_host_priv { >   >  static struct sata_dwc_host_priv host_pvt; >   > -static struct dw_dma_slave sata_dwc_dma_dws = { > - .src_id = 0, > - .dst_id = 0, > - .src_master = 0, > - .dst_master = 1, > -}; > - >  /* >   * Prototypes >   */ > @@ -215,6 +206,90 @@ static void sata_dwc_dma_xfer_complete(struct > ata_port *ap, u32 check_status); >  static void sata_dwc_port_stop(struct ata_port *ap); >  static void sata_dwc_clear_dmacr(struct sata_dwc_device_port > *hsdevp, u8 tag); >   > +#ifdef CONFIG_SATA_DWC_OLD_DMA > + > +#include > +#include > + > +static struct dw_dma_slave sata_dwc_dma_dws = { > + .src_id = 0, > + .dst_id = 0, > + .src_master = 0, > + .dst_master = 1, > +}; > + > +static bool sata_dwc_dma_filter(struct dma_chan *chan, void *param) > +{ > + struct dw_dma_slave *dws = &sata_dwc_dma_dws; > + > + if (dws->dma_dev != chan->device->dev) > + return false; > + > + chan->private = dws; > + return true; > +} > + > +static int sata_dwc_dma_get_channel_old(struct sata_dwc_device_port > *hsdevp) > +{ > + struct sata_dwc_device *hsdev = hsdevp->hsdev; > + struct dw_dma_slave *dws = &sata_dwc_dma_dws; > + dma_cap_mask_t mask; > + > + dws->dma_dev = hsdev->dev; > + > + dma_cap_zero(mask); > + dma_cap_set(DMA_SLAVE, mask); > + > + /* Acquire DMA channel */ > + hsdevp->chan = dma_request_channel(mask, > sata_dwc_dma_filter, hsdevp); > + if (!hsdevp->chan) { > + dev_err(hsdev->dev, "%s: dma channel unavailable\n", > +  __func__); > + return -EAGAIN; > + } > + > + return 0; > +} > + > +static int sata_dwc_dma_init_old(struct platform_device *pdev, > +  struct sata_dwc_device *hsdev) > +{ > + struct device_node *np = pdev->dev.of_node; > + int err; > + > + hsdev->dma = devm_kzalloc(&pdev->dev, sizeof(*hsdev->dma), > GFP_KERNEL); > + if (!hsdev->dma) > + return -ENOMEM; > + > + hsdev->dma->dev = &pdev->dev; > + > + /* Get SATA DMA interrupt number */ > + hsdev->dma->irq = irq_of_parse_and_map(np, 1); > + if (hsdev->dma->irq == NO_IRQ) { > + dev_err(&pdev->dev, "no SATA DMA irq\n"); > + return -ENODEV; > + } > + > + /* Get physical SATA DMA register base address */ > + hsdev->dma->regs = of_iomap(np, 1); > + if (!hsdev->dma->regs) { > + dev_err(&pdev->dev, > + "ioremap failed for AHBDMA register > address\n"); > + return -ENODEV; > + } > + > + /* Initialize AHB DMAC */ > + err = dw_dma_probe(hsdev->dma, NULL); > + if (err) { > + iounmap(hsdev->dma->regs); > + return err; > + } > + > + return 0; > +} > + > +#endif > + >  static const char *get_prot_descript(u8 protocol) >  { >   switch ((enum ata_tf_protocols)protocol) { > @@ -783,18 +858,6 @@ static void sata_dwc_enable_interrupts(struct > sata_dwc_device *hsdev) >   in_le32(&hsdev->sata_dwc_regs->errmr)); >  } >   > -static bool sata_dwc_dma_filter(struct dma_chan *chan, void *param) > -{ > - struct sata_dwc_device_port *hsdevp = param; > - struct dw_dma_slave *dws = hsdevp->dws; > - > - if (dws->dma_dev != chan->device->dev) > - return false; > - > - chan->private = dws; > - return true; > -} > - >  static void sata_dwc_setup_port(struct ata_ioports *port, unsigned > long base) >  { >   port->cmd_addr = (void __iomem *)base + 0x00; > @@ -817,6 +880,26 @@ static void sata_dwc_setup_port(struct > ata_ioports *port, unsigned long base) >   port->ctl_addr = (void __iomem *)base + 0x20; >  } >   > +static int sata_dwc_dma_get_channel(struct sata_dwc_device_port > *hsdevp) > +{ > + struct sata_dwc_device *hsdev = hsdevp->hsdev; > + struct device *dev = hsdev->dev; > + > +#ifdef CONFIG_SATA_DWC_OLD_DMA > + if (!of_find_property(dev->of_node, "dmas", NULL)) > + return sata_dwc_dma_get_channel_old(hsdevp); > +#endif > + > + hsdevp->chan = dma_request_slave_channel(dev, "sata-dma"); > + if (IS_ERR(hsdevp->chan)) { > + dev_err(dev, "failed to allocate dma channel: > %ld\n", > + PTR_ERR(hsdevp->chan)); > + return PTR_ERR(hsdevp->chan); > + } > + > + return 0; > +} > + >  /* >   * Function : sata_dwc_port_start >   * arguments : struct ata_ioports *port > @@ -829,7 +912,6 @@ static int sata_dwc_port_start(struct ata_port > *ap) >   struct sata_dwc_device *hsdev; >   struct sata_dwc_device_port *hsdevp = NULL; >   struct device *pdev; > - dma_cap_mask_t mask; >   int i; >   >   hsdev = HSDEV_FROM_AP(ap); > @@ -853,20 +935,9 @@ static int sata_dwc_port_start(struct ata_port > *ap) >   } >   hsdevp->hsdev = hsdev; >   > - hsdevp->dws = &sata_dwc_dma_dws; > - hsdevp->dws->dma_dev = hsdev->dev; > - > - dma_cap_zero(mask); > - dma_cap_set(DMA_SLAVE, mask); > - > - /* Acquire DMA channel */ > - hsdevp->chan = dma_request_channel(mask, > sata_dwc_dma_filter, hsdevp); > - if (!hsdevp->chan) { > - dev_err(hsdev->dev, "%s: dma channel unavailable\n", > -  __func__); > - err = -EAGAIN; > + err = sata_dwc_dma_get_channel(hsdevp); > + if (err) >   goto CLEANUP_ALLOC; > - } >   >   for (i = 0; i < SATA_DWC_QCMD_MAX; i++) >   hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; > @@ -1225,33 +1296,9 @@ static int sata_dwc_probe(struct > platform_device *ofdev) >   dev_notice(&ofdev->dev, "id %d, controller version > %c.%c%c\n", >      idr, ver[0], ver[1], ver[2]); >   > - /* Get SATA DMA interrupt number */ > - hsdev->dma->irq = irq_of_parse_and_map(np, 1); > - if (hsdev->dma->irq == NO_IRQ) { > - dev_err(&ofdev->dev, "no SATA DMA irq\n"); > - err = -ENODEV; > - goto error_iomap; > - } > - > - /* Get physical SATA DMA register base address */ > - hsdev->dma->regs = of_iomap(np, 1); > - if (!hsdev->dma->regs) { > - dev_err(&ofdev->dev, > - "ioremap failed for AHBDMA register > address\n"); > - err = -ENODEV; > - goto error_iomap; > - } > - >   /* Save dev for later use in dev_xxx() routines */ >   hsdev->dev = &ofdev->dev; >   > - hsdev->dma->dev = &ofdev->dev; > - > - /* Initialize AHB DMAC */ > - err = dw_dma_probe(hsdev->dma, NULL); > - if (err) > - goto error_dma_iomap; > - >   /* Enable SATA Interrupts */ >   sata_dwc_enable_interrupts(hsdev); >   > @@ -1263,6 +1310,14 @@ static int sata_dwc_probe(struct > platform_device *ofdev) >   goto error_out; >   } >   > +#ifdef CONFIG_SATA_DWC_OLD_DMA > + if (!of_find_property(np, "dmas", NULL)) { > + err = sata_dwc_dma_init_old(ofdev, hsdev); > + if (err) > + goto error_out; > + } > +#endif > + >   /* >    * Now, register with libATA core, this will also initiate > the >    * device discovery process, invoking our port_start() > handler & > @@ -1276,11 +1331,6 @@ static int sata_dwc_probe(struct > platform_device *ofdev) >   return 0; >   >  error_out: > - /* Free SATA DMA resources */ > - dw_dma_remove(hsdev->dma); > -error_dma_iomap: > - iounmap(hsdev->dma->regs); > -error_iomap: >   iounmap(base); >   return err; >  } > @@ -1293,10 +1343,14 @@ static int sata_dwc_remove(struct > platform_device *ofdev) >   >   ata_host_detach(host); >   > +#ifdef CONFIG_SATA_DWC_OLD_DMA >   /* Free SATA DMA resources */ > - dw_dma_remove(hsdev->dma); > + if (hsdev->dma) { > + dw_dma_remove(hsdev->dma); > + iounmap(hsdev->dma->regs); > + } > +#endif >   > - iounmap(hsdev->dma->regs); >   iounmap(hsdev->reg_base); >   dev_dbg(&ofdev->dev, "done\n"); >   return 0; -- Andy Shevchenko Intel Finland Oy -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/