All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] dmaengine: add slave sg transfer capabilities api
@ 2013-02-04 19:47 ` Matt Porter
  0 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-02-04 19:47 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

Changes since v2:
	- Change to a separate slave sg specific api. Drop the
	  generic per-channel capabilities api that is not used.

Changes since v1:
	- Use the existing dma_transaction_type enums instead of
	  adding the mostly duplicated dmaengine_apis enums

This series adds a new dmaengine api, dma_get_slave_sg_caps(), which
may be used by a client driver to get slave SG transfer capabilities
for a particular channel. At this time, these include the max number
of segments and max length of a segment that a channel can handle for
a SG transfer.

Along with the API implementation, this series implements the backend
device_slave_sg_caps() in the EDMA DMA Engine driver and converts the
davinci_mmc driver to use dma_get_slave_sg_caps() to replace hardcoded
limits.

This is tested on the AM1808-EVM.

Matt Porter (3):
  dmaengine: add dma_get_slave_sg_caps()
  dma: edma: add device_slave_sg_caps() support
  mmc: davinci: get SG segment limits with dma_get_slave_sg_caps()

 drivers/dma/edma.c                        |   17 ++++++++++++
 drivers/mmc/host/davinci_mmc.c            |   37 ++++++++------------------
 include/linux/dmaengine.h                 |   40 +++++++++++++++++++++++++++++
 include/linux/platform_data/mmc-davinci.h |    3 ---
 4 files changed, 67 insertions(+), 30 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 0/3] dmaengine: add slave sg transfer capabilities api
@ 2013-02-04 19:47 ` Matt Porter
  0 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-02-04 19:47 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

Changes since v2:
	- Change to a separate slave sg specific api. Drop the
	  generic per-channel capabilities api that is not used.

Changes since v1:
	- Use the existing dma_transaction_type enums instead of
	  adding the mostly duplicated dmaengine_apis enums

This series adds a new dmaengine api, dma_get_slave_sg_caps(), which
may be used by a client driver to get slave SG transfer capabilities
for a particular channel. At this time, these include the max number
of segments and max length of a segment that a channel can handle for
a SG transfer.

Along with the API implementation, this series implements the backend
device_slave_sg_caps() in the EDMA DMA Engine driver and converts the
davinci_mmc driver to use dma_get_slave_sg_caps() to replace hardcoded
limits.

This is tested on the AM1808-EVM.

Matt Porter (3):
  dmaengine: add dma_get_slave_sg_caps()
  dma: edma: add device_slave_sg_caps() support
  mmc: davinci: get SG segment limits with dma_get_slave_sg_caps()

 drivers/dma/edma.c                        |   17 ++++++++++++
 drivers/mmc/host/davinci_mmc.c            |   37 ++++++++------------------
 include/linux/dmaengine.h                 |   40 +++++++++++++++++++++++++++++
 include/linux/platform_data/mmc-davinci.h |    3 ---
 4 files changed, 67 insertions(+), 30 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/3] dmaengine: add dma_get_slave_sg_caps()
  2013-02-04 19:47 ` Matt Porter
@ 2013-02-04 19:47   ` Matt Porter
  -1 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-02-04 19:47 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

Add a dmaengine API to retrieve slave SG transfer capabilities.

The API is optionally implemented by dmaengine drivers and when
unimplemented will return a NULL pointer. A client driver using
this API provides the required dma channel, address width, and
burst size of the transfer. dma_get_slave_sg_caps() returns an
SG caps structure with the maximum number and size of SG segments
that the given channel can handle.

Signed-off-by: Matt Porter <mporter@ti.com>
---
 include/linux/dmaengine.h |   40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index d3201e4..5b5b220 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -371,6 +371,19 @@ struct dma_slave_config {
 	unsigned int slave_id;
 };
 
+/* struct dma_slave_sg_caps - expose SG transfer capability of a
+ * channel.
+ *
+ * @max_seg_nr: maximum number of SG segments supported on a SG/SLAVE
+ *	    channel (0 for no maximum or not a SG/SLAVE channel)
+ * @max_seg_len: maximum length of SG segments supported on a SG/SLAVE
+ *	     channel (0 for no maximum or not a SG/SLAVE channel)
+ */
+struct dma_slave_sg_caps {
+	u32 max_seg_nr;
+	u32 max_seg_len;
+};
+
 static inline const char *dma_chan_name(struct dma_chan *chan)
 {
 	return dev_name(&chan->dev->device);
@@ -534,6 +547,7 @@ struct dma_tx_state {
  *	struct with auxiliary transfer status information, otherwise the call
  *	will just return a simple status code
  * @device_issue_pending: push pending transactions to hardware
+ * @device_slave_sg_caps: return the slave SG capabilities
  */
 struct dma_device {
 
@@ -602,6 +616,9 @@ struct dma_device {
 					    dma_cookie_t cookie,
 					    struct dma_tx_state *txstate);
 	void (*device_issue_pending)(struct dma_chan *chan);
+	struct dma_slave_sg_caps *(*device_slave_sg_caps)(
+		struct dma_chan *chan, enum dma_slave_buswidth addr_width,
+		u32 maxburst);
 };
 
 static inline int dmaengine_device_control(struct dma_chan *chan,
@@ -969,6 +986,29 @@ dma_set_tx_state(struct dma_tx_state *st, dma_cookie_t last, dma_cookie_t used,
 	}
 }
 
+/**
+ * dma_get_slave_sg_caps - get DMAC SG transfer capabilities
+ * @chan: target DMA channel
+ * @addr_width: address width of the DMA transfer
+ * @maxburst: maximum DMA transfer burst size
+ *
+ * Get SG transfer capabilities for a specified channel. If the dmaengine
+ * driver does not implement SG transfer capabilities then NULL is
+ * returned.
+ */
+static inline struct dma_slave_sg_caps
+*dma_get_slave_sg_caps(struct dma_chan *chan,
+		       enum dma_slave_buswidth addr_width,
+		       u32 maxburst)
+{
+	if (chan->device->device_slave_sg_caps)
+		return chan->device->device_slave_sg_caps(chan,
+							  addr_width,
+							  maxburst);
+
+	return NULL;
+}
+
 enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
 #ifdef CONFIG_DMA_ENGINE
 enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 1/3] dmaengine: add dma_get_slave_sg_caps()
@ 2013-02-04 19:47   ` Matt Porter
  0 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-02-04 19:47 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

Add a dmaengine API to retrieve slave SG transfer capabilities.

The API is optionally implemented by dmaengine drivers and when
unimplemented will return a NULL pointer. A client driver using
this API provides the required dma channel, address width, and
burst size of the transfer. dma_get_slave_sg_caps() returns an
SG caps structure with the maximum number and size of SG segments
that the given channel can handle.

Signed-off-by: Matt Porter <mporter@ti.com>
---
 include/linux/dmaengine.h |   40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index d3201e4..5b5b220 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -371,6 +371,19 @@ struct dma_slave_config {
 	unsigned int slave_id;
 };
 
+/* struct dma_slave_sg_caps - expose SG transfer capability of a
+ * channel.
+ *
+ * @max_seg_nr: maximum number of SG segments supported on a SG/SLAVE
+ *	    channel (0 for no maximum or not a SG/SLAVE channel)
+ * @max_seg_len: maximum length of SG segments supported on a SG/SLAVE
+ *	     channel (0 for no maximum or not a SG/SLAVE channel)
+ */
+struct dma_slave_sg_caps {
+	u32 max_seg_nr;
+	u32 max_seg_len;
+};
+
 static inline const char *dma_chan_name(struct dma_chan *chan)
 {
 	return dev_name(&chan->dev->device);
@@ -534,6 +547,7 @@ struct dma_tx_state {
  *	struct with auxiliary transfer status information, otherwise the call
  *	will just return a simple status code
  * @device_issue_pending: push pending transactions to hardware
+ * @device_slave_sg_caps: return the slave SG capabilities
  */
 struct dma_device {
 
@@ -602,6 +616,9 @@ struct dma_device {
 					    dma_cookie_t cookie,
 					    struct dma_tx_state *txstate);
 	void (*device_issue_pending)(struct dma_chan *chan);
+	struct dma_slave_sg_caps *(*device_slave_sg_caps)(
+		struct dma_chan *chan, enum dma_slave_buswidth addr_width,
+		u32 maxburst);
 };
 
 static inline int dmaengine_device_control(struct dma_chan *chan,
@@ -969,6 +986,29 @@ dma_set_tx_state(struct dma_tx_state *st, dma_cookie_t last, dma_cookie_t used,
 	}
 }
 
+/**
+ * dma_get_slave_sg_caps - get DMAC SG transfer capabilities
+ * @chan: target DMA channel
+ * @addr_width: address width of the DMA transfer
+ * @maxburst: maximum DMA transfer burst size
+ *
+ * Get SG transfer capabilities for a specified channel. If the dmaengine
+ * driver does not implement SG transfer capabilities then NULL is
+ * returned.
+ */
+static inline struct dma_slave_sg_caps
+*dma_get_slave_sg_caps(struct dma_chan *chan,
+		       enum dma_slave_buswidth addr_width,
+		       u32 maxburst)
+{
+	if (chan->device->device_slave_sg_caps)
+		return chan->device->device_slave_sg_caps(chan,
+							  addr_width,
+							  maxburst);
+
+	return NULL;
+}
+
 enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
 #ifdef CONFIG_DMA_ENGINE
 enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/3] dma: edma: add device_slave_sg_caps() support
  2013-02-04 19:47 ` Matt Porter
@ 2013-02-04 19:47   ` Matt Porter
  -1 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-02-04 19:47 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

Implement device_slave_sg_caps().

EDMA has a finite set of PaRAM slots available for linking a
multi-segment SG transfer. In order to prevent any one channel
from consuming all PaRAM slots to fulfill a large SG transfer,
the driver reports a static per-channel max number of SG segments
it will handle.

The maximum size of an SG segment is limited by the addr_width
and maxburst of a given transfer request. These values are
provided by the client driver and used to calculate and return
the maximum segment length.

Signed-off-by: Matt Porter <mporter@ti.com>
---
 drivers/dma/edma.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index f424298..b779cee 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -72,6 +72,7 @@ struct edma_chan {
 	dma_addr_t			addr;
 	int				addr_width;
 	int				maxburst;
+	struct dma_slave_sg_caps	sg_caps;
 };
 
 struct edma_cc {
@@ -463,6 +464,20 @@ static void edma_issue_pending(struct dma_chan *chan)
 	spin_unlock_irqrestore(&echan->vchan.lock, flags);
 }
 
+static struct dma_slave_sg_caps
+*edma_get_slave_sg_caps(struct dma_chan *chan,
+			enum dma_slave_buswidth addr_width,
+			u32 maxburst)
+{
+	struct edma_chan *echan;
+
+	echan = to_edma_chan(chan);
+	echan->sg_caps.max_seg_len =
+		(SZ_64K - 1) * addr_width * maxburst;
+
+	return &echan->sg_caps;
+}
+
 static size_t edma_desc_size(struct edma_desc *edesc)
 {
 	int i;
@@ -522,6 +537,7 @@ static void __init edma_chan_init(struct edma_cc *ecc,
 		echan->ch_num = EDMA_CTLR_CHAN(ecc->ctlr, i);
 		echan->ecc = ecc;
 		echan->vchan.desc_free = edma_desc_free;
+		echan->sg_caps.max_seg_nr = MAX_NR_SG;
 
 		vchan_init(&echan->vchan, dma);
 
@@ -538,6 +554,7 @@ static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma,
 	dma->device_alloc_chan_resources = edma_alloc_chan_resources;
 	dma->device_free_chan_resources = edma_free_chan_resources;
 	dma->device_issue_pending = edma_issue_pending;
+	dma->device_slave_sg_caps = edma_get_slave_sg_caps;
 	dma->device_tx_status = edma_tx_status;
 	dma->device_control = edma_control;
 	dma->dev = dev;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/3] dma: edma: add device_slave_sg_caps() support
@ 2013-02-04 19:47   ` Matt Porter
  0 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-02-04 19:47 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

Implement device_slave_sg_caps().

EDMA has a finite set of PaRAM slots available for linking a
multi-segment SG transfer. In order to prevent any one channel
from consuming all PaRAM slots to fulfill a large SG transfer,
the driver reports a static per-channel max number of SG segments
it will handle.

The maximum size of an SG segment is limited by the addr_width
and maxburst of a given transfer request. These values are
provided by the client driver and used to calculate and return
the maximum segment length.

Signed-off-by: Matt Porter <mporter@ti.com>
---
 drivers/dma/edma.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index f424298..b779cee 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -72,6 +72,7 @@ struct edma_chan {
 	dma_addr_t			addr;
 	int				addr_width;
 	int				maxburst;
+	struct dma_slave_sg_caps	sg_caps;
 };
 
 struct edma_cc {
@@ -463,6 +464,20 @@ static void edma_issue_pending(struct dma_chan *chan)
 	spin_unlock_irqrestore(&echan->vchan.lock, flags);
 }
 
+static struct dma_slave_sg_caps
+*edma_get_slave_sg_caps(struct dma_chan *chan,
+			enum dma_slave_buswidth addr_width,
+			u32 maxburst)
+{
+	struct edma_chan *echan;
+
+	echan = to_edma_chan(chan);
+	echan->sg_caps.max_seg_len =
+		(SZ_64K - 1) * addr_width * maxburst;
+
+	return &echan->sg_caps;
+}
+
 static size_t edma_desc_size(struct edma_desc *edesc)
 {
 	int i;
@@ -522,6 +537,7 @@ static void __init edma_chan_init(struct edma_cc *ecc,
 		echan->ch_num = EDMA_CTLR_CHAN(ecc->ctlr, i);
 		echan->ecc = ecc;
 		echan->vchan.desc_free = edma_desc_free;
+		echan->sg_caps.max_seg_nr = MAX_NR_SG;
 
 		vchan_init(&echan->vchan, dma);
 
@@ -538,6 +554,7 @@ static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma,
 	dma->device_alloc_chan_resources = edma_alloc_chan_resources;
 	dma->device_free_chan_resources = edma_free_chan_resources;
 	dma->device_issue_pending = edma_issue_pending;
+	dma->device_slave_sg_caps = edma_get_slave_sg_caps;
 	dma->device_tx_status = edma_tx_status;
 	dma->device_control = edma_control;
 	dma->dev = dev;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/3] mmc: davinci: get SG segment limits with dma_get_slave_sg_caps()
  2013-02-04 19:47 ` Matt Porter
@ 2013-02-04 19:47   ` Matt Porter
  -1 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-02-04 19:47 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

Replace the hardcoded values used to set max_segs/max_seg_size with
a dma_get_slave_sg_caps() query to the dmaengine driver.

Signed-off-by: Matt Porter <mporter@ti.com>
---
 drivers/mmc/host/davinci_mmc.c            |   37 ++++++++---------------------
 include/linux/platform_data/mmc-davinci.h |    3 ---
 2 files changed, 10 insertions(+), 30 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 2063677..583cbd0 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -144,18 +144,6 @@
 /* MMCSD Init clock in Hz in opendrain mode */
 #define MMCSD_INIT_CLOCK		200000
 
-/*
- * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
- * and we handle up to MAX_NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
- * for drivers with max_segs == 1, making the segments bigger (64KB)
- * than the page or two that's otherwise typical. nr_sg (passed from
- * platform data) == 16 gives at least the same throughput boost, using
- * EDMA transfer linkage instead of spending CPU time copying pages.
- */
-#define MAX_CCNT	((1 << 16) - 1)
-
-#define MAX_NR_SG	16
-
 static unsigned rw_threshold = 32;
 module_param(rw_threshold, uint, S_IRUGO);
 MODULE_PARM_DESC(rw_threshold,
@@ -216,8 +204,6 @@ struct mmc_davinci_host {
 	u8 version;
 	/* for ns in one cycle calculation */
 	unsigned ns_in_one_cycle;
-	/* Number of sg segments */
-	u8 nr_sg;
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
 #endif
@@ -1165,6 +1151,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 	struct resource *r, *mem = NULL;
 	int ret = 0, irq = 0;
 	size_t mem_size;
+	struct dma_slave_sg_caps *dma_sg_caps;
 
 	/* REVISIT:  when we're fully converted, fail if pdata is NULL */
 
@@ -1214,12 +1201,6 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 
 	init_mmcsd_host(host);
 
-	if (pdata->nr_sg)
-		host->nr_sg = pdata->nr_sg - 1;
-
-	if (host->nr_sg > MAX_NR_SG || !host->nr_sg)
-		host->nr_sg = MAX_NR_SG;
-
 	host->use_dma = use_dma;
 	host->mmc_irq = irq;
 	host->sdio_irq = platform_get_irq(pdev, 1);
@@ -1248,14 +1229,16 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 		mmc->caps |= pdata->caps;
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
-	/* With no iommu coalescing pages, each phys_seg is a hw_seg.
-	 * Each hw_seg uses one EDMA parameter RAM slot, always one
-	 * channel and then usually some linked slots.
-	 */
-	mmc->max_segs		= MAX_NR_SG;
+	/* Just check one channel for the DMA SG limits */
+	dma_sg_caps = dma_get_slave_sg_caps(
+				host->dma_tx,
+				DMA_SLAVE_BUSWIDTH_4_BYTES,
+				rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES);
 
-	/* EDMA limit per hw segment (one or two MBytes) */
-	mmc->max_seg_size	= MAX_CCNT * rw_threshold;
+	if (dma_sg_caps) {
+		mmc->max_segs = dma_sg_caps->max_seg_nr;
+		mmc->max_seg_size = dma_sg_caps->max_seg_len;
+	}
 
 	/* MMC/SD controller limits for multiblock requests */
 	mmc->max_blk_size	= 4095;  /* BLEN is 12 bits */
diff --git a/include/linux/platform_data/mmc-davinci.h b/include/linux/platform_data/mmc-davinci.h
index 5ba6b22..6910209 100644
--- a/include/linux/platform_data/mmc-davinci.h
+++ b/include/linux/platform_data/mmc-davinci.h
@@ -25,9 +25,6 @@ struct davinci_mmc_config {
 
 	/* Version of the MMC/SD controller */
 	u8	version;
-
-	/* Number of sg segments */
-	u8	nr_sg;
 };
 void davinci_setup_mmc(int module, struct davinci_mmc_config *config);
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/3] mmc: davinci: get SG segment limits with dma_get_slave_sg_caps()
@ 2013-02-04 19:47   ` Matt Porter
  0 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-02-04 19:47 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

Replace the hardcoded values used to set max_segs/max_seg_size with
a dma_get_slave_sg_caps() query to the dmaengine driver.

Signed-off-by: Matt Porter <mporter@ti.com>
---
 drivers/mmc/host/davinci_mmc.c            |   37 ++++++++---------------------
 include/linux/platform_data/mmc-davinci.h |    3 ---
 2 files changed, 10 insertions(+), 30 deletions(-)

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 2063677..583cbd0 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -144,18 +144,6 @@
 /* MMCSD Init clock in Hz in opendrain mode */
 #define MMCSD_INIT_CLOCK		200000
 
-/*
- * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
- * and we handle up to MAX_NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
- * for drivers with max_segs == 1, making the segments bigger (64KB)
- * than the page or two that's otherwise typical. nr_sg (passed from
- * platform data) == 16 gives at least the same throughput boost, using
- * EDMA transfer linkage instead of spending CPU time copying pages.
- */
-#define MAX_CCNT	((1 << 16) - 1)
-
-#define MAX_NR_SG	16
-
 static unsigned rw_threshold = 32;
 module_param(rw_threshold, uint, S_IRUGO);
 MODULE_PARM_DESC(rw_threshold,
@@ -216,8 +204,6 @@ struct mmc_davinci_host {
 	u8 version;
 	/* for ns in one cycle calculation */
 	unsigned ns_in_one_cycle;
-	/* Number of sg segments */
-	u8 nr_sg;
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
 #endif
@@ -1165,6 +1151,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 	struct resource *r, *mem = NULL;
 	int ret = 0, irq = 0;
 	size_t mem_size;
+	struct dma_slave_sg_caps *dma_sg_caps;
 
 	/* REVISIT:  when we're fully converted, fail if pdata is NULL */
 
@@ -1214,12 +1201,6 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 
 	init_mmcsd_host(host);
 
-	if (pdata->nr_sg)
-		host->nr_sg = pdata->nr_sg - 1;
-
-	if (host->nr_sg > MAX_NR_SG || !host->nr_sg)
-		host->nr_sg = MAX_NR_SG;
-
 	host->use_dma = use_dma;
 	host->mmc_irq = irq;
 	host->sdio_irq = platform_get_irq(pdev, 1);
@@ -1248,14 +1229,16 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 		mmc->caps |= pdata->caps;
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
-	/* With no iommu coalescing pages, each phys_seg is a hw_seg.
-	 * Each hw_seg uses one EDMA parameter RAM slot, always one
-	 * channel and then usually some linked slots.
-	 */
-	mmc->max_segs		= MAX_NR_SG;
+	/* Just check one channel for the DMA SG limits */
+	dma_sg_caps = dma_get_slave_sg_caps(
+				host->dma_tx,
+				DMA_SLAVE_BUSWIDTH_4_BYTES,
+				rw_threshold / DMA_SLAVE_BUSWIDTH_4_BYTES);
 
-	/* EDMA limit per hw segment (one or two MBytes) */
-	mmc->max_seg_size	= MAX_CCNT * rw_threshold;
+	if (dma_sg_caps) {
+		mmc->max_segs = dma_sg_caps->max_seg_nr;
+		mmc->max_seg_size = dma_sg_caps->max_seg_len;
+	}
 
 	/* MMC/SD controller limits for multiblock requests */
 	mmc->max_blk_size	= 4095;  /* BLEN is 12 bits */
diff --git a/include/linux/platform_data/mmc-davinci.h b/include/linux/platform_data/mmc-davinci.h
index 5ba6b22..6910209 100644
--- a/include/linux/platform_data/mmc-davinci.h
+++ b/include/linux/platform_data/mmc-davinci.h
@@ -25,9 +25,6 @@ struct davinci_mmc_config {
 
 	/* Version of the MMC/SD controller */
 	u8	version;
-
-	/* Number of sg segments */
-	u8	nr_sg;
 };
 void davinci_setup_mmc(int module, struct davinci_mmc_config *config);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/3] dmaengine: add dma_get_slave_sg_caps()
  2013-02-04 19:47   ` Matt Porter
@ 2013-02-12 17:08     ` Vinod Koul
  -1 siblings, 0 replies; 12+ messages in thread
From: Vinod Koul @ 2013-02-12 17:08 UTC (permalink / raw)
  To: Matt Porter
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

On Mon, Feb 04, 2013 at 02:47:02PM -0500, Matt Porter wrote:
> Add a dmaengine API to retrieve slave SG transfer capabilities.
> 
> The API is optionally implemented by dmaengine drivers and when
> unimplemented will return a NULL pointer. A client driver using
> this API provides the required dma channel, address width, and
> burst size of the transfer. dma_get_slave_sg_caps() returns an
> SG caps structure with the maximum number and size of SG segments
> that the given channel can handle.
Okay this sounds much better :-)

few points though:
- you added API for caps, but is actually calculating for given configuration
  the max allowed range. IMHO that is not caps, perhaps renaming to get_max_sg
  /some_better_name would be more apt.
- Still I like the idea of caps, but it should give H/W support capablity. If
  you want to add that, pls develop on same line...

--
~Vinod

> 
> Signed-off-by: Matt Porter <mporter@ti.com>
> ---
>  include/linux/dmaengine.h |   40 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
> 
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index d3201e4..5b5b220 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -371,6 +371,19 @@ struct dma_slave_config {
>  	unsigned int slave_id;
>  };
>  
> +/* struct dma_slave_sg_caps - expose SG transfer capability of a
> + * channel.
> + *
> + * @max_seg_nr: maximum number of SG segments supported on a SG/SLAVE
> + *	    channel (0 for no maximum or not a SG/SLAVE channel)
> + * @max_seg_len: maximum length of SG segments supported on a SG/SLAVE
> + *	     channel (0 for no maximum or not a SG/SLAVE channel)
> + */
> +struct dma_slave_sg_caps {
> +	u32 max_seg_nr;
> +	u32 max_seg_len;
> +};
> +
>  static inline const char *dma_chan_name(struct dma_chan *chan)
>  {
>  	return dev_name(&chan->dev->device);
> @@ -534,6 +547,7 @@ struct dma_tx_state {
>   *	struct with auxiliary transfer status information, otherwise the call
>   *	will just return a simple status code
>   * @device_issue_pending: push pending transactions to hardware
> + * @device_slave_sg_caps: return the slave SG capabilities
>   */
>  struct dma_device {
>  
> @@ -602,6 +616,9 @@ struct dma_device {
>  					    dma_cookie_t cookie,
>  					    struct dma_tx_state *txstate);
>  	void (*device_issue_pending)(struct dma_chan *chan);
> +	struct dma_slave_sg_caps *(*device_slave_sg_caps)(
> +		struct dma_chan *chan, enum dma_slave_buswidth addr_width,
> +		u32 maxburst);
>  };
>  
>  static inline int dmaengine_device_control(struct dma_chan *chan,
> @@ -969,6 +986,29 @@ dma_set_tx_state(struct dma_tx_state *st, dma_cookie_t last, dma_cookie_t used,
>  	}
>  }
>  
> +/**
> + * dma_get_slave_sg_caps - get DMAC SG transfer capabilities
> + * @chan: target DMA channel
> + * @addr_width: address width of the DMA transfer
> + * @maxburst: maximum DMA transfer burst size
> + *
> + * Get SG transfer capabilities for a specified channel. If the dmaengine
> + * driver does not implement SG transfer capabilities then NULL is
> + * returned.
> + */
> +static inline struct dma_slave_sg_caps
> +*dma_get_slave_sg_caps(struct dma_chan *chan,
> +		       enum dma_slave_buswidth addr_width,
> +		       u32 maxburst)
> +{
> +	if (chan->device->device_slave_sg_caps)
> +		return chan->device->device_slave_sg_caps(chan,
> +							  addr_width,
> +							  maxburst);
> +
> +	return NULL;
> +}
> +
>  enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
>  #ifdef CONFIG_DMA_ENGINE
>  enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/3] dmaengine: add dma_get_slave_sg_caps()
@ 2013-02-12 17:08     ` Vinod Koul
  0 siblings, 0 replies; 12+ messages in thread
From: Vinod Koul @ 2013-02-12 17:08 UTC (permalink / raw)
  To: Matt Porter
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

On Mon, Feb 04, 2013 at 02:47:02PM -0500, Matt Porter wrote:
> Add a dmaengine API to retrieve slave SG transfer capabilities.
> 
> The API is optionally implemented by dmaengine drivers and when
> unimplemented will return a NULL pointer. A client driver using
> this API provides the required dma channel, address width, and
> burst size of the transfer. dma_get_slave_sg_caps() returns an
> SG caps structure with the maximum number and size of SG segments
> that the given channel can handle.
Okay this sounds much better :-)

few points though:
- you added API for caps, but is actually calculating for given configuration
  the max allowed range. IMHO that is not caps, perhaps renaming to get_max_sg
  /some_better_name would be more apt.
- Still I like the idea of caps, but it should give H/W support capablity. If
  you want to add that, pls develop on same line...

--
~Vinod

> 
> Signed-off-by: Matt Porter <mporter@ti.com>
> ---
>  include/linux/dmaengine.h |   40 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
> 
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index d3201e4..5b5b220 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -371,6 +371,19 @@ struct dma_slave_config {
>  	unsigned int slave_id;
>  };
>  
> +/* struct dma_slave_sg_caps - expose SG transfer capability of a
> + * channel.
> + *
> + * @max_seg_nr: maximum number of SG segments supported on a SG/SLAVE
> + *	    channel (0 for no maximum or not a SG/SLAVE channel)
> + * @max_seg_len: maximum length of SG segments supported on a SG/SLAVE
> + *	     channel (0 for no maximum or not a SG/SLAVE channel)
> + */
> +struct dma_slave_sg_caps {
> +	u32 max_seg_nr;
> +	u32 max_seg_len;
> +};
> +
>  static inline const char *dma_chan_name(struct dma_chan *chan)
>  {
>  	return dev_name(&chan->dev->device);
> @@ -534,6 +547,7 @@ struct dma_tx_state {
>   *	struct with auxiliary transfer status information, otherwise the call
>   *	will just return a simple status code
>   * @device_issue_pending: push pending transactions to hardware
> + * @device_slave_sg_caps: return the slave SG capabilities
>   */
>  struct dma_device {
>  
> @@ -602,6 +616,9 @@ struct dma_device {
>  					    dma_cookie_t cookie,
>  					    struct dma_tx_state *txstate);
>  	void (*device_issue_pending)(struct dma_chan *chan);
> +	struct dma_slave_sg_caps *(*device_slave_sg_caps)(
> +		struct dma_chan *chan, enum dma_slave_buswidth addr_width,
> +		u32 maxburst);
>  };
>  
>  static inline int dmaengine_device_control(struct dma_chan *chan,
> @@ -969,6 +986,29 @@ dma_set_tx_state(struct dma_tx_state *st, dma_cookie_t last, dma_cookie_t used,
>  	}
>  }
>  
> +/**
> + * dma_get_slave_sg_caps - get DMAC SG transfer capabilities
> + * @chan: target DMA channel
> + * @addr_width: address width of the DMA transfer
> + * @maxburst: maximum DMA transfer burst size
> + *
> + * Get SG transfer capabilities for a specified channel. If the dmaengine
> + * driver does not implement SG transfer capabilities then NULL is
> + * returned.
> + */
> +static inline struct dma_slave_sg_caps
> +*dma_get_slave_sg_caps(struct dma_chan *chan,
> +		       enum dma_slave_buswidth addr_width,
> +		       u32 maxburst)
> +{
> +	if (chan->device->device_slave_sg_caps)
> +		return chan->device->device_slave_sg_caps(chan,
> +							  addr_width,
> +							  maxburst);
> +
> +	return NULL;
> +}
> +
>  enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
>  #ifdef CONFIG_DMA_ENGINE
>  enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/3] dmaengine: add dma_get_slave_sg_caps()
       [not found]   ` <8b3455d3f1aa42818e917d47fd993ea1@DFLE72.ent.ti.com>
@ 2013-03-06 19:58       ` Matt Porter
  0 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-03-06 19:58 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

On Tue, Feb 12, 2013 at 05:08:44PM +0000, Vinod Koul wrote:
> On Mon, Feb 04, 2013 at 02:47:02PM -0500, Matt Porter wrote:
> > Add a dmaengine API to retrieve slave SG transfer capabilities.
> > 
> > The API is optionally implemented by dmaengine drivers and when
> > unimplemented will return a NULL pointer. A client driver using
> > this API provides the required dma channel, address width, and
> > burst size of the transfer. dma_get_slave_sg_caps() returns an
> > SG caps structure with the maximum number and size of SG segments
> > that the given channel can handle.
> Okay this sounds much better :-)
> 
> few points though:
> - you added API for caps, but is actually calculating for given configuration
>   the max allowed range. IMHO that is not caps, perhaps renaming to get_max_sg
>   /some_better_name would be more apt.

I went with get_slave_sg_limits(), seemed pretty descriptive. Just
posted v4 with that change.

> - Still I like the idea of caps, but it should give H/W support capablity. If
>   you want to add that, pls develop on same line...

Ok, seems like a good separate submission.
 
-Matt

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/3] dmaengine: add dma_get_slave_sg_caps()
@ 2013-03-06 19:58       ` Matt Porter
  0 siblings, 0 replies; 12+ messages in thread
From: Matt Porter @ 2013-03-06 19:58 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Dan Williams, Chris Ball, Grant Likely,
	Linux DaVinci Kernel List, Linux Kernel Mailing List,
	Linux MMC List

On Tue, Feb 12, 2013 at 05:08:44PM +0000, Vinod Koul wrote:
> On Mon, Feb 04, 2013 at 02:47:02PM -0500, Matt Porter wrote:
> > Add a dmaengine API to retrieve slave SG transfer capabilities.
> > 
> > The API is optionally implemented by dmaengine drivers and when
> > unimplemented will return a NULL pointer. A client driver using
> > this API provides the required dma channel, address width, and
> > burst size of the transfer. dma_get_slave_sg_caps() returns an
> > SG caps structure with the maximum number and size of SG segments
> > that the given channel can handle.
> Okay this sounds much better :-)
> 
> few points though:
> - you added API for caps, but is actually calculating for given configuration
>   the max allowed range. IMHO that is not caps, perhaps renaming to get_max_sg
>   /some_better_name would be more apt.

I went with get_slave_sg_limits(), seemed pretty descriptive. Just
posted v4 with that change.

> - Still I like the idea of caps, but it should give H/W support capablity. If
>   you want to add that, pls develop on same line...

Ok, seems like a good separate submission.
 
-Matt

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2013-03-06 19:57 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-04 19:47 [PATCH v3 0/3] dmaengine: add slave sg transfer capabilities api Matt Porter
2013-02-04 19:47 ` Matt Porter
2013-02-04 19:47 ` [PATCH v3 1/3] dmaengine: add dma_get_slave_sg_caps() Matt Porter
2013-02-04 19:47   ` Matt Porter
2013-02-12 17:08   ` Vinod Koul
2013-02-12 17:08     ` Vinod Koul
     [not found]   ` <8b3455d3f1aa42818e917d47fd993ea1@DFLE72.ent.ti.com>
2013-03-06 19:58     ` Matt Porter
2013-03-06 19:58       ` Matt Porter
2013-02-04 19:47 ` [PATCH v3 2/3] dma: edma: add device_slave_sg_caps() support Matt Porter
2013-02-04 19:47   ` Matt Porter
2013-02-04 19:47 ` [PATCH v3 3/3] mmc: davinci: get SG segment limits with dma_get_slave_sg_caps() Matt Porter
2013-02-04 19:47   ` Matt Porter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.