RE: [RFC PATCH v6 5/5] mmc: queue: Use bigger segments if IOMMU can merge the segments

2019-06-17 Thread Yoshihiro Shimoda
Hi Christoph,

> From: Christoph Hellwig, Sent: Monday, June 17, 2019 3:54 PM
> 
> On Mon, Jun 17, 2019 at 06:46:33AM +, Yoshihiro Shimoda wrote:
> > > can_merge seems a little too generic a name to me.  Maybe can_iommu_merge?
> >
> > I'll fix the name. Also, only the device_iommu_mapped() condition wiil cause
> > a problem on iommu=pt [1]. So, I'll add another condition here.
> 
> Instead of adding another condition here I think we need to properly
> abstract it out in the DMA layer.  E.g. have a

Thank you for your comment and sample code! I'll add such functions
on next patch series.

Best regards,
Yoshihiro Shimoda

> unsigned long dma_get_merge_boundary(struct device *dev)
> {
>   const struct dma_map_ops *ops = get_dma_ops(dev);
> 
>   if (!ops || !ops->get_merge_boundary)
>   return 0; /* can't merge */
>   return ops->get_merge_boundary(dev);
> }
> 
> and then implement the method in dma-iommu.c.
> 
> blk_queue_can_use_iommu_merging then comes:
> 
> bool blk_queue_enable_iommu_merging(struct request_queue *q,
>   struct device *dev)
> {
>   unsigned long boundary = dma_get_merge_boundary(dev);
> 
>   if (!boundary)
>   return false;
>   blk_queue_virt_boundary(q, boundary);
>   return true;
> }


Re: [RFC PATCH v6 5/5] mmc: queue: Use bigger segments if IOMMU can merge the segments

2019-06-17 Thread Christoph Hellwig
On Mon, Jun 17, 2019 at 06:46:33AM +, Yoshihiro Shimoda wrote:
> > can_merge seems a little too generic a name to me.  Maybe can_iommu_merge?
> 
> I'll fix the name. Also, only the device_iommu_mapped() condition wiil cause
> a problem on iommu=pt [1]. So, I'll add another condition here.

Instead of adding another condition here I think we need to properly
abstract it out in the DMA layer.  E.g. have a

unsigned long dma_get_merge_boundary(struct device *dev)
{
const struct dma_map_ops *ops = get_dma_ops(dev);

if (!ops || !ops->get_merge_boundary)
return 0; /* can't merge */
return ops->get_merge_boundary(dev);
}

and then implement the method in dma-iommu.c.

blk_queue_can_use_iommu_merging then comes:

bool blk_queue_enable_iommu_merging(struct request_queue *q,
struct device *dev)
{
unsigned long boundary = dma_get_merge_boundary(dev);

if (!boundary)
return false;
blk_queue_virt_boundary(q, boundary);
return true;
}


RE: [RFC PATCH v6 5/5] mmc: queue: Use bigger segments if IOMMU can merge the segments

2019-06-17 Thread Yoshihiro Shimoda
Hi Christoph,

> From: Christoph Hellwig, Sent: Friday, June 14, 2019 4:25 PM
> 
> On Thu, Jun 13, 2019 at 07:20:15PM +0900, Yoshihiro Shimoda wrote:
> > +static unsigned int mmc_get_max_segments(struct mmc_host *host)
> > +{
> > +   return host->can_merge ? BLK_MAX_SEGMENTS : host->max_segs;
> > +}
> 
> Note that BLK_MAX_SEGMENTS is really a little misnamed, it just
> is a BLK_DEFAULT_SEGMENTS.  I think you are better of picking your
> own value here (even if 128 ends up ok) than reusing this somewhat
> confusing constant.

Thank you for your comments. I got it. I'll fix this.

> > +   /*
> > +* Since blk_mq_alloc_tag_set() calls .init_request() of mmc_mq_ops,
> > +* the host->can_merge should be set before to get max_segs from
> > +* mmc_get_max_segments().
> > +*/
> > +   if (host->max_segs < BLK_MAX_SEGMENTS &&
> > +   device_iommu_mapped(mmc_dev(host)))
> > +   host->can_merge = 1;
> > +   else
> > +   host->can_merge = 0;
> > +
> 
> can_merge seems a little too generic a name to me.  Maybe can_iommu_merge?

I'll fix the name. Also, only the device_iommu_mapped() condition wiil cause
a problem on iommu=pt [1]. So, I'll add another condition here.

[1]
https://marc.info/?l=linux-mmc=156050608709643=2

Best regards,
Yoshihiro Shimoda

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [RFC PATCH v6 5/5] mmc: queue: Use bigger segments if IOMMU can merge the segments

2019-06-17 Thread Yoshihiro Shimoda
Hi Wolfram-san,

> From: Wolfram Sang, Sent: Friday, June 14, 2019 4:59 AM
> 
> > -   blk_queue_max_segments(mq->queue, host->max_segs);
> > +   /* blk_queue_can_use_iommu_merging() should succeed if can_merge = 1 */
> > +   if (host->can_merge &&
> > +   !blk_queue_can_use_iommu_merging(mq->queue, mmc_dev(host)))
> > +   WARN_ON(1);
> > +   blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));
> 
> Maybe we could use WARN here to save the comment and move the info to
> the printout?
> 
> - blk_queue_max_segments(mq->queue, host->max_segs);
> + if (host->can_merge)
> + WARN(!blk_queue_can_use_iommu_merging(mq->queue, mmc_dev(host)),
> +  "merging was advertised but not possible\n");
> + blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));

Thank you for the suggestion. It's a good idea! I'll fix the patch.

Best regards,
Yoshihiro Shimoda



Re: [RFC PATCH v6 5/5] mmc: queue: Use bigger segments if IOMMU can merge the segments

2019-06-14 Thread Wolfram Sang

> > +   host->can_merge = 1;
> > +   else
> > +   host->can_merge = 0;
> > +
> 
> can_merge seems a little too generic a name to me.  Maybe can_iommu_merge?

Ack.



signature.asc
Description: PGP signature


Re: [RFC PATCH v6 5/5] mmc: queue: Use bigger segments if IOMMU can merge the segments

2019-06-14 Thread Christoph Hellwig
On Thu, Jun 13, 2019 at 07:20:15PM +0900, Yoshihiro Shimoda wrote:
> +static unsigned int mmc_get_max_segments(struct mmc_host *host)
> +{
> + return host->can_merge ? BLK_MAX_SEGMENTS : host->max_segs;
> +}

Note that BLK_MAX_SEGMENTS is really a little misnamed, it just
is a BLK_DEFAULT_SEGMENTS.  I think you are better of picking your
own value here (even if 128 ends up ok) than reusing this somewhat
confusing constant.

> + /*
> +  * Since blk_mq_alloc_tag_set() calls .init_request() of mmc_mq_ops,
> +  * the host->can_merge should be set before to get max_segs from
> +  * mmc_get_max_segments().
> +  */
> + if (host->max_segs < BLK_MAX_SEGMENTS &&
> + device_iommu_mapped(mmc_dev(host)))
> + host->can_merge = 1;
> + else
> + host->can_merge = 0;
> +

can_merge seems a little too generic a name to me.  Maybe can_iommu_merge?


Re: [RFC PATCH v6 5/5] mmc: queue: Use bigger segments if IOMMU can merge the segments

2019-06-13 Thread Wolfram Sang

> - blk_queue_max_segments(mq->queue, host->max_segs);
> + /* blk_queue_can_use_iommu_merging() should succeed if can_merge = 1 */
> + if (host->can_merge &&
> + !blk_queue_can_use_iommu_merging(mq->queue, mmc_dev(host)))
> + WARN_ON(1);
> + blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));

Maybe we could use WARN here to save the comment and move the info to
the printout?

-   blk_queue_max_segments(mq->queue, host->max_segs);
+   if (host->can_merge)
+   WARN(!blk_queue_can_use_iommu_merging(mq->queue, mmc_dev(host)),
+"merging was advertised but not possible\n");
+   blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));



signature.asc
Description: PGP signature


[RFC PATCH v6 5/5] mmc: queue: Use bigger segments if IOMMU can merge the segments

2019-06-13 Thread Yoshihiro Shimoda
If max_segs of a mmc host is smaller than BLK_MAX_SEGMENTS,
the mmc subsystem tries to use such bigger segments by using
IOMMU subsystem, and then the mmc subsystem exposes such information
to the block layer by using blk_queue_can_use_iommu_merging().

Signed-off-by: Yoshihiro Shimoda 
---
 drivers/mmc/core/queue.c | 33 +
 include/linux/mmc/host.h |  1 +
 2 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index b5b9c61..59d7606 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -196,6 +196,11 @@ static void mmc_queue_setup_discard(struct request_queue 
*q,
blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
 }
 
+static unsigned int mmc_get_max_segments(struct mmc_host *host)
+{
+   return host->can_merge ? BLK_MAX_SEGMENTS : host->max_segs;
+}
+
 /**
  * mmc_init_request() - initialize the MMC-specific per-request data
  * @q: the request queue
@@ -209,7 +214,7 @@ static int __mmc_init_request(struct mmc_queue *mq, struct 
request *req,
struct mmc_card *card = mq->card;
struct mmc_host *host = card->host;
 
-   mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp);
+   mq_rq->sg = mmc_alloc_sg(mmc_get_max_segments(host), gfp);
if (!mq_rq->sg)
return -ENOMEM;
 
@@ -368,15 +373,24 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct 
mmc_card *card)
blk_queue_bounce_limit(mq->queue, limit);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
-   blk_queue_max_segments(mq->queue, host->max_segs);
+   /* blk_queue_can_use_iommu_merging() should succeed if can_merge = 1 */
+   if (host->can_merge &&
+   !blk_queue_can_use_iommu_merging(mq->queue, mmc_dev(host)))
+   WARN_ON(1);
+   blk_queue_max_segments(mq->queue, mmc_get_max_segments(host));
 
if (mmc_card_mmc(card))
block_size = card->ext_csd.data_sector_size;
 
blk_queue_logical_block_size(mq->queue, block_size);
-   blk_queue_max_segment_size(mq->queue,
+   /*
+* After blk_queue_can_use_iommu_merging() was called with succeed,
+* since it calls blk_queue_virt_boundary for IOMMU, the mmc should
+* not call blk_queue_max_segment_size().
+*/
+   if (!host->can_merge)
+   blk_queue_max_segment_size(mq->queue,
round_down(host->max_seg_size, block_size));
-
INIT_WORK(>recovery_work, mmc_mq_recovery_handler);
INIT_WORK(>complete_work, mmc_blk_mq_complete_work);
 
@@ -422,6 +436,17 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card 
*card)
mq->tag_set.cmd_size = sizeof(struct mmc_queue_req);
mq->tag_set.driver_data = mq;
 
+   /*
+* Since blk_mq_alloc_tag_set() calls .init_request() of mmc_mq_ops,
+* the host->can_merge should be set before to get max_segs from
+* mmc_get_max_segments().
+*/
+   if (host->max_segs < BLK_MAX_SEGMENTS &&
+   device_iommu_mapped(mmc_dev(host)))
+   host->can_merge = 1;
+   else
+   host->can_merge = 0;
+
ret = blk_mq_alloc_tag_set(>tag_set);
if (ret)
return ret;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 43d0f0c..84b9bef 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -398,6 +398,7 @@ struct mmc_host {
unsigned intretune_now:1;   /* do re-tuning at next req */
unsigned intretune_paused:1; /* re-tuning is temporarily 
disabled */
unsigned intuse_blk_mq:1;   /* use blk-mq */
+   unsigned intcan_merge:1;/* merging can be used */
 
int rescan_disable; /* disable card detection */
int rescan_entered; /* used with nonremovable 
devices */
-- 
2.7.4

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu