Re: [PATCH] mmc: jz4740: rework pre_req/post_req implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 20 November 2018 at 19:21, Ezequiel Garcia <ezequiel@xxxxxxxxxxxxx> wrote:
> As reported by Aaro, the JZ4740 MMC driver throws a warning
> when the kernel is built without preemption (CONFIG_PREEMPT_NONE=y).
>
> [   16.461094] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 567 host->next_data.cookie 568
> [   16.473120] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 568 host->next_data.cookie 569
> [   16.485144] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 569 host->next_data.cookie 570
> [   16.497170] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 570 host->next_data.cookie 571
> [   16.509194] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 571 host->next_data.cookie 572
> [   16.532421] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 572 host->next_data.cookie 573
> [   16.544594] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 573 host->next_data.cookie 574
> [   16.556621] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 574 host->next_data.cookie 575
> [   16.568638] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 575 host->next_data.cookie 576
> [   16.601092] jz4740-mmc 13450000.mmc: [jz4740_mmc_prepare_dma_data] invalid cookie: data->host_cookie 582 host->next_data.cookie 583
>
> The problem seems to be related to how pre_req/post_req is implemented.
> Currently, it seems the driver expects jz4740_mmc_prepare_dma_data()
> to be called with monotonically increasing host_cookie values,
> which is wrong.
>
> Moreover, the implementation is overly complicated, keeping track
> of unneeded "next cookie" state.
>
> So, instead of attempting to fix the current pre_req/post_req
> implementation, this commit refactors the driver, dropping
> the state, following other drivers such as dw_mmc and sdhci.
>
> Cc: Paul Cercueil <paul@xxxxxxxxxxxxxxx>
> Cc: Mathieu Malaterre <malat@xxxxxxxxxx>
> Reported-by: Aaro Koskinen <aaro.koskinen@xxxxxx>
> Signed-off-by: Ezequiel Garcia <ezequiel@xxxxxxxxxxxxx>

This looks good to me, however because of the rather big changes I
doubt this can be tagged for stable - or did you have a try to apply
it for an old kernel?

In either case, I can queue this up for next, which anyway seems like
it should be sufficient. Right?

Kind regards
Uffe

> ---
>  drivers/mmc/host/jz4740_mmc.c | 118 ++++++++++++++++------------------
>  1 file changed, 54 insertions(+), 64 deletions(-)
>
> diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
> index 0c1efd5100b7..ca20e2f81be8 100644
> --- a/drivers/mmc/host/jz4740_mmc.c
> +++ b/drivers/mmc/host/jz4740_mmc.c
> @@ -126,9 +126,23 @@ enum jz4740_mmc_state {
>         JZ4740_MMC_STATE_DONE,
>  };
>
> -struct jz4740_mmc_host_next {
> -       int sg_len;
> -       s32 cookie;
> +/*
> + * The MMC core allows to prepare a mmc_request while another mmc_request
> + * is in-flight. This is used via the pre_req/post_req hooks.
> + * This driver uses the pre_req/post_req hooks to map/unmap the mmc_request.
> + * Following what other drivers do (sdhci, dw_mmc) we use the following cookie
> + * flags to keep track of the mmc_request mapping state.
> + *
> + * COOKIE_UNMAPPED: the request is not mapped.
> + * COOKIE_PREMAPPED: the request was mapped in pre_req,
> + * and should be unmapped in post_req.
> + * COOKIE_MAPPED: the request was mapped in the irq handler,
> + * and should be unmapped before mmc_request_done is called..
> + */
> +enum jz4780_cookie {
> +       COOKIE_UNMAPPED = 0,
> +       COOKIE_PREMAPPED,
> +       COOKIE_MAPPED,
>  };
>
>  struct jz4740_mmc_host {
> @@ -162,9 +176,7 @@ struct jz4740_mmc_host {
>         /* DMA support */
>         struct dma_chan *dma_rx;
>         struct dma_chan *dma_tx;
> -       struct jz4740_mmc_host_next next_data;
>         bool use_dma;
> -       int sg_len;
>
>  /* The DMA trigger level is 8 words, that is to say, the DMA read
>   * trigger is when data words in MSC_RXFIFO is >= 8 and the DMA write
> @@ -226,9 +238,6 @@ static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
>                 return PTR_ERR(host->dma_rx);
>         }
>
> -       /* Initialize DMA pre request cookie */
> -       host->next_data.cookie = 1;
> -
>         return 0;
>  }
>
> @@ -245,60 +254,44 @@ static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host,
>         enum dma_data_direction dir = mmc_get_dma_dir(data);
>
>         dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
> +       data->host_cookie = COOKIE_UNMAPPED;
>  }
>
> -/* Prepares DMA data for current/next transfer, returns non-zero on failure */
> +/* Prepares DMA data for current or next transfer.
> + * A request can be in-flight when this is called.
> + */
>  static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
>                                        struct mmc_data *data,
> -                                      struct jz4740_mmc_host_next *next,
> -                                      struct dma_chan *chan)
> +                                      int cookie)
>  {
> -       struct jz4740_mmc_host_next *next_data = &host->next_data;
> +       struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
>         enum dma_data_direction dir = mmc_get_dma_dir(data);
> -       int sg_len;
> -
> -       if (!next && data->host_cookie &&
> -           data->host_cookie != host->next_data.cookie) {
> -               dev_warn(mmc_dev(host->mmc),
> -                        "[%s] invalid cookie: data->host_cookie %d host->next_data.cookie %d\n",
> -                        __func__,
> -                        data->host_cookie,
> -                        host->next_data.cookie);
> -               data->host_cookie = 0;
> -       }
> +       int sg_count;
>
> -       /* Check if next job is already prepared */
> -       if (next || data->host_cookie != host->next_data.cookie) {
> -               sg_len = dma_map_sg(chan->device->dev,
> -                                   data->sg,
> -                                   data->sg_len,
> -                                   dir);
> +       if (data->host_cookie == COOKIE_PREMAPPED)
> +               return data->sg_count;
>
> -       } else {
> -               sg_len = next_data->sg_len;
> -               next_data->sg_len = 0;
> -       }
> +       sg_count = dma_map_sg(chan->device->dev,
> +                       data->sg,
> +                       data->sg_len,
> +                       dir);
>
> -       if (sg_len <= 0) {
> +       if (sg_count <= 0) {
>                 dev_err(mmc_dev(host->mmc),
>                         "Failed to map scatterlist for DMA operation\n");
>                 return -EINVAL;
>         }
>
> -       if (next) {
> -               next->sg_len = sg_len;
> -               data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
> -       } else
> -               host->sg_len = sg_len;
> +       data->sg_count = sg_count;
> +       data->host_cookie = cookie;
>
> -       return 0;
> +       return data->sg_count;
>  }
>
>  static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
>                                          struct mmc_data *data)
>  {
> -       int ret;
> -       struct dma_chan *chan;
> +       struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
>         struct dma_async_tx_descriptor *desc;
>         struct dma_slave_config conf = {
>                 .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
> @@ -306,29 +299,26 @@ static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
>                 .src_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
>                 .dst_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
>         };
> +       int sg_count;
>
>         if (data->flags & MMC_DATA_WRITE) {
>                 conf.direction = DMA_MEM_TO_DEV;
>                 conf.dst_addr = host->mem_res->start + JZ_REG_MMC_TXFIFO;
>                 conf.slave_id = JZ4740_DMA_TYPE_MMC_TRANSMIT;
> -               chan = host->dma_tx;
>         } else {
>                 conf.direction = DMA_DEV_TO_MEM;
>                 conf.src_addr = host->mem_res->start + JZ_REG_MMC_RXFIFO;
>                 conf.slave_id = JZ4740_DMA_TYPE_MMC_RECEIVE;
> -               chan = host->dma_rx;
>         }
>
> -       ret = jz4740_mmc_prepare_dma_data(host, data, NULL, chan);
> -       if (ret)
> -               return ret;
> +       sg_count = jz4740_mmc_prepare_dma_data(host, data, COOKIE_MAPPED);
> +       if (sg_count < 0)
> +               return sg_count;
>
>         dmaengine_slave_config(chan, &conf);
> -       desc = dmaengine_prep_slave_sg(chan,
> -                                      data->sg,
> -                                      host->sg_len,
> -                                      conf.direction,
> -                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
> +       desc = dmaengine_prep_slave_sg(chan, data->sg, sg_count,
> +                       conf.direction,
> +                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
>         if (!desc) {
>                 dev_err(mmc_dev(host->mmc),
>                         "Failed to allocate DMA %s descriptor",
> @@ -342,7 +332,8 @@ static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
>         return 0;
>
>  dma_unmap:
> -       jz4740_mmc_dma_unmap(host, data);
> +       if (data->host_cookie == COOKIE_MAPPED)
> +               jz4740_mmc_dma_unmap(host, data);
>         return -ENOMEM;
>  }
>
> @@ -351,16 +342,13 @@ static void jz4740_mmc_pre_request(struct mmc_host *mmc,
>  {
>         struct jz4740_mmc_host *host = mmc_priv(mmc);
>         struct mmc_data *data = mrq->data;
> -       struct jz4740_mmc_host_next *next_data = &host->next_data;
>
> -       BUG_ON(data->host_cookie);
> -
> -       if (host->use_dma) {
> -               struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
> +       if (!host->use_dma)
> +               return;
>
> -               if (jz4740_mmc_prepare_dma_data(host, data, next_data, chan))
> -                       data->host_cookie = 0;
> -       }
> +       data->host_cookie = COOKIE_UNMAPPED;
> +       if (jz4740_mmc_prepare_dma_data(host, data, COOKIE_PREMAPPED) < 0)
> +               data->host_cookie = COOKIE_UNMAPPED;
>  }
>
>  static void jz4740_mmc_post_request(struct mmc_host *mmc,
> @@ -370,10 +358,8 @@ static void jz4740_mmc_post_request(struct mmc_host *mmc,
>         struct jz4740_mmc_host *host = mmc_priv(mmc);
>         struct mmc_data *data = mrq->data;
>
> -       if (host->use_dma && data->host_cookie) {
> +       if (data && data->host_cookie != COOKIE_UNMAPPED)
>                 jz4740_mmc_dma_unmap(host, data);
> -               data->host_cookie = 0;
> -       }
>
>         if (err) {
>                 struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
> @@ -436,10 +422,14 @@ static void jz4740_mmc_reset(struct jz4740_mmc_host *host)
>  static void jz4740_mmc_request_done(struct jz4740_mmc_host *host)
>  {
>         struct mmc_request *req;
> +       struct mmc_data *data;
>
>         req = host->req;
> +       data = req->data;
>         host->req = NULL;
>
> +       if (data && data->host_cookie == COOKIE_MAPPED)
> +               jz4740_mmc_dma_unmap(host, data);
>         mmc_request_done(host->mmc, req);
>  }
>
> --
> 2.19.1
>



[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux