Re: [RFC PATCH v3.1 00/27] Add support UHS-II for GL9755

2020-12-07 Thread AKASHI Takahiro
Adrian,

On Thu, Dec 03, 2020 at 11:55:23AM +0200, Adrian Hunter wrote:
> On 1/12/20 5:09 am, AKASHI Takahiro wrote:
> > Adrian,
> > 
> > Thank you for your review comments.
> > 
> > On Thu, Nov 26, 2020 at 10:18:55AM +0200, Adrian Hunter wrote:
> >> On 25/11/20 9:41 am, AKASHI Takahiro wrote:
> >>> Gentle ping;
> >>>
> >>> On Fri, Nov 06, 2020 at 11:26:59AM +0900, AKASHI Takahiro wrote:
> >>>> This is an interim snapshot of our next version, v4, for enabling
> >>>> UHS-II on MMC/SD.
> >>>>
> >>>> It is focused on 'sdhci' side to address Adrian's comments regarding
> >>>> "modularising" sdhci-uhs2.c.
> >>>> The whole aim of this version is to get early feedback from Adrian (and
> >>>> others) on this issue. Without any consensus about the code structure,
> >>>
> >>> Any comments so far?
> >>>
> >>
> >> Overall, I like this approach of separating UHS2 from legacy sdhci as much
> >> as possible.  The only major change, is to drop support for legacy quirks
> >> and features that you do not need.  The reason for that, is that there may
> >> be few drivers that end up with UHS-II support (opting instead for SD
> >> Express), so there is no point going to a lot of trouble to support things
> >> that never get used.
> >>
> >> From what I have seen that looks like it includes:
> >>- any quirks
> > 
> > GLI driver (gl9755) needs
> >   * SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
> >   * SDHCI_QUIRK2_BROKEN_DDR50
> > but they are managed in sdhci code.
> > 
> >>- SDHCI LED support
> >>- external DMA support
> > 
> > Should we add 'depends on !SDHCI_UHS2' to MMC_SDHCI_EXTERNAL_DMA?
> > 
> >> In this regard, the important thing is to have a comment somewhere that
> >> lists what is not supported.
> >>
> >> I have only looked at SDHCI patches so far, and only up to about patch 20,
> >> but maybe that gives you enough to go on for a while.
> > 
> > Well, I have almost done.
> > Can I expect your comments on the patches #21-#27 as well soon?
> 
> I have made some more comments and that is all for now, except for anything
> more you wish to discuss.

Thank you.
I assume that you don't have any objection against adding extra hooks
to sdhci_ops in patch#23 and #25, do you?

If so, since we don't have any critical issues to discuss,
I hope that my changes will be contained in the new version
where a major rework will be done on the core side by Ben.

-Takahiro Akashi


Re: [RFC PATCH v3.1 22/27] mmc: sdhci-uhs2: add add_host() and others to set up the driver

2020-12-07 Thread AKASHI Takahiro
On Thu, Dec 03, 2020 at 11:42:34AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > This is a UHS-II version of sdhci's add_host/remove_host operation.
> > Any sdhci drivers which are capable of handling UHS-II cards must
> > call those functions instead of the corresponding sdhci's.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 198 ++
> >  drivers/mmc/host/sdhci-uhs2.h |   2 +
> >  drivers/mmc/host/sdhci.c  |  24 +++--
> >  drivers/mmc/host/sdhci.h  |  10 ++
> >  4 files changed, 226 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index d50134e912f3..5d3362ea138f 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -15,6 +15,7 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >  
> >  #include "sdhci.h"
> >  #include "sdhci-uhs2.h"
> > @@ -406,6 +407,15 @@ static inline void sdhci_led_deactivate(struct 
> > sdhci_host *host)
> >  {
> >  }
> >  #else
> > +static inline int sdhci_led_register(struct sdhci_host *host)
> > +{
> > +   return 0;
> > +}
> > +
> > +static inline void sdhci_led_unregister(struct sdhci_host *host)
> > +{
> > +}
> > +
> >  static inline void sdhci_led_activate(struct sdhci_host *host)
> >  {
> > __sdhci_led_activate(host);
> > @@ -1298,6 +1308,194 @@ static irqreturn_t sdhci_uhs2_thread_irq(int irq, 
> > void *dev_id)
> > return IRQ_HANDLED;
> >  }
> >  
> > +/*\
> > + *
> > + * Device allocation/registration  
> >   *
> > + * 
> >   *
> > +\*/
> > +
> > +static int __sdhci_uhs2_add_host_v4(struct sdhci_host *host, u32 caps1)
> > +{
> > +   struct mmc_host *mmc;
> > +   u32 max_current_caps2;
> > +
> > +   if (host->version < SDHCI_SPEC_400)
> > +   return 0;
> > +
> > +   mmc = host->mmc;
> > +
> > +   /* Support UHS2 */
> > +   if (caps1 & SDHCI_SUPPORT_UHS2)
> > +   mmc->caps |= MMC_CAP_UHS2;
> > +
> > +   max_current_caps2 = sdhci_readl(host, SDHCI_MAX_CURRENT_1);
> > +
> > +   if ((caps1 & SDHCI_SUPPORT_VDD2_180) &&
> > +   !max_current_caps2 &&
> > +   !IS_ERR(mmc->supply.vmmc2)) {
> > +   /* UHS2 - VDD2 */
> > +   int curr = regulator_get_current_limit(mmc->supply.vmmc2);
> > +
> > +   if (curr > 0) {
> > +   /* convert to SDHCI_MAX_CURRENT format */
> > +   curr = curr / 1000;  /* convert to mA */
> > +   curr = curr / SDHCI_MAX_CURRENT_MULTIPLIER;
> > +   curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
> > +   max_current_caps2 = curr;
> > +   }
> > +   }
> > +
> > +   if (caps1 & SDHCI_SUPPORT_VDD2_180) {
> > +   mmc->ocr_avail_uhs2 |= MMC_VDD2_165_195;
> > +   /*
> > +* UHS2 doesn't require this. Only UHS-I bus needs to set
> > +* max current.
> > +*/
> > +   mmc->max_current_180_vdd2 = (max_current_caps2 &
> > +   SDHCI_MAX_CURRENT_VDD2_180_MASK) *
> > +   SDHCI_MAX_CURRENT_MULTIPLIER;
> > +   } else {
> > +   mmc->caps &= ~MMC_CAP_UHS2;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int sdhci_uhs2_host_ops_init(struct sdhci_host *host);
> > +
> > +static int __sdhci_uhs2_add_host(struct sdhci_host *host)
> 
> Can you leverage __sdhci_add_host() here?

Yes if we can always use sdhci_request_done() instead of
sdhci_uhs2_request_done() and we don't need sdhci_uhs2_thread_irq().

> > +{
> > +   unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI;
> > +   struct mmc_host *mmc = host->mmc;
> > +   int ret;
> > +
> > +   if ((mmc->caps2 & MMC_CAP2_CQE) &&
> > +   (host->quirks & SDHCI_QUIRK_BROKEN_CQE)) {
> > +   mmc->caps2 &= 

Re: [RFC PATCH v3.1 21/27] mmc: sdhci-uhs2: add irq() and others

2020-12-07 Thread AKASHI Takahiro
On Tue, Dec 01, 2020 at 06:46:39PM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > This is a UHS-II version of sdhci's request() operation.
> > It handles UHS-II related command interrupts and errors.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 247 ++
> >  drivers/mmc/host/sdhci-uhs2.h |   3 +
> >  drivers/mmc/host/sdhci.c  | 112 ---
> >  drivers/mmc/host/sdhci.h  |   6 +
> >  4 files changed, 319 insertions(+), 49 deletions(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 36e52553977a..d50134e912f3 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -11,6 +11,7 @@
> >   */
> >  
> >  #include 
> > +#include 
> >  #include 
> >  #include 
> >  #include 
> > @@ -670,6 +671,12 @@ static inline void 
> > sdhci_external_dma_pre_transfer(struct sdhci_host *host,
> >struct mmc_command *cmd)
> >  {
> >  }
> > +
> > +static inline struct dma_chan *sdhci_external_dma_channel(struct 
> > sdhci_host *host,
> > + struct mmc_data *data)
> > +{
> > +   return NULL;
> > +}
> >  #endif /* CONFIG_MMC_SDHCI_EXTERNAL_DMA */
> >  
> >  static void sdhci_uhs2_finish_data(struct sdhci_host *host)
> > @@ -1051,6 +1058,246 @@ static void sdhci_uhs2_finish_command(struct 
> > sdhci_host *host)
> > }
> >  }
> >  
> > +/*\
> > + * 
> >   *
> > + * Request done
> >   *
> > + * 
> >   *
> > +\*/
> > +
> > +static bool sdhci_uhs2_request_done(struct sdhci_host *host)
> > +{
> > +   unsigned long flags;
> > +   struct mmc_request *mrq;
> > +   int i;
> > +
> > +   /* FIXME: UHS2_INITIALIZED, instead? */
> > +   if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
> > +   return sdhci_request_done(host);
> > +
> > +   spin_lock_irqsave(&host->lock, flags);
> > +
> > +   for (i = 0; i < SDHCI_MAX_MRQS; i++) {
> > +   mrq = host->mrqs_done[i];
> > +   if (mrq)
> > +   break;
> > +   }
> > +
> > +   if (!mrq) {
> > +   spin_unlock_irqrestore(&host->lock, flags);
> > +   return true;
> > +   }
> > +
> > +   /*
> > +* Always unmap the data buffers if they were mapped by
> > +* sdhci_prepare_data() whenever we finish with a request.
> > +* This avoids leaking DMA mappings on error.
> > +*/
> > +   if (host->flags & SDHCI_REQ_USE_DMA) {
> > +   struct mmc_data *data = mrq->data;
> > +
> > +   if (host->use_external_dma && data &&
> > +   (mrq->cmd->error || data->error)) {
> > +   struct dma_chan *chan = 
> > sdhci_external_dma_channel(host, data);
> > +
> > +   host->mrqs_done[i] = NULL;
> > +   spin_unlock_irqrestore(&host->lock, flags);
> > +   dmaengine_terminate_sync(chan);
> > +   spin_lock_irqsave(&host->lock, flags);
> > +   sdhci_set_mrq_done(host, mrq);
> > +   }
> > +
> > +   sdhci_request_done_dma(host, mrq);
> > +   }
> > +
> > +   /*
> > +* The controller needs a reset of internal state machines
> > +* upon error conditions.
> > +*/
> > +   if (sdhci_needs_reset(host, mrq)) {
> > +   /*
> > +* Do not finish until command and data lines are available for
> > +* reset. Note there can only be one other mrq, so it cannot
> > +* also be in mrqs_done, otherwise host->cmd and host->data_cmd
> > +* would both be null.
> > +*/
> > +   if (host->cmd || host->data_cmd) {
> > +   spin_unlock_irqrestore(&host->lock, flags);
> > +   return true;
> > + 

Re: [RFC PATCH v3.1 00/27] Add support UHS-II for GL9755

2020-11-30 Thread AKASHI Takahiro
Adrian,

Thank you for your review comments.

On Thu, Nov 26, 2020 at 10:18:55AM +0200, Adrian Hunter wrote:
> On 25/11/20 9:41 am, AKASHI Takahiro wrote:
> > Gentle ping;
> > 
> > On Fri, Nov 06, 2020 at 11:26:59AM +0900, AKASHI Takahiro wrote:
> >> This is an interim snapshot of our next version, v4, for enabling
> >> UHS-II on MMC/SD.
> >>
> >> It is focused on 'sdhci' side to address Adrian's comments regarding
> >> "modularising" sdhci-uhs2.c.
> >> The whole aim of this version is to get early feedback from Adrian (and
> >> others) on this issue. Without any consensus about the code structure,
> > 
> > Any comments so far?
> > 
> 
> Overall, I like this approach of separating UHS2 from legacy sdhci as much
> as possible.  The only major change, is to drop support for legacy quirks
> and features that you do not need.  The reason for that, is that there may
> be few drivers that end up with UHS-II support (opting instead for SD
> Express), so there is no point going to a lot of trouble to support things
> that never get used.
> 
> From what I have seen that looks like it includes:
>   - any quirks

GLI driver (gl9755) needs
  * SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
  * SDHCI_QUIRK2_BROKEN_DDR50
but they are managed in sdhci code.

>   - SDHCI LED support
>   - external DMA support

Should we add 'depends on !SDHCI_UHS2' to MMC_SDHCI_EXTERNAL_DMA?

> In this regard, the important thing is to have a comment somewhere that
> lists what is not supported.
> 
> I have only looked at SDHCI patches so far, and only up to about patch 20,
> but maybe that gives you enough to go on for a while.

Well, I have almost done.
Can I expect your comments on the patches #21-#27 as well soon?

-Takahiro Akashi


Re: [RFC PATCH v3.1 20/27] mmc: sdhci-uhs2: add request() and others

2020-11-30 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:18:44AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > This is a sdhci version of mmc's request operation.
> > It covers both UHS-I and UHS-II.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 529 ++
> >  drivers/mmc/host/sdhci.c  |  93 +++---
> >  drivers/mmc/host/sdhci.h  |  21 ++
> >  3 files changed, 610 insertions(+), 33 deletions(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index d8afb99a9918..36e52553977a 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -13,6 +13,7 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >  
> >  #include "sdhci.h"
> >  #include "sdhci-uhs2.h"
> > @@ -394,6 +395,27 @@ static int sdhci_uhs2_check_dormant(struct sdhci_host 
> > *host)
> > return 0;
> >  }
> >  
> > +/* TODO: move them to a header */
> > +#if IS_REACHABLE(CONFIG_LEDS_CLASS)
> > +static inline void sdhci_led_activate(struct sdhci_host *host)
> > +{
> > +}
> > +
> > +static inline void sdhci_led_deactivate(struct sdhci_host *host)
> > +{
> > +}
> > +#else
> > +static inline void sdhci_led_activate(struct sdhci_host *host)
> > +{
> > +   __sdhci_led_activate(host);
> > +}
> > +
> > +static inline void sdhci_led_deactivate(struct sdhci_host *host)
> > +{
> > +   __sdhci_led_deactivate(host);
> > +}
> > +#endif
> 
> Unless you need LED support, let's drop  it

Okay

> > +
> >  
> > /*\
> >   * 
> >   *
> >   * MMC callbacks   
> >   *
> > @@ -523,6 +545,512 @@ static int sdhci_uhs2_set_reg(struct mmc_host *mmc, 
> > enum uhs2_act act)
> > return err;
> >  }
> >  
> > +static bool sdhci_uhs2_send_command(struct sdhci_host *host,
> > +   struct mmc_command *cmd);
> > +static bool sdhci_uhs2_send_command_retry(struct sdhci_host *host,
> > +struct mmc_command *cmd,
> > +unsigned long flags);
> 
> Always order functions so that early function declarations are not needed

Will try.

> > +
> > +void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
> > +{
> > +   struct sdhci_host *host = mmc_priv(mmc);
> > +   struct mmc_command *cmd;
> > +   unsigned long flags;
> > +   bool present;
> > +
> > +   /* FIXME: check more flags? */
> > +   if (!host->mmc->flags & MMC_UHS2_SUPPORT) {
> 
> 
>   if (sdhci_uhs2_mode(host))
> 
> > +   sdhci_request(mmc, mrq);
> > +   return;
> > +   }
> > +
> > +   /* Firstly check card presence */
> > +   present = mmc->ops->get_cd(mmc);
> 
> Checking CD here is another legacy hangover.  Should be able to check the
> bus power instead. i.e. if the card has been removed, the bus power (bit-0
> Power Control reg) should get set to 0.  That can be checked under spin lock.

Replace it with check against SDHCI_POWER_ON.

> > +
> > +   spin_lock_irqsave(&host->lock, flags);
> > +
> > +   sdhci_led_activate(host);
> 
> Drop support for sdhci LEDs unless yoy are using them

Sure

> > +
> > +   if (sdhci_present_error(host, mrq->cmd, present))
> > +   goto out_finish;
> > +
> > +   cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd;
> 
> UHS2 doesn't use CMD23 does it?

I don't know. Will replace it with
cmd = mrq->sbc ? mrq->sbc : mrq->cmd;

> > +
> > +   if (!sdhci_uhs2_send_command_retry(host, cmd, flags))
> 
> Don't use sdhci_uhs2_send_command_retry.  sdhci_send_command_retry is again
> dealing with legacy hangover.  The inhibit bits should not be set.  If they
> are it can be an error immediately.  So just use sdhci_uhs2_send_commend()

Will follow your suggestion.

> > +   goto out_finish;
> > +
> > +   spin_unlock_irqrestore(&host->lock, flags);
> > +
> > +   return;
> > +
> > +out_finish:
> > +   sdhci_finish_mrq(host, mrq);
> > +   spin_unlock_irqrestore(&host->lock, flags);
> > +}
> > +EXPORT_SYMB

Re: [RFC PATCH v3.1 19/27] mmc: sdhci-uhs2: add set_reg() to initialise the interface

2020-11-30 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:18:26AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > This is a sdhci version of mmc's uhs2_set_reg operation.
> > UHS-II interface (related registers) will be initialised here.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 103 ++
> >  1 file changed, 103 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 55362ace1857..d8afb99a9918 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -332,6 +332,68 @@ static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, 
> > struct mmc_ios *ios)
> > spin_unlock_irqrestore(&host->lock, flags);
> >  }
> >  
> > +/* TODO: move this function to sdhci.c */
> > +static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 
> > set)
> > +{
> > +   u32 ier;
> > +
> > +   ier = sdhci_readl(host, SDHCI_INT_ENABLE);
> > +   ier &= ~clear;
> > +   ier |= set;
> > +   sdhci_writel(host, ier, SDHCI_INT_ENABLE);
> > +   sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
> > +}
> > +
> > +static void sdhci_uhs2_set_config(struct sdhci_host *host)
> > +{
> > +   u32 value;
> > +   u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
> > +   u16 sdhci_uhs2_gen_set_reg = (sdhci_uhs2_set_ptr + 0);
> > +   u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
> > +   u16 sdhci_uhs2_tran_set_reg = (sdhci_uhs2_set_ptr + 8);
> > +   u16 sdhci_uhs2_tran_set_1_reg = (sdhci_uhs2_set_ptr + 12);
> > +
> > +   /* Set Gen Settings */
> > +   sdhci_writel(host, host->mmc->uhs2_caps.n_lanes_set <<
> > +   SDHCI_UHS2_GEN_SET_N_LANES_POS, sdhci_uhs2_gen_set_reg);
> > +
> > +   /* Set PHY Settings */
> > +   value = (host->mmc->uhs2_caps.n_lss_dir_set <<
> > +   SDHCI_UHS2_PHY_SET_N_LSS_DIR_POS) |
> > +   (host->mmc->uhs2_caps.n_lss_sync_set <<
> > +   SDHCI_UHS2_PHY_SET_N_LSS_SYN_POS);
> > +   if (host->mmc->flags & MMC_UHS2_SPEED_B)
> > +   value |= 1 << SDHCI_UHS2_PHY_SET_SPEED_POS;
> > +   sdhci_writel(host, value, sdhci_uhs2_phy_set_reg);
> > +
> > +   /* Set LINK-TRAN Settings */
> > +   value = (host->mmc->uhs2_caps.max_retry_set <<
> > +   SDHCI_UHS2_TRAN_SET_RETRY_CNT_POS) |
> > +   (host->mmc->uhs2_caps.n_fcu_set <<
> > +   SDHCI_UHS2_TRAN_SET_N_FCU_POS);
> > +   sdhci_writel(host, value, sdhci_uhs2_tran_set_reg);
> > +   sdhci_writel(host, host->mmc->uhs2_caps.n_data_gap_set,
> > +sdhci_uhs2_tran_set_1_reg);
> > +}
> > +
> > +static int sdhci_uhs2_check_dormant(struct sdhci_host *host)
> > +{
> > +   int timeout = 100;
> > +
> > +   while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
> > +   SDHCI_UHS2_IN_DORMANT_STATE)) {
> 
> Can use read_poll_timeout(sdhci_readl,..., host, SDHCI_PRESENT_STATE)

Okay

-Takahiro Akashi

> > +   if (timeout == 0) {
> > +   pr_warn("%s: UHS2 IN_DORMANT fail in 100ms.\n",
> > +   mmc_hostname(host->mmc));
> > +   sdhci_dumpregs(host);
> > +   return -EIO;
> > +   }
> > +   timeout--;
> > +   mdelay(1);
> > +   }
> > +   return 0;
> > +}
> > +
> >  
> > /*\
> >   * 
> >   *
> >   * MMC callbacks   
> >   *
> > @@ -422,6 +484,45 @@ static void sdhci_uhs2_enable_clk(struct mmc_host *mmc)
> > }
> >  }
> >  
> > +static int sdhci_uhs2_set_reg(struct mmc_host *mmc, enum uhs2_act act)
> > +{
> > +struct sdhci_host *host = mmc_priv(mmc);
> > +   unsigned long flags;
> > +   int err = 0;
> > +   u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
> > +   u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
> > +
> > +   DBG("Begin sdhci_uhs2_set_reg, act %d.\n", act);
> > +   spin_lock_irqsave(&host->lock, flags);
> > +
> > +   switch (act) {
> > +   case SE

Re: [RFC PATCH v3.1 18/27] mmc: sdhci-uhs2: add clock operations

2020-11-30 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:17:59AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > This is a sdhci version of mmc's uhs2_[enable|disable]_clk operations.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 41 +++
> >  1 file changed, 41 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 994dff967e85..55362ace1857 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -11,6 +11,7 @@
> >   */
> >  
> >  #include 
> > +#include 
> >  #include 
> >  
> >  #include "sdhci.h"
> > @@ -385,6 +386,42 @@ void sdhci_uhs2_set_ios(struct mmc_host *mmc, struct 
> > mmc_ios *ios)
> > __sdhci_uhs2_set_ios(mmc, ios);
> >  }
> >  
> > +static void sdhci_uhs2_disable_clk(struct mmc_host *mmc)
> > +{
> > +struct sdhci_host *host = mmc_priv(mmc);
> > +   u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> > +
> > +   clk &= ~SDHCI_CLOCK_CARD_EN;
> > +   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> > +}
> > +
> > +static void sdhci_uhs2_enable_clk(struct mmc_host *mmc)
> > +{
> > +struct sdhci_host *host = mmc_priv(mmc);
> > +   u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> > +   ktime_t timeout;
> > +
> > +   clk |= SDHCI_CLOCK_CARD_EN;
> > +   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> > +
> > +   /* Wait max 20 ms */
> > +   timeout = ktime_add_ms(ktime_get(), 20);
> > +   while (1) {
> > +   bool timedout = ktime_after(ktime_get(), timeout);
> > +
> > +   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> 
> Can use read_poll_timeout(sdhci_readw,..., host, SDHCI_CLOCK_CONTROL)

Okay.

-Takahiro Akashi

> > +   if (clk & SDHCI_CLOCK_INT_STABLE)
> > +   break;
> > +   if (timedout) {
> > +   pr_err("%s: Internal clock never stabilised.\n",
> > +  mmc_hostname(host->mmc));
> > +   sdhci_dumpregs(host);
> > +   return;
> > +   }
> > +   udelay(10);
> > +   }
> > +}
> > +
> >  
> > /*\
> >   * 
> >   *
> >   * Driver init/exit
> >   *
> > @@ -556,6 +593,10 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host 
> > *host)
> >  
> > if (!host->mmc_host_ops.uhs2_detect_init)
> > host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
> > +   if (!host->mmc_host_ops.uhs2_disable_clk)
> > +   host->mmc_host_ops.uhs2_disable_clk = sdhci_uhs2_disable_clk;
> > +   if (!host->mmc_host_ops.uhs2_enable_clk)
> > +   host->mmc_host_ops.uhs2_enable_clk = sdhci_uhs2_enable_clk;
> >  
> > return 0;
> >  }
> > 
> 


Re: [RFC PATCH v3.1 17/27] mmc: sdhci-uhs2: add detect_init() to detect the interface

2020-11-30 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:17:38AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > Sdhci_uhs2_do_detect_init() is a sdhci version of mmc's uhs2_detect_init
> > operation. After detected, the host's UHS-II capabilities will be set up
> > here and interrupts will also be enabled.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 160 ++
> >  1 file changed, 160 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 637464748cc4..994dff967e85 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -391,12 +391,172 @@ void sdhci_uhs2_set_ios(struct mmc_host *mmc, struct 
> > mmc_ios *ios)
> >   * 
> >   *
> >  
> > \*/
> >  
> > +static int sdhci_uhs2_interface_detect(struct sdhci_host *host)
> > +{
> > +   int timeout = 100;
> 
> Please comment on where timeouts / delays come from. e.g. as per spec

It does exist in the original code, but I will try to find the source
of information.

> > +
> > +   udelay(200); /* wait for 200us before check */
> > +
> > +   while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
> > +   SDHCI_UHS2_IF_DETECT)) {
> 
> 
> Can be read_poll_timeout(sdhci_readl,...,host, SDHCI_PRESENT_STATE)

Okay.

> > +   if (timeout == 0) {
> > +   pr_warn("%s: not detect UHS2 interface in 200us.\n",
> > +   mmc_hostname(host->mmc));
> > +   sdhci_dumpregs(host);
> > +   return -EIO;
> > +   }
> > +   timeout--;
> > +   mdelay(1);
> > +   }
> > +
> > +   /* Enable UHS2 error interrupts */
> > +   sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
> > + SDHCI_UHS2_ERR_INT_STATUS_MASK);
> > +
> > +   timeout = 150;
> > +   while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
> > +   SDHCI_UHS2_LANE_SYNC)) {
> 
> Ditto

Okay.

-Takahiro Akashi

> 
> > +   if (timeout == 0) {
> > +   pr_warn("%s: UHS2 Lane sync fail in 150ms.\n",
> > +   mmc_hostname(host->mmc));
> > +   sdhci_dumpregs(host);
> > +   return -EIO;
> > +   }
> > +   timeout--;
> > +   mdelay(1);
> > +   }
> > +
> > +   DBG("%s: UHS2 Lane synchronized in UHS2 mode, PHY is initialized.\n",
> > +   mmc_hostname(host->mmc));
> > +   return 0;
> > +}
> > +
> > +static int sdhci_uhs2_init(struct sdhci_host *host)
> > +{
> > +   u16 caps_ptr = 0;
> > +   u32 caps_gen = 0;
> > +   u32 caps_phy = 0;
> > +   u32 caps_tran[2] = {0, 0};
> > +   struct mmc_host *mmc = host->mmc;
> > +
> > +   /*
> > +* TODO: may add corresponding members in sdhci_host to
> > +* keep these caps.
> > +*/
> > +   caps_ptr = sdhci_readw(host, SDHCI_UHS2_HOST_CAPS_PTR);
> > +   if (caps_ptr < 0x100 || caps_ptr > 0x1FF) {
> > +   pr_err("%s: SDHCI_UHS2_HOST_CAPS_PTR(%d) is wrong.\n",
> > +  mmc_hostname(mmc), caps_ptr);
> > +   return -ENODEV;
> > +   }
> > +   caps_gen = sdhci_readl(host,
> > +  caps_ptr + SDHCI_UHS2_HOST_CAPS_GEN_OFFSET);
> > +   caps_phy = sdhci_readl(host,
> > +  caps_ptr + SDHCI_UHS2_HOST_CAPS_PHY_OFFSET);
> > +   caps_tran[0] = sdhci_readl(host,
> > +  caps_ptr + SDHCI_UHS2_HOST_CAPS_TRAN_OFFSET);
> > +   caps_tran[1] = sdhci_readl(host,
> > +  caps_ptr
> > +   + SDHCI_UHS2_HOST_CAPS_TRAN_1_OFFSET);
> > +
> > +   /* General Caps */
> > +   mmc->uhs2_caps.dap = caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_DAP_MASK;
> > +   mmc->uhs2_caps.gap = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_GAP_MASK) >>
> > +SDHCI_UHS2_HOST_CAPS_GEN_GAP_SHIFT;
> > +   mmc->uhs2_caps.n_lanes = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_LANE_MASK)
> > +   >> SDHCI_UHS2_HOST_CAPS_GEN_LANE_SHIFT;
> > +   mmc->uhs2_caps.addr64 =
> > + 

Re: [RFC PATCH v3.1 16/27] mmc: sdhci-uhs2: add set_ios()

2020-11-29 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:17:11AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > This is a sdhci version of mmc's set_ios operation.
> > It covers both UHS-I and UHS-II.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 100 ++
> >  drivers/mmc/host/sdhci-uhs2.h |   1 +
> >  drivers/mmc/host/sdhci.c  |  40 +-
> >  drivers/mmc/host/sdhci.h  |   2 +
> >  4 files changed, 128 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index d9e98c097bfe..637464748cc4 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -263,6 +263,74 @@ void sdhci_uhs2_set_timeout(struct sdhci_host *host, 
> > struct mmc_command *cmd)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
> >  
> > +/**
> > + * sdhci_uhs2_clear_set_irqs - set Error Interrupt Status Enable register
> > + * @host:  SDHCI host
> > + * @clear: bit-wise clear mask
> > + * @set:   bit-wise set mask
> > + *
> > + * Set/unset bits in UHS-II Error Interrupt Status Enable register
> > + */
> > +void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
> > +{
> > +   u32 ier;
> > +
> > +   ier = sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN);
> > +   ier &= ~clear;
> > +   ier |= set;
> > +   sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_STATUS_EN);
> > +   sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_SIG_EN);
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_clear_set_irqs);
> > +
> > +static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> > +{
> > +   struct sdhci_host *host = mmc_priv(mmc);
> > +   u8 cmd_res, dead_lock;
> > +   u16 ctrl_2;
> > +   unsigned long flags;
> > +
> > +   /* FIXME: why lock? */
> > +   spin_lock_irqsave(&host->lock, flags);
> > +
> > +   /* UHS2 Timeout Control */
> > +   sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
> > +
> > +   /* change to use calculate value */
> > +   cmd_res |= dead_lock << SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT;
> > +
> > +   sdhci_uhs2_clear_set_irqs(host,
> > + SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
> > + SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT,
> > + 0);
> > +   sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
> > +   sdhci_uhs2_clear_set_irqs(host, 0,
> > + SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
> > + SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT);
> > +
> > +   /* UHS2 timing */
> > +   ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> > +   if (ios->timing == MMC_TIMING_UHS2)
> > +   ctrl_2 |= SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN;
> > +   else
> > +   ctrl_2 &= ~(SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN);
> > +   sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
> > +
> > +   if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
> > +   sdhci_enable_preset_value(host, true);
> > +
> > +   if (host->ops->set_power)
> > +   host->ops->set_power(host, ios->power_mode, ios->vdd);
> > +   else
> > +   sdhci_set_power(host, ios->power_mode, ios->vdd);
> > +   udelay(100);
> > +
> > +   host->timing = ios->timing;
> > +   sdhci_set_clock(host, host->clock);
> 
> sdhci_set_ios_common() already called ->set_clock() and ->set_power(), so I
> am not really following what is going on here.  Can you explain some more?

To be frank, I don't know. The logic in Intel's (and/or Ben's?)
original code does so.
What I changed is to remove the code of setting (ios->vdd and) ios->vdd2,
which is executed before calling set_power(), in __sdhci_uhs2_set_ios().

So yes, effectively it may be of no use to call set_power() here.

-Takahiro Akashi

> > +
> > +   spin_unlock_irqrestore(&host->lock, flags);
> > +}
> > +
> >  
> > /*\
> >   * 
> >   *
> >   * MMC callbacks   
> >   *
> > @@ -286,6 +354,37 @@ static int 
> > sdhci_uhs2_start_signal_vo

Re: [RFC PATCH v3.1 14/27] mmc: sdhci-uhs2: skip signal_voltage_switch()

2020-11-29 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:16:44AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > For UHS2, the signal voltage is supplied by vdd2 which is already 1.8v,
> > so no voltage switch required.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 26 ++
> >  1 file changed, 26 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 2bf78cc4e9ed..1eca89359351 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -178,6 +178,29 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, 
> > unsigned char mode,
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
> >  
> > +/*\
> > + * 
> >   *
> > + * MMC callbacks   
> >   *
> > + * 
> >   *
> > +\*/
> > +
> > +static int sdhci_uhs2_start_signal_voltage_switch(struct mmc_host *mmc,
> > + struct mmc_ios *ios)
> > +{
> > +   struct sdhci_host *host = mmc_priv(mmc);
> > +
> > +   /*
> > +* For UHS2, the signal voltage is supplied by vdd2 which is
> > +* already 1.8v so no voltage switch required.
> > +*/
> > +if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > + host->version >= SDHCI_SPEC_400 &&
> > + host->mmc->flags & MMC_UHS2_SUPPORT)
> 
> Could this be the same helper function suggested elsewhere i.e.
> 
>   if (!sdhci_uhs2_mode(host))


ditto. I'd defer the change until some time later.

-Takahiro Akashi

> 
> > +return 0;
> > +
> > +   return sdhci_start_signal_voltage_switch(mmc, ios);
> > +}
> > +
> >  
> > /*\
> >   * 
> >   *
> >   * Driver init/exit
> >   *
> > @@ -186,6 +209,9 @@ EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
> >  
> >  static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
> >  {
> > +   host->mmc_host_ops.start_signal_voltage_switch =
> > +   sdhci_uhs2_start_signal_voltage_switch;
> > +
> > return 0;
> >  }
> >  
> > 
> 


Re: [RFC PATCH v3.1 13/27] mmc: sdhci-uhs2: add set_power() to support vdd2

2020-11-29 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:16:27AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > This is a UHS-II version of sdhci's set_power operation.
> > VDD2, as well as VDD, is handled here.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 80 +++
> >  drivers/mmc/host/sdhci-uhs2.h |  2 +
> >  drivers/mmc/host/sdhci.c  | 58 +++--
> >  drivers/mmc/host/sdhci.h  |  2 +
> >  4 files changed, 119 insertions(+), 23 deletions(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index e2b9743fe17d..2bf78cc4e9ed 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -98,6 +98,86 @@ void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
> >  
> > +void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
> > + unsigned short vdd)
> 
> This function isn't used, so let's rename it sdhci_uhs2_set_power_noreg and
> drop regulator support.

I have no strong opinion, but here Ben might want to further rework
the new sdhci_uhs2_set_power_noreg() now that it is almost the same as
GLI's gl9755_set_power()(, adding a new quirk?).

> > +{
> > +   struct mmc_host *mmc = host->mmc;
> > +   u8 pwr;
> > +
> > +   /* FIXME: check if flags & MMC_UHS2_SUPPORT? */
> > +   if (!(host->mmc->caps & MMC_CAP_UHS2)) {
> 
> As commented in another patch, please use a helper fn

As said, I would defer this.

> > +   sdhci_set_power(host, mode, vdd);
> > +   return;
> > +   }
> > +
> > +   if (mode != MMC_POWER_OFF) {
> > +   pwr = sdhci_get_vdd_value(vdd);
> 
> Simpler to open code this esp. as there are only 2 valid values:
> 
>   switch (1 << vdd) {

Can you ignore MMC_VDD_165_195 and MMC_VDD_20_21 here?

>   case MMC_VDD_29_30..MMC_VDD_30_31:
>   pwr = SDHCI_POWER_300;
>   break;
>   case MMC_VDD_32_33..MMC_VDD_33_34:
>   pwr = SDHCI_POWER_330;
>   break;
>   default:
>   WARN(1, "%s: Invalid vdd %#x\n",
>mmc_hostname(host->mmc), vdd);
>   break;
>   }
> 
> 
> > +   if (!pwr)
> > +   WARN(1, "%s: Invalid vdd %#x\n",
> > +mmc_hostname(host->mmc), vdd);
> > +
> > +   pwr |= SDHCI_VDD2_POWER_180;
> > +   }
> > +
> > +   if (host->pwr == pwr)
> > +   return;
> > +   host ->pwr = pwr;
> > +
> > +   if (pwr == 0) {
> > +   sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
> > +
> > +   if (!IS_ERR(host->mmc->supply.vmmc))
> > +   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> > +   if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
> > +   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
> > +
> > +   if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
> 
> Please drop support for legacy quirk SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON

Okay.

> 
> > +   sdhci_runtime_pm_bus_off(host);
> > +   } else {
> > +   if (!IS_ERR(host->mmc->supply.vmmc))
> > +   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
> > +   if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
> > +   /* support 1.8v only for now */
> > +   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2,
> > + fls(MMC_VDD2_165_195) - 1);
> > +
> > +   /*
> > +* Spec says that we should clear the power reg before setting
> > +* a new value. Some controllers don't seem to like this though.
> > +*/
> > +   if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
> 
> Please drop support for legacy quirk here and several cases below.  As I
> mentioned in another patch, just put a comment somewhere listing what is
> not supported for UHS2 host controllers.

Okay.

-Takahiro Akashi

> 
> > +   sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
> > +
> > +   /*
> > +* At least the Marvell CaFe ch

Re: [RFC PATCH v3.1 12/27] mmc: sdhci-uhs2: add reset function

2020-11-29 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:16:11AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > Sdhci_uhs2_reset() does a UHS-II specific reset operation.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.c | 49 +++
> >  drivers/mmc/host/sdhci-uhs2.h |  1 +
> >  drivers/mmc/host/sdhci.c  |  3 ++-
> >  drivers/mmc/host/sdhci.h  |  1 +
> >  4 files changed, 53 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
> > index 08905ed081fb..e2b9743fe17d 100644
> > --- a/drivers/mmc/host/sdhci-uhs2.c
> > +++ b/drivers/mmc/host/sdhci-uhs2.c
> > @@ -10,6 +10,7 @@
> >   *  Author: AKASHI Takahiro 
> >   */
> >  
> > +#include 
> >  #include 
> >  
> >  #include "sdhci.h"
> > @@ -49,6 +50,54 @@ void sdhci_uhs2_dump_regs(struct sdhci_host *host)
> >  }
> >  EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
> >  
> > +/*\
> > + * 
> >   *
> > + * Low level functions 
> >   *
> > + * 
> >   *
> > +\*/
> > +
> > +/**
> > + * sdhci_uhs2_reset - invoke SW reset
> > + * @host: SDHCI host
> > + * @mask: Control mask
> > + *
> > + * Invoke SW reset, depending on a bit in @mask and wait for completion.
> > + */
> > +void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
> > +{
> > +   unsigned long timeout;
> > +
> > +   if (!(host->mmc->caps & MMC_CAP_UHS2))
> 
> Please make a helper so this can be like:
> 
>   if (!sdhci_uhs2_mode(host))
> 
> The capability will be always present for hosts that support UHS2, but not
> all cards support UHS2 mode.  I suggest just adding a bool to struct
> sdhci_host to keep track of when the host is in UHS2 mode.

Given the fact that UHS-2 host may (potentially) support a topology like
a ring, this kind of status should be attributed to a card (structure)
rather than a host.

I'm asking Ben to modify the way how the current mode be managed
in both 'core' side and 'host' side.
That is why I marked "TODO" in many places to check the mode.

So I'd defer the change until his rework be done.


> > +   return;
> > +
> > +   sdhci_writew(host, mask, SDHCI_UHS2_SW_RESET);
> > +
> > +   if (mask & SDHCI_UHS2_SW_RESET_FULL) {
> > +   host->clock = 0;
> > +   /* Reset-all turns off SD Bus Power */
> > +   if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
> 
> I would prefer not to support any legacy quirks that we do not need right
> now.  Just be sure to add a comment somewhere listing which quirks are not
> supported for UHS2 host controllers.

No strong opinion. I'd defer to you.

> > +   sdhci_runtime_pm_bus_off(host);
> > +   }
> > +
> > +   /* Wait max 100 ms */
> > +   timeout = 1;
> > +
> > +   /* hw clears the bit when it's done */
> > +   while (sdhci_readw(host, SDHCI_UHS2_SW_RESET) & mask) {
> 
> This kind of loop can now be done with read_poll_timeout_atomic(sdhci_readw,
> ..., host, SDHCI_UHS2_SW_RESET)

Okay.

-Takahiro Akashi

> > +   if (timeout == 0) {
> > +   pr_err("%s: %s: Reset 0x%x never completed.\n",
> > +  __func__, mmc_hostname(host->mmc), (int)mask);
> > +   pr_err("%s: clean reset bit\n",
> > +  mmc_hostname(host->mmc));
> > +   sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET);
> > +   return;
> > +   }
> > +   timeout--;
> > +   udelay(10);
> > +   }
> > +}
> > +EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
> > +
> >  
> > /*\
> >   * 
> >   *
> >   * Driver init/exit
> >   *
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > index b9529d32b58d..7bb7a0d67109 100644
> > --- 

Re: [RFC PATCH v3.1 09/27] mmc: sdhci: add UHS-II related definitions in headers

2020-11-29 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:15:29AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > Add UHS-II related definitions in shdci.h and sdhci-uhs2.h.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.h | 210 ++
> >  drivers/mmc/host/sdhci.h  |  73 +++-
> >  2 files changed, 282 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/mmc/host/sdhci-uhs2.h
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > new file mode 100644
> > index ..3b157df9c89c
> > --- /dev/null
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -0,0 +1,210 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + *  linux/drivers/mmc/host/sdhci-uhs2.h - Secure Digital Host Controller
> > + *  Interface driver
> > + *
> > + * Header file for Host Controller UHS2 related registers and I/O 
> > accessors.
> > + *
> > + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> > + */
> > +#ifndef __SDHCI_UHS2_H
> > +#define __SDHCI_UHS2_H
> > +
> > +#include 
> > +
> > +/*
> > + * UHS-II Controller registers
> > + * 0x74 preset in sdhci.h
> > + * 0x80
> > + * 0x84-0xB4
> > + * 0xB8-0xCF
> > + * 0xE0-0xE7
> > + */
> > +/* UHS2 */
> > +#define SDHCI_UHS2_BLOCK_SIZE  0x80
> > +#define  SDHCI_UHS2_MAKE_BLKSZ(dma, blksz) \
> > +   dma) & 0x7) << 12) | ((blksz) & 0xFFF))
> > +
> > +#define SDHCI_UHS2_BLOCK_COUNT 0x84
> > +
> > +#define SDHCI_UHS2_CMD_PACKET  0x88
> > +#define  SDHCI_UHS2_CMD_PACK_MAX_LEN   20
> > +
> > +#define SDHCI_UHS2_TRANS_MODE  0x9C
> > +#define  SDHCI_UHS2_TRNS_DMA   BIT(0)
> > +#define  SDHCI_UHS2_TRNS_BLK_CNT_ENBIT(1)
> > +#define  SDHCI_UHS2_TRNS_DATA_TRNS_WRT BIT(4)
> > +#define  SDHCI_UHS2_TRNS_BLK_BYTE_MODE BIT(5)
> > +#define  SDHCI_UHS2_TRNS_RES_R5BIT(6)
> > +#define  SDHCI_UHS2_TRNS_RES_ERR_CHECK_EN  BIT(7)
> > +#define  SDHCI_UHS2_TRNS_RES_INT_DIS   BIT(8)
> > +#define  SDHCI_UHS2_TRNS_WAIT_EBSY BIT(14)
> > +#define  SDHCI_UHS2_TRNS_2L_HD BIT(15)
> > +
> > +#define SDHCI_UHS2_COMMAND 0x9E
> > +#define  SDHCI_UHS2_COMMAND_SUB_CMD0x0004
> > +#define  SDHCI_UHS2_COMMAND_DATA   0x0020
> > +#define  SDHCI_UHS2_COMMAND_TRNS_ABORT 0x0040
> > +#define  SDHCI_UHS2_COMMAND_CMD12  0x0080
> > +#define  SDHCI_UHS2_COMMAND_DORMANT0x00C0
> > +#define  SDHCI_UHS2_COMMAND_PACK_LEN_MASK  GENMASK(12,8)
> > +#define  SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT 8
> > +
> > +#define SDHCI_UHS2_RESPONSE0xA0
> > +#define  SDHCI_UHS2_RESPONSE_MAX_LEN   20
> > +
> > +#define SDHCI_UHS2_MSG_SELECT  0xB4
> > +#define SDHCI_UHS2_MSG_SELECT_CURR 0x0
> > +#define SDHCI_UHS2_MSG_SELECT_ONE  0x1
> > +#define SDHCI_UHS2_MSG_SELECT_TWO  0x2
> > +#define SDHCI_UHS2_MSG_SELECT_THREE0x3
> > +
> > +#define SDHCI_UHS2_MSG 0xB8
> > +
> > +#define SDHCI_UHS2_DEV_INT_STATUS  0xBC
> > +
> > +#define SDHCI_UHS2_DEV_SELECT  0xBE
> > +#define SDHCI_UHS2_DEV_SELECT_DEV_SEL_MASK GENMASK(3,0)
> > +#define SDHCI_UHS2_DEV_SELECT_INT_MSG_EN   BIT(7)
> > +
> > +#define SDHCI_UHS2_DEV_INT_CODE0xBF
> > +
> > +#define SDHCI_UHS2_SW_RESET0xC0
> > +#define SDHCI_UHS2_SW_RESET_FULL   0x0001
> > +#define SDHCI_UHS2_SW_RESET_SD 0x0002
> > +
> > +#define SDHCI_UHS2_TIMER_CTRL  0xC2
> > +#define SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT   4
> > +
> > +#define SDHCI_UHS2_ERR_INT_STATUS  0xC4
> > +#define SDHCI_UHS2_ERR_INT_STATUS_EN   0xC8
> > +#define SDHCI_UHS2_ERR_INT_SIG_EN  0xCC
> > +#define SDHCI_UHS2_ERR_INT_STATUS_HEADER   BIT(0)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_RES  BIT(1)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXPBIT(2)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_CRC  BIT(3)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_FRAMEBIT(4)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_TID  BIT(5)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_UNRECOVERBIT(7)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_EBUSYBIT(8)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_ADMA BIT(15)
> > +#define SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT  BIT(16)
> > +#def

Re: [RFC PATCH v3.1 08/27] mmc: sdhci: add a kernel configuration for enabling UHS-II support

2020-11-29 Thread AKASHI Takahiro
On Thu, Nov 26, 2020 at 10:14:36AM +0200, Adrian Hunter wrote:
> On 6/11/20 4:27 am, AKASHI Takahiro wrote:
> > This kernel configuration, CONFIG_MMC_SDHCI_UHS2, will be used
> > in the following commits to indicate UHS-II specific code in sdhci
> > controllers.
> 
> This patch needs to be combined with a patch that actually uses the config.

Earlier is better. So the patch #10/27 would be the best.

-Takahiro Akashi

> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/Kconfig | 9 +
> >  1 file changed, 9 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> > index 31481c9fcc2e..5ca9ac03db40 100644
> > --- a/drivers/mmc/host/Kconfig
> > +++ b/drivers/mmc/host/Kconfig
> > @@ -89,6 +89,15 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
> >  
> >   This is the case for the Nintendo Wii SDHCI.
> >  
> > +config MMC_SDHCI_UHS2
> > +   tristate "UHS2 support on SDHCI controller"
> > +   depends on MMC_SDHCI
> > +   help
> > + This option is selected by SDHCI controller drivers that want to
> > + support UHS2-capable devices.
> > +
> > + If you have a controller with this feature, say Y or M here.
> > +
> >  config MMC_SDHCI_PCI
> > tristate "SDHCI support on PCI bus"
> > depends on MMC_SDHCI && PCI
> > 
> 


Re: [RFC PATCH v3.1 00/27] Add support UHS-II for GL9755

2020-11-25 Thread AKASHI Takahiro
On Wed, Nov 25, 2020 at 11:43:18AM +0100, Ulf Hansson wrote:
> On Wed, 25 Nov 2020 at 08:41, AKASHI Takahiro
>  wrote:
> >
> > Gentle ping;
> >
> > On Fri, Nov 06, 2020 at 11:26:59AM +0900, AKASHI Takahiro wrote:
> > > This is an interim snapshot of our next version, v4, for enabling
> > > UHS-II on MMC/SD.
> > >
> > > It is focused on 'sdhci' side to address Adrian's comments regarding
> > > "modularising" sdhci-uhs2.c.
> > > The whole aim of this version is to get early feedback from Adrian (and
> > > others) on this issue. Without any consensus about the code structure,
> >
> > Any comments so far?
> 
> I haven't been able to look at sdhci parts (I will try to), but as you
> know, I am relying on Adrian's help with this.

Yeah, I understand.

> When it comes to the core part, I am planning to help to put some of
> the foundation in place for the mmc core changes. Although,
> unfortunately I haven't been able to post patches, yet. I will keep
> you in the loop, when I get to it.

I think Ben has some idea on the topic.

-Takahiro Akashi


> [...]
> 
> Kind regards
> Uffe


Re: [RFC PATCH v3.1 00/27] Add support UHS-II for GL9755

2020-11-24 Thread AKASHI Takahiro
Gentle ping;

On Fri, Nov 06, 2020 at 11:26:59AM +0900, AKASHI Takahiro wrote:
> This is an interim snapshot of our next version, v4, for enabling
> UHS-II on MMC/SD.
> 
> It is focused on 'sdhci' side to address Adrian's comments regarding
> "modularising" sdhci-uhs2.c.
> The whole aim of this version is to get early feedback from Adrian (and
> others) on this issue. Without any consensus about the code structure,

Any comments so far?

-Takahiro Akashi

> it would make little sense to go further ahead on sdhci side.
> (Actually, Adrian has made no comments other than "modularising" so far.)
> 
> I heavily reworked/refactored sdhci-uhs2.c and re-organised the patch
> set to meet what I believe Adrian expects; no UHS-II related code in
> Legacy (UHS-I) code or sdhci.c.
> 
> Nevertheless, almost of all changes I made are trivial and straightforward
> in this direction, and I believe that there is no logic changed since v3
> except sdhci_uhs2_irq(), as ops->irq hook, where we must deal with UHS-II
> command sequences in addition to UHS-II errors. So I added extra handlings.
> 
> I admit that there is plenty of room for improvements (for example,
> handling host->flags), but again the focal point here is how sdhci-uhs2.c
> should be built as a module.
> 
> Please review this series (particularly Patch#8-#26 and #27) from this
> viewpoint in the first place.
> (Ben is working on 'host' side but there is no change on 'host' side
> in this submission except a minor tweak.)
> 
> Thanks,
> -Takahiro Akashi
> 
> -- original cover letter from v3 --
> Summary
> ===
> These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.
> 
> About UHS-II, roughly deal with the following three parts:
> 1) A UHS-II detection and initialization:
> - Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
>   [2]).
> - Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
> - In step(9) of Section 3.13.2 in [2], UHS-II initialization is include 
> Section
>   3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
>   Setup Sequence.
> 
> 2) Send Legacy SD command through SD-TRAN
> - Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
>   compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
>   Types and Format Overview[3]).
> - Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
>   CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).
> 
> 3) UHS-II Interrupt
> - Except for UHS-II error interrupts, most interrupts share the original
>   interrupt registers.
> 
> Patch structure
> ===
> patch#1-#7: for core
> patch#8-#17: for sdhci
> patch#18-#21: for GL9755
> 
> Tests
> =
> Ran 'dd' command to evaluate the performance:
> (SanDisk UHS-II card on GL9755 controller)
>  ReadWrite
> UHS-II disabled (UHS-I): 88.3MB/s 60.7MB/s
> UHS-II enabled :  206MB/s   80MB/s
> 
> TODO
> 
> - replace some define with BIT macro
> 
> Reference
> =
> [1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
> [2] SD Host Controller Simplified Specification 4.20
> [3] UHS-II Simplified Addendum 1.02
> 
> Changes in v3 (Jul. 10, 2020)
> * rebased to v5.8-rc4
> * add copyright notice
> * reorganize the patch set and split some commits into smaller ones
> * separate uhs-2 headers from others
> * correct wrong spellings
> * fix most of checkpatch warnings/errors
> * remove all k[cz]alloc() from the code
> * guard sdhci-uhs2 specific code with
>   'if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))'
> * make sdhci-uhs2.c as a module
> * trivial changes, including
>   - rename back sdhci-core.c to sdhci.c
>   - allow vendor code to disable uhs2 if v4_mode == 0
>   in __sdhci_add_host()
>   - merge uhs2_power_up() into mmc_power_up()
>   - remove flag_uhs2 from mmc_attach_sd()
>   - add function descriptions to EXPORT'ed functions
>   - other minor code optimization
> 
> Changes in v2 (Jan. 9, 2020)
> * rebased to v5.5-rc5
> 
> AKASHI Takahiro (23):
>   mmc: core: UHS-II support, modify power-up sequence
>   mmc: core: UHS-II support, skip set_chip_select()
>   mmc: core: UHS-II support, skip TMODE setup in some cases
>   mmc: core: UHS-II support, generate UHS-II SD command packet
>   mmc: core: UHS-II support, set APP_CMD bit if necessary
>   mmc: sdhci: add a kernel configuration for enabling UHS-II support
>   mmc: sdhci: add UHS-II related definitions in headers
>   mmc: sdhci: add UHS-II module
>   mmc: sdhci

[RFC PATCH v3.1 06/27] mmc: core: UHS-II support, generate UHS-II SD command packet

2020-11-05 Thread AKASHI Takahiro
In SD-TRAN protocol, legacy SD commands should be "encapsulated" in SD
packets as described in SD specification.
Please see section 7.1 and 7.2.1 in "UHS-II Simplified Addendum."

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/core.c | 18 +++
 drivers/mmc/core/uhs2.c | 70 +
 drivers/mmc/core/uhs2.h |  1 +
 3 files changed, 89 insertions(+)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index a08cb1c0f6d2..ac43e93033e6 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -337,6 +337,8 @@ static int mmc_mrq_prep(struct mmc_host *host, struct 
mmc_request *mrq)
 
 int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 {
+   struct uhs2_command uhs2_cmd;
+   u32 payload[4]; /* for maximum size */
int err;
 
init_completion(&mrq->cmd_completion);
@@ -354,6 +356,13 @@ int mmc_start_request(struct mmc_host *host, struct 
mmc_request *mrq)
if (err)
return err;
 
+   if (host->flags & MMC_UHS2_SUPPORT &&
+   host->flags & MMC_UHS2_INITIALIZED) {
+   uhs2_cmd.payload = payload;
+   mrq->cmd->uhs2_cmd = &uhs2_cmd;
+   uhs2_prepare_sd_cmd(host, mrq);
+   }
+
led_trigger_event(host->led, LED_FULL);
__mmc_start_request(host, mrq);
 
@@ -433,6 +442,8 @@ EXPORT_SYMBOL(mmc_wait_for_req_done);
  */
 int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
+   struct uhs2_command uhs2_cmd;
+   u32 payload[4]; /* for maximum size */
int err;
 
/*
@@ -453,6 +464,13 @@ int mmc_cqe_start_req(struct mmc_host *host, struct 
mmc_request *mrq)
if (err)
goto out_err;
 
+   if (host->flags & MMC_UHS2_SUPPORT &&
+   host->flags & MMC_UHS2_INITIALIZED) {
+   uhs2_cmd.payload = payload;
+   mrq->cmd->uhs2_cmd = &uhs2_cmd;
+   uhs2_prepare_sd_cmd(host, mrq);
+   }
+
err = host->cqe_ops->cqe_request(host, mrq);
if (err)
goto out_err;
diff --git a/drivers/mmc/core/uhs2.c b/drivers/mmc/core/uhs2.c
index acb46b5b57ef..1f6d0e0cf355 100644
--- a/drivers/mmc/core/uhs2.c
+++ b/drivers/mmc/core/uhs2.c
@@ -807,3 +807,73 @@ int mmc_uhs2_rescan_try_freq(struct mmc_host *host, 
unsigned int freq)
return err;
 }
 EXPORT_SYMBOL_GPL(mmc_uhs2_rescan_try_freq);
+
+/**
+ * uhs2_prepare_sd_cmd - prepare for SD command packet
+ * @host:  MMC host
+ * @mrq:   MMC request
+ *
+ * Initialize and fill in a header and a payload of SD command packet.
+ * The caller should allocate uhs2_command in host->cmd->uhs2_cmd in
+ * advance.
+ *
+ * Return: 0 on success, non-zero error on failure
+ */
+int uhs2_prepare_sd_cmd(struct mmc_host *host, struct mmc_request *mrq)
+{
+   struct mmc_command *cmd;
+   struct uhs2_command *uhs2_cmd;
+   u16 header = 0, arg = 0;
+   u32 *payload;
+   u8 plen = 0;
+
+   cmd = mrq->cmd;
+   header = host->uhs2_dev_prop.node_id;
+   if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC)
+   header |= UHS2_PACKET_TYPE_DCMD;
+   else
+   header |= UHS2_PACKET_TYPE_CCMD;
+
+   arg = cmd->opcode << UHS2_SD_CMD_INDEX_POS;
+
+   uhs2_cmd = cmd->uhs2_cmd;
+   payload = uhs2_cmd->payload;
+   plen = 2; /* at the maximum */
+
+   if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC &&
+   !cmd->uhs2_tmode0_flag) {
+   if (host->flags & MMC_UHS2_2L_HD)
+   arg |= UHS2_DCMD_2L_HD_MODE;
+
+   arg |= UHS2_DCMD_LM_TLEN_EXIST;
+
+   if (cmd->data->blocks == 1 &&
+   cmd->data->blksz != 512 &&
+   cmd->opcode != MMC_READ_SINGLE_BLOCK &&
+   cmd->opcode != MMC_WRITE_BLOCK) {
+   arg |= UHS2_DCMD_TLUM_BYTE_MODE;
+   payload[1] = uhs2_dcmd_convert_msb(cmd->data->blksz);
+   } else {
+   payload[1] = uhs2_dcmd_convert_msb(cmd->data->blocks);
+   }
+
+   if (cmd->opcode == SD_IO_RW_EXTENDED) {
+   arg &= ~(UHS2_DCMD_LM_TLEN_EXIST |
+   UHS2_DCMD_TLUM_BYTE_MODE |
+   UHS2_NATIVE_DCMD_DAM_IO);
+   payload[1] = 0;
+   plen = 1;
+   }
+   } else {
+   plen = 1;
+   }
+
+   payload[0] = uhs2_dcmd_convert_msb(cmd->arg);
+   pr_debug("%s: %s: sd_cmd->arg = 0x%x, payload[0]= 0x%x.\n",
+mmc_hostname(host), __func__, cmd->arg, payload[0]);
+
+   uhs2_cmd_assemble(cmd, uhs2_cmd, h

[RFC PATCH v3.1 21/27] mmc: sdhci-uhs2: add irq() and others

2020-11-05 Thread AKASHI Takahiro
This is a UHS-II version of sdhci's request() operation.
It handles UHS-II related command interrupts and errors.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 247 ++
 drivers/mmc/host/sdhci-uhs2.h |   3 +
 drivers/mmc/host/sdhci.c  | 112 ---
 drivers/mmc/host/sdhci.h  |   6 +
 4 files changed, 319 insertions(+), 49 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 36e52553977a..d50134e912f3 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -11,6 +11,7 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -670,6 +671,12 @@ static inline void sdhci_external_dma_pre_transfer(struct 
sdhci_host *host,
   struct mmc_command *cmd)
 {
 }
+
+static inline struct dma_chan *sdhci_external_dma_channel(struct sdhci_host 
*host,
+ struct mmc_data *data)
+{
+   return NULL;
+}
 #endif /* CONFIG_MMC_SDHCI_EXTERNAL_DMA */
 
 static void sdhci_uhs2_finish_data(struct sdhci_host *host)
@@ -1051,6 +1058,246 @@ static void sdhci_uhs2_finish_command(struct sdhci_host 
*host)
}
 }
 
+/*\
+ *   *
+ * Request done  *
+ *   *
+\*/
+
+static bool sdhci_uhs2_request_done(struct sdhci_host *host)
+{
+   unsigned long flags;
+   struct mmc_request *mrq;
+   int i;
+
+   /* FIXME: UHS2_INITIALIZED, instead? */
+   if (!(host->mmc->flags & MMC_UHS2_SUPPORT))
+   return sdhci_request_done(host);
+
+   spin_lock_irqsave(&host->lock, flags);
+
+   for (i = 0; i < SDHCI_MAX_MRQS; i++) {
+   mrq = host->mrqs_done[i];
+   if (mrq)
+   break;
+   }
+
+   if (!mrq) {
+   spin_unlock_irqrestore(&host->lock, flags);
+   return true;
+   }
+
+   /*
+* Always unmap the data buffers if they were mapped by
+* sdhci_prepare_data() whenever we finish with a request.
+* This avoids leaking DMA mappings on error.
+*/
+   if (host->flags & SDHCI_REQ_USE_DMA) {
+   struct mmc_data *data = mrq->data;
+
+   if (host->use_external_dma && data &&
+   (mrq->cmd->error || data->error)) {
+   struct dma_chan *chan = 
sdhci_external_dma_channel(host, data);
+
+   host->mrqs_done[i] = NULL;
+   spin_unlock_irqrestore(&host->lock, flags);
+   dmaengine_terminate_sync(chan);
+   spin_lock_irqsave(&host->lock, flags);
+   sdhci_set_mrq_done(host, mrq);
+   }
+
+   sdhci_request_done_dma(host, mrq);
+   }
+
+   /*
+* The controller needs a reset of internal state machines
+* upon error conditions.
+*/
+   if (sdhci_needs_reset(host, mrq)) {
+   /*
+* Do not finish until command and data lines are available for
+* reset. Note there can only be one other mrq, so it cannot
+* also be in mrqs_done, otherwise host->cmd and host->data_cmd
+* would both be null.
+*/
+   if (host->cmd || host->data_cmd) {
+   spin_unlock_irqrestore(&host->lock, flags);
+   return true;
+   }
+
+   /* Some controllers need this kick or reset won't work here */
+   if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
+   /* This is to force an update */
+   host->ops->set_clock(host, host->clock);
+
+   sdhci_uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD);
+   host->pending_reset = false;
+   }
+
+   host->mrqs_done[i] = NULL;
+
+   spin_unlock_irqrestore(&host->lock, flags);
+
+   if (host->ops->request_done)
+   host->ops->request_done(host, mrq);
+   else
+   mmc_request_done(host->mmc, mrq);
+
+   return false;
+}
+
+static void sdhci_uhs2_complete_work(struct work_struct *work)
+{
+   struct sdhci_host *host = container_of(work, struct sdhci_host,
+  complete_work);
+
+   while (!sdhci_uhs2_request_done(host))
+   ;
+}
+
+/***

[RFC PATCH v3.1 13/27] mmc: sdhci-uhs2: add set_power() to support vdd2

2020-11-05 Thread AKASHI Takahiro
This is a UHS-II version of sdhci's set_power operation.
VDD2, as well as VDD, is handled here.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 80 +++
 drivers/mmc/host/sdhci-uhs2.h |  2 +
 drivers/mmc/host/sdhci.c  | 58 +++--
 drivers/mmc/host/sdhci.h  |  2 +
 4 files changed, 119 insertions(+), 23 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index e2b9743fe17d..2bf78cc4e9ed 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -98,6 +98,86 @@ void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
 
+void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
+ unsigned short vdd)
+{
+   struct mmc_host *mmc = host->mmc;
+   u8 pwr;
+
+   /* FIXME: check if flags & MMC_UHS2_SUPPORT? */
+   if (!(host->mmc->caps & MMC_CAP_UHS2)) {
+   sdhci_set_power(host, mode, vdd);
+   return;
+   }
+
+   if (mode != MMC_POWER_OFF) {
+   pwr = sdhci_get_vdd_value(vdd);
+   if (!pwr)
+   WARN(1, "%s: Invalid vdd %#x\n",
+mmc_hostname(host->mmc), vdd);
+
+   pwr |= SDHCI_VDD2_POWER_180;
+   }
+
+   if (host->pwr == pwr)
+   return;
+   host ->pwr = pwr;
+
+   if (pwr == 0) {
+   sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+
+   if (!IS_ERR(host->mmc->supply.vmmc))
+   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+   if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
+   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
+
+   if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+   sdhci_runtime_pm_bus_off(host);
+   } else {
+   if (!IS_ERR(host->mmc->supply.vmmc))
+   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+   if (!IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
+   /* support 1.8v only for now */
+   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2,
+ fls(MMC_VDD2_165_195) - 1);
+
+   /*
+* Spec says that we should clear the power reg before setting
+* a new value. Some controllers don't seem to like this though.
+*/
+   if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+   sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+
+   /*
+* At least the Marvell CaFe chip gets confused if we set the
+* voltage and set turn on power at the same time, so set the
+* voltage first.
+*/
+   if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
+   sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+   /* vdd first */
+   pwr |= SDHCI_POWER_ON;
+   sdhci_writeb(host, pwr & 0xf, SDHCI_POWER_CONTROL);
+   mdelay(5);
+
+   pwr |= SDHCI_VDD2_POWER_ON;
+   sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+   mdelay(5);
+
+   if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+   sdhci_runtime_pm_bus_on(host);
+
+   /*
+* Some controllers need an extra 10ms delay of 10ms before
+* they can apply clock after applying power
+*/
+   if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
+   mdelay(10);
+   }
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
+
 /*\
  *   *
  * Driver init/exit  *
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index 7bb7a0d67109..3c19d8e44c36 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -211,5 +211,7 @@ struct sdhci_host;
 
 void sdhci_uhs2_dump_regs(struct sdhci_host *host);
 void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
+void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
+ unsigned short vdd);
 
 #endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index af336bdb4305..0b741eb546cb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -187,13 +187,14 @@ static void sdhci_disable_card_detection(struct 
sdhci_host *host)
sdhci_set_card_detection(host, false);

[RFC PATCH v3.1 18/27] mmc: sdhci-uhs2: add clock operations

2020-11-05 Thread AKASHI Takahiro
This is a sdhci version of mmc's uhs2_[enable|disable]_clk operations.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 41 +++
 1 file changed, 41 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 994dff967e85..55362ace1857 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -11,6 +11,7 @@
  */
 
 #include 
+#include 
 #include 
 
 #include "sdhci.h"
@@ -385,6 +386,42 @@ void sdhci_uhs2_set_ios(struct mmc_host *mmc, struct 
mmc_ios *ios)
__sdhci_uhs2_set_ios(mmc, ios);
 }
 
+static void sdhci_uhs2_disable_clk(struct mmc_host *mmc)
+{
+struct sdhci_host *host = mmc_priv(mmc);
+   u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+
+   clk &= ~SDHCI_CLOCK_CARD_EN;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+}
+
+static void sdhci_uhs2_enable_clk(struct mmc_host *mmc)
+{
+struct sdhci_host *host = mmc_priv(mmc);
+   u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+   ktime_t timeout;
+
+   clk |= SDHCI_CLOCK_CARD_EN;
+   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+   /* Wait max 20 ms */
+   timeout = ktime_add_ms(ktime_get(), 20);
+   while (1) {
+   bool timedout = ktime_after(ktime_get(), timeout);
+
+   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+   if (clk & SDHCI_CLOCK_INT_STABLE)
+   break;
+   if (timedout) {
+   pr_err("%s: Internal clock never stabilised.\n",
+  mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return;
+   }
+   udelay(10);
+   }
+}
+
 /*\
  *   *
  * Driver init/exit  *
@@ -556,6 +593,10 @@ static int sdhci_uhs2_host_ops_init(struct sdhci_host 
*host)
 
if (!host->mmc_host_ops.uhs2_detect_init)
host->mmc_host_ops.uhs2_detect_init = sdhci_uhs2_do_detect_init;
+   if (!host->mmc_host_ops.uhs2_disable_clk)
+   host->mmc_host_ops.uhs2_disable_clk = sdhci_uhs2_disable_clk;
+   if (!host->mmc_host_ops.uhs2_enable_clk)
+   host->mmc_host_ops.uhs2_enable_clk = sdhci_uhs2_enable_clk;
 
return 0;
 }
-- 
2.28.0



[RFC PATCH v3.1 23/27] mmc: sdhci-uhs2: add pre-detect_init hook

2020-11-05 Thread AKASHI Takahiro
From: Ben Chuang 

This "pre" hook for detect_init(), uhs2_pre_detect_init, will be required
to enable UHS-II support, at least, on GL9755.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 3 +++
 drivers/mmc/host/sdhci.h  | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 5d3362ea138f..3dd81c89d8f1 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -1631,6 +1631,9 @@ static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc)
DBG("%s: begin UHS2 init.\n", __func__);
spin_lock_irqsave(&host->lock, flags);
 
+   if (host->ops && host->ops->uhs2_pre_detect_init)
+   host->ops->uhs2_pre_detect_init(host);
+
if (sdhci_uhs2_interface_detect(host)) {
pr_warn("%s: cannot detect UHS2 interface.\n",
mmc_hostname(host->mmc));
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index b1d856664b58..4e2cb73a63bd 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -723,6 +723,7 @@ struct sdhci_ops {
struct mmc_request *mrq);
void(*dump_vendor_regs)(struct sdhci_host *host);
void(*dump_uhs2_regs)(struct sdhci_host *host);
+   void(*uhs2_pre_detect_init)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-- 
2.28.0



[RFC PATCH v3.1 11/27] mmc: sdhci-uhs2: dump UHS-II registers

2020-11-05 Thread AKASHI Takahiro
Dump UHS-II specific registers, if available, in sdhci_dumpregs()
for informative/debugging use.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 30 ++
 drivers/mmc/host/sdhci-uhs2.h |  4 
 drivers/mmc/host/sdhci.c  |  3 +++
 3 files changed, 37 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index f29d3a4ed43c..08905ed081fb 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -18,6 +18,36 @@
 #define DRIVER_NAME "sdhci_uhs2"
 #define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
+#define SDHCI_UHS2_DUMP(f, x...) \
+   pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
+
+void sdhci_uhs2_dump_regs(struct sdhci_host *host)
+{
+   if (!host->mmc || !(host->mmc->flags & MMC_UHS2_SUPPORT))
+   return;
+
+   SDHCI_UHS2_DUMP(" UHS2 ==\n");
+   SDHCI_UHS2_DUMP("Blk Size:  0x%08x | Blk Cnt:  0x%08x\n",
+   sdhci_readw(host, SDHCI_UHS2_BLOCK_SIZE),
+   sdhci_readl(host, SDHCI_UHS2_BLOCK_COUNT));
+   SDHCI_UHS2_DUMP("Cmd:   0x%08x | Trn mode: 0x%08x\n",
+   sdhci_readw(host, SDHCI_UHS2_COMMAND),
+   sdhci_readw(host, SDHCI_UHS2_TRANS_MODE));
+   SDHCI_UHS2_DUMP("Int Stat:  0x%08x | Dev Sel : 0x%08x\n",
+   sdhci_readw(host, SDHCI_UHS2_DEV_INT_STATUS),
+   sdhci_readb(host, SDHCI_UHS2_DEV_SELECT));
+   SDHCI_UHS2_DUMP("Dev Int Code:  0x%08x\n",
+   sdhci_readb(host, SDHCI_UHS2_DEV_INT_CODE));
+   SDHCI_UHS2_DUMP("Reset: 0x%08x | Timer:0x%08x\n",
+   sdhci_readw(host, SDHCI_UHS2_SW_RESET),
+   sdhci_readw(host, SDHCI_UHS2_TIMER_CTRL));
+   SDHCI_UHS2_DUMP("ErrInt:0x%08x | ErrIntEn: 0x%08x\n",
+   sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS),
+   sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN));
+   SDHCI_UHS2_DUMP("ErrSigEn:  0x%08x\n",
+   sdhci_readl(host, SDHCI_UHS2_ERR_INT_SIG_EN));
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
 
 /*\
  *   *
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index 3b157df9c89c..b9529d32b58d 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -207,4 +207,8 @@
 #define SDHCI_UHS2_EMBED_CTRL  0xE6
 #define SDHCI_UHS2_VENDOR  0xE8
 
+struct sdhci_host;
+
+void sdhci_uhs2_dump_regs(struct sdhci_host *host);
+
 #endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 592a55a34b58..d4a57e8c9bb8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -111,6 +111,9 @@ void sdhci_dumpregs(struct sdhci_host *host)
}
}
 
+   if (host->ops->dump_uhs2_regs)
+   host->ops->dump_uhs2_regs(host);
+
if (host->ops->dump_vendor_regs)
host->ops->dump_vendor_regs(host);
 
-- 
2.28.0



[RFC PATCH v3.1 25/27] mmc: sdhci-uhs2: add post-mmc_attach_sd hook

2020-11-05 Thread AKASHI Takahiro
From: Ben Chuang 

This "post" hook for mmc_attach_sd(), uhs2_post_attach_sd, will be required
to enable UHS-II support, at least, on GL9755.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 4e2cb73a63bd..b85d9d077c61 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -724,6 +724,7 @@ struct sdhci_ops {
void(*dump_vendor_regs)(struct sdhci_host *host);
void(*dump_uhs2_regs)(struct sdhci_host *host);
void(*uhs2_pre_detect_init)(struct sdhci_host *host);
+   void(*uhs2_post_attach_sd)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-- 
2.28.0



[RFC PATCH v3.1 27/27] mmc: sdhci-pci-gli: enable UHS-II mode for GL9755

2020-11-05 Thread AKASHI Takahiro
Changes are:
* Disable GL9755 overcurrent interrupt when power on/off on UHS-II.
* Enable the internal clock when do reset on UHS-II mode.
* Set ZC to 0x0 for Sandisk cards and set ZC to 0xB for others.
* Increase timeout value before detecting UHS-II interface.
* Add vendor settings fro UHS-II mode.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/Kconfig |   1 +
 drivers/mmc/host/sdhci-pci-gli.c | 318 ++-
 2 files changed, 318 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5ca9ac03db40..cef033dd02ce 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -102,6 +102,7 @@ config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus"
depends on MMC_SDHCI && PCI
select MMC_CQHCI
+   select MMC_SDHCI_UHS2
select IOSF_MBI if X86
select MMC_SDHCI_IO_ACCESSORS
help
diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c
index 9887485a4134..dad465800446 100644
--- a/drivers/mmc/host/sdhci-pci-gli.c
+++ b/drivers/mmc/host/sdhci-pci-gli.c
@@ -14,6 +14,7 @@
 #include 
 #include "sdhci.h"
 #include "sdhci-pci.h"
+#include "sdhci-uhs2.h"
 #include "cqhci.h"
 
 /*  Genesys Logic extra registers */
@@ -72,6 +73,42 @@
 #define   SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLYGENMASK(2, 0)
 #define   GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE0x1
 
+#define PCI_GLI_9755_WT   0x800
+#define   PCI_GLI_9755_WT_ENBIT(0)
+#define   GLI_9755_WT_EN_ON0x1
+#define   GLI_9755_WT_EN_OFF0x0
+
+#define PCI_GLI_9755_PLLSSC 0x68
+#define   PCI_GLI_9755_PLLSSC_RTL BIT(24)
+#define   GLI_9755_PLLSSC_RTL_VALUE   0x1
+#define   PCI_GLI_9755_PLLSSC_TRANS_PASS  BIT(27)
+#define   GLI_9755_PLLSSC_TRANS_PASS_VALUE0x1
+#define   PCI_GLI_9755_PLLSSC_RECVGENMASK(29, 28)
+#define   GLI_9755_PLLSSC_RECV_VALUE  0x3
+#define   PCI_GLI_9755_PLLSSC_TRANGENMASK(31, 30)
+#define   GLI_9755_PLLSSC_TRAN_VALUE  0x3
+
+#define PCI_GLI_9755_UHS2_PLL0x6C
+#define   PCI_GLI_9755_UHS2_PLL_SSCGENMASK(9, 8)
+#define   GLI_9755_UHS2_PLL_SSC_VALUE  0x0
+#define   PCI_GLI_9755_UHS2_PLL_DELAY  BIT(18)
+#define   GLI_9755_UHS2_PLL_DELAY_VALUE0x1
+#define   PCI_GLI_9755_UHS2_PLL_PDRST  BIT(27)
+#define   GLI_9755_UHS2_PLL_PDRST_VALUE0x1
+
+#define PCI_GLI_9755_UHS2_SERDES   0x70
+#define   PCI_GLI_9755_UHS2_SERDES_INTR   GENMASK(2, 0)
+#define   GLI_9755_UHS2_SERDES_INTR_VALUE 0x3
+#define   PCI_GLI_9755_UHS2_SERDES_ZC1BIT(3)
+#define   GLI_9755_UHS2_SERDES_ZC1_VALUE  0x0
+#define   PCI_GLI_9755_UHS2_SERDES_ZC2GENMASK(7, 4)
+#define   GLI_9755_UHS2_SERDES_ZC2_DEFAULT0xB
+#define   GLI_9755_UHS2_SERDES_ZC2_SANDISK0x0
+#define   PCI_GLI_9755_UHS2_SERDES_TRAN   GENMASK(27, 24)
+#define   GLI_9755_UHS2_SERDES_TRAN_VALUE 0xC
+#define   PCI_GLI_9755_UHS2_SERDES_RECV   GENMASK(31, 28)
+#define   GLI_9755_UHS2_SERDES_RECV_VALUE 0xF
+
 #define SDHCI_GLI_9763E_CTRL_HS400  0x7
 
 #define SDHCI_GLI_9763E_HS400_ES_REG  0x52C
@@ -519,6 +556,276 @@ static void sdhci_gl9755_set_clock(struct sdhci_host 
*host, unsigned int clock)
sdhci_enable_clk(host, clk);
 }
 
+static void gl9755_vendor_init(struct sdhci_host *host)
+{
+   struct sdhci_pci_slot *slot = sdhci_priv(host);
+   struct pci_dev *pdev = slot->chip->pdev;
+   u32 serdes;
+   u32 pllssc;
+   u32 uhs2_pll;
+
+   gl9755_wt_on(pdev);
+
+   pci_read_config_dword(pdev, PCI_GLI_9755_UHS2_SERDES, &serdes);
+   serdes &= ~PCI_GLI_9755_UHS2_SERDES_TRAN;
+   serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_TRAN,
+GLI_9755_UHS2_SERDES_TRAN_VALUE);
+   serdes &= ~PCI_GLI_9755_UHS2_SERDES_RECV;
+   serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_RECV,
+GLI_9755_UHS2_SERDES_RECV_VALUE);
+   serdes &= ~PCI_GLI_9755_UHS2_SERDES_INTR;
+   serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_INTR,
+GLI_9755_UHS2_SERDES_INTR_VALUE);
+   serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC1;
+   serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC1,
+GLI_9755_UHS2_SERDES_ZC1_VALUE);
+   serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC2;
+   serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC2,
+GLI_9755_UHS2_SERDES_ZC2_DEFAULT);
+   pci_write_config_dword(pdev, PCI_GLI_9755_UHS2_SERDES, serdes);
+
+   pci_read_config_dword(pdev, PCI_GLI_9755_UHS2_PLL, &uhs2_pll);
+   uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_SSC;
+   uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_SSC,
+ GLI_9755_UHS2_PLL_SSC_VALUE);
+   uhs2

[RFC PATCH v3.1 20/27] mmc: sdhci-uhs2: add request() and others

2020-11-05 Thread AKASHI Takahiro
This is a sdhci version of mmc's request operation.
It covers both UHS-I and UHS-II.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 529 ++
 drivers/mmc/host/sdhci.c  |  93 +++---
 drivers/mmc/host/sdhci.h  |  21 ++
 3 files changed, 610 insertions(+), 33 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index d8afb99a9918..36e52553977a 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "sdhci.h"
 #include "sdhci-uhs2.h"
@@ -394,6 +395,27 @@ static int sdhci_uhs2_check_dormant(struct sdhci_host 
*host)
return 0;
 }
 
+/* TODO: move them to a header */
+#if IS_REACHABLE(CONFIG_LEDS_CLASS)
+static inline void sdhci_led_activate(struct sdhci_host *host)
+{
+}
+
+static inline void sdhci_led_deactivate(struct sdhci_host *host)
+{
+}
+#else
+static inline void sdhci_led_activate(struct sdhci_host *host)
+{
+   __sdhci_led_activate(host);
+}
+
+static inline void sdhci_led_deactivate(struct sdhci_host *host)
+{
+   __sdhci_led_deactivate(host);
+}
+#endif
+
 /*\
  *   *
  * MMC callbacks *
@@ -523,6 +545,512 @@ static int sdhci_uhs2_set_reg(struct mmc_host *mmc, enum 
uhs2_act act)
return err;
 }
 
+static bool sdhci_uhs2_send_command(struct sdhci_host *host,
+   struct mmc_command *cmd);
+static bool sdhci_uhs2_send_command_retry(struct sdhci_host *host,
+struct mmc_command *cmd,
+unsigned long flags);
+
+void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+   struct mmc_command *cmd;
+   unsigned long flags;
+   bool present;
+
+   /* FIXME: check more flags? */
+   if (!host->mmc->flags & MMC_UHS2_SUPPORT) {
+   sdhci_request(mmc, mrq);
+   return;
+   }
+
+   /* Firstly check card presence */
+   present = mmc->ops->get_cd(mmc);
+
+   spin_lock_irqsave(&host->lock, flags);
+
+   sdhci_led_activate(host);
+
+   if (sdhci_present_error(host, mrq->cmd, present))
+   goto out_finish;
+
+   cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd;
+
+   if (!sdhci_uhs2_send_command_retry(host, cmd, flags))
+   goto out_finish;
+
+   spin_unlock_irqrestore(&host->lock, flags);
+
+   return;
+
+out_finish:
+   sdhci_finish_mrq(host, mrq);
+   spin_unlock_irqrestore(&host->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_request);
+
+int sdhci_uhs2_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+   struct mmc_command *cmd;
+   unsigned long flags;
+   int ret = 0;
+
+   if (!host->mmc->flags & MMC_UHS2_SUPPORT)
+   return sdhci_request_atomic(mmc, mrq);
+
+   spin_lock_irqsave(&host->lock, flags);
+
+   if (sdhci_present_error(host, mrq->cmd, true)) {
+   sdhci_finish_mrq(host, mrq);
+   goto out_finish;
+   }
+
+   cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd;
+
+   /*
+* The HSQ may send a command in interrupt context without polling
+* the busy signaling, which means we should return BUSY if controller
+* has not released inhibit bits to allow HSQ trying to send request
+* again in non-atomic context. So we should not finish this request
+* here.
+*/
+   if (!sdhci_uhs2_send_command(host, cmd))
+   ret = -EBUSY;
+   else
+   sdhci_led_activate(host);
+
+out_finish:
+   spin_unlock_irqrestore(&host->lock, flags);
+   return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_request_atomic);
+
+/*\
+ *   *
+ * Core functions*
+ *   *
+\*/
+
+static void sdhci_uhs2_prepare_data(struct sdhci_host *host,
+   struct mmc_command *cmd)
+{
+   struct mmc_data *data = cmd->data;
+
+   sdhci_initialize_data(host, data);
+
+   sdhci_prepare_dma(host, data);
+
+   sdhci_writew(host, data->blksz, SDHCI_UHS2_BLOCK_SIZE);
+   sdhci_writew

[RFC PATCH v3.1 19/27] mmc: sdhci-uhs2: add set_reg() to initialise the interface

2020-11-05 Thread AKASHI Takahiro
This is a sdhci version of mmc's uhs2_set_reg operation.
UHS-II interface (related registers) will be initialised here.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 103 ++
 1 file changed, 103 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 55362ace1857..d8afb99a9918 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -332,6 +332,68 @@ static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, 
struct mmc_ios *ios)
spin_unlock_irqrestore(&host->lock, flags);
 }
 
+/* TODO: move this function to sdhci.c */
+static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
+{
+   u32 ier;
+
+   ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+   ier &= ~clear;
+   ier |= set;
+   sdhci_writel(host, ier, SDHCI_INT_ENABLE);
+   sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_uhs2_set_config(struct sdhci_host *host)
+{
+   u32 value;
+   u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
+   u16 sdhci_uhs2_gen_set_reg = (sdhci_uhs2_set_ptr + 0);
+   u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
+   u16 sdhci_uhs2_tran_set_reg = (sdhci_uhs2_set_ptr + 8);
+   u16 sdhci_uhs2_tran_set_1_reg = (sdhci_uhs2_set_ptr + 12);
+
+   /* Set Gen Settings */
+   sdhci_writel(host, host->mmc->uhs2_caps.n_lanes_set <<
+   SDHCI_UHS2_GEN_SET_N_LANES_POS, sdhci_uhs2_gen_set_reg);
+
+   /* Set PHY Settings */
+   value = (host->mmc->uhs2_caps.n_lss_dir_set <<
+   SDHCI_UHS2_PHY_SET_N_LSS_DIR_POS) |
+   (host->mmc->uhs2_caps.n_lss_sync_set <<
+   SDHCI_UHS2_PHY_SET_N_LSS_SYN_POS);
+   if (host->mmc->flags & MMC_UHS2_SPEED_B)
+   value |= 1 << SDHCI_UHS2_PHY_SET_SPEED_POS;
+   sdhci_writel(host, value, sdhci_uhs2_phy_set_reg);
+
+   /* Set LINK-TRAN Settings */
+   value = (host->mmc->uhs2_caps.max_retry_set <<
+   SDHCI_UHS2_TRAN_SET_RETRY_CNT_POS) |
+   (host->mmc->uhs2_caps.n_fcu_set <<
+   SDHCI_UHS2_TRAN_SET_N_FCU_POS);
+   sdhci_writel(host, value, sdhci_uhs2_tran_set_reg);
+   sdhci_writel(host, host->mmc->uhs2_caps.n_data_gap_set,
+sdhci_uhs2_tran_set_1_reg);
+}
+
+static int sdhci_uhs2_check_dormant(struct sdhci_host *host)
+{
+   int timeout = 100;
+
+   while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
+   SDHCI_UHS2_IN_DORMANT_STATE)) {
+   if (timeout == 0) {
+   pr_warn("%s: UHS2 IN_DORMANT fail in 100ms.\n",
+   mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return -EIO;
+   }
+   timeout--;
+   mdelay(1);
+   }
+   return 0;
+}
+
 /*\
  *   *
  * MMC callbacks *
@@ -422,6 +484,45 @@ static void sdhci_uhs2_enable_clk(struct mmc_host *mmc)
}
 }
 
+static int sdhci_uhs2_set_reg(struct mmc_host *mmc, enum uhs2_act act)
+{
+struct sdhci_host *host = mmc_priv(mmc);
+   unsigned long flags;
+   int err = 0;
+   u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SET_PTR);
+   u16 sdhci_uhs2_phy_set_reg = (sdhci_uhs2_set_ptr + 4);
+
+   DBG("Begin sdhci_uhs2_set_reg, act %d.\n", act);
+   spin_lock_irqsave(&host->lock, flags);
+
+   switch (act) {
+   case SET_CONFIG:
+   sdhci_uhs2_set_config(host);
+   break;
+   case ENABLE_INT:
+   sdhci_clear_set_irqs(host, 0, SDHCI_INT_CARD_INT);
+   break;
+   case DISABLE_INT:
+   sdhci_clear_set_irqs(host, SDHCI_INT_CARD_INT, 0);
+   break;
+   case SET_SPEED_B:
+   sdhci_writeb(host, 1 << SDHCI_UHS2_PHY_SET_SPEED_POS,
+sdhci_uhs2_phy_set_reg);
+   break;
+   case CHECK_DORMANT:
+   err = sdhci_uhs2_check_dormant(host);
+   break;
+   default:
+   pr_err("%s: input action %d is wrong!\n",
+  mmc_hostname(host->mmc), act);
+   err = -EIO;
+   break;
+   }
+
+   spin_unlock_irqrestore(&host->lock, flags);
+   return err;
+}
+
 /*\
  *   *
  * Driver init/exit   

[RFC PATCH v3.1 12/27] mmc: sdhci-uhs2: add reset function

2020-11-05 Thread AKASHI Takahiro
Sdhci_uhs2_reset() does a UHS-II specific reset operation.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 49 +++
 drivers/mmc/host/sdhci-uhs2.h |  1 +
 drivers/mmc/host/sdhci.c  |  3 ++-
 drivers/mmc/host/sdhci.h  |  1 +
 4 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 08905ed081fb..e2b9743fe17d 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -10,6 +10,7 @@
  *  Author: AKASHI Takahiro 
  */
 
+#include 
 #include 
 
 #include "sdhci.h"
@@ -49,6 +50,54 @@ void sdhci_uhs2_dump_regs(struct sdhci_host *host)
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
 
+/*\
+ *   *
+ * Low level functions   *
+ *   *
+\*/
+
+/**
+ * sdhci_uhs2_reset - invoke SW reset
+ * @host: SDHCI host
+ * @mask: Control mask
+ *
+ * Invoke SW reset, depending on a bit in @mask and wait for completion.
+ */
+void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
+{
+   unsigned long timeout;
+
+   if (!(host->mmc->caps & MMC_CAP_UHS2))
+   return;
+
+   sdhci_writew(host, mask, SDHCI_UHS2_SW_RESET);
+
+   if (mask & SDHCI_UHS2_SW_RESET_FULL) {
+   host->clock = 0;
+   /* Reset-all turns off SD Bus Power */
+   if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+   sdhci_runtime_pm_bus_off(host);
+   }
+
+   /* Wait max 100 ms */
+   timeout = 1;
+
+   /* hw clears the bit when it's done */
+   while (sdhci_readw(host, SDHCI_UHS2_SW_RESET) & mask) {
+   if (timeout == 0) {
+   pr_err("%s: %s: Reset 0x%x never completed.\n",
+  __func__, mmc_hostname(host->mmc), (int)mask);
+   pr_err("%s: clean reset bit\n",
+  mmc_hostname(host->mmc));
+   sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET);
+   return;
+   }
+   timeout--;
+   udelay(10);
+   }
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
+
 /*\
  *   *
  * Driver init/exit  *
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index b9529d32b58d..7bb7a0d67109 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -210,5 +210,6 @@
 struct sdhci_host;
 
 void sdhci_uhs2_dump_regs(struct sdhci_host *host);
+void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
 
 #endif /* __SDHCI_UHS2_H */
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d4a57e8c9bb8..af336bdb4305 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -195,13 +195,14 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host 
*host)
pm_runtime_get_noresume(host->mmc->parent);
 }
 
-static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
+void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
 {
if (!host->bus_on)
return;
host->bus_on = false;
pm_runtime_put_noidle(host->mmc->parent);
 }
+EXPORT_SYMBOL_GPL(sdhci_runtime_pm_bus_off);
 
 void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d9d7a76cedc1..b9932423db08 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -831,6 +831,7 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
__sdhci_read_caps(host, NULL, NULL, NULL);
 }
 
+void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
 u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
   unsigned int *actual_clock);
 void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
-- 
2.28.0



[RFC PATCH v3.1 17/27] mmc: sdhci-uhs2: add detect_init() to detect the interface

2020-11-05 Thread AKASHI Takahiro
Sdhci_uhs2_do_detect_init() is a sdhci version of mmc's uhs2_detect_init
operation. After detected, the host's UHS-II capabilities will be set up
here and interrupts will also be enabled.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 160 ++
 1 file changed, 160 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 637464748cc4..994dff967e85 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -391,12 +391,172 @@ void sdhci_uhs2_set_ios(struct mmc_host *mmc, struct 
mmc_ios *ios)
  *   *
 \*/
 
+static int sdhci_uhs2_interface_detect(struct sdhci_host *host)
+{
+   int timeout = 100;
+
+   udelay(200); /* wait for 200us before check */
+
+   while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
+   SDHCI_UHS2_IF_DETECT)) {
+   if (timeout == 0) {
+   pr_warn("%s: not detect UHS2 interface in 200us.\n",
+   mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return -EIO;
+   }
+   timeout--;
+   mdelay(1);
+   }
+
+   /* Enable UHS2 error interrupts */
+   sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
+ SDHCI_UHS2_ERR_INT_STATUS_MASK);
+
+   timeout = 150;
+   while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
+   SDHCI_UHS2_LANE_SYNC)) {
+   if (timeout == 0) {
+   pr_warn("%s: UHS2 Lane sync fail in 150ms.\n",
+   mmc_hostname(host->mmc));
+   sdhci_dumpregs(host);
+   return -EIO;
+   }
+   timeout--;
+   mdelay(1);
+   }
+
+   DBG("%s: UHS2 Lane synchronized in UHS2 mode, PHY is initialized.\n",
+   mmc_hostname(host->mmc));
+   return 0;
+}
+
+static int sdhci_uhs2_init(struct sdhci_host *host)
+{
+   u16 caps_ptr = 0;
+   u32 caps_gen = 0;
+   u32 caps_phy = 0;
+   u32 caps_tran[2] = {0, 0};
+   struct mmc_host *mmc = host->mmc;
+
+   /*
+* TODO: may add corresponding members in sdhci_host to
+* keep these caps.
+*/
+   caps_ptr = sdhci_readw(host, SDHCI_UHS2_HOST_CAPS_PTR);
+   if (caps_ptr < 0x100 || caps_ptr > 0x1FF) {
+   pr_err("%s: SDHCI_UHS2_HOST_CAPS_PTR(%d) is wrong.\n",
+  mmc_hostname(mmc), caps_ptr);
+   return -ENODEV;
+   }
+   caps_gen = sdhci_readl(host,
+  caps_ptr + SDHCI_UHS2_HOST_CAPS_GEN_OFFSET);
+   caps_phy = sdhci_readl(host,
+  caps_ptr + SDHCI_UHS2_HOST_CAPS_PHY_OFFSET);
+   caps_tran[0] = sdhci_readl(host,
+  caps_ptr + SDHCI_UHS2_HOST_CAPS_TRAN_OFFSET);
+   caps_tran[1] = sdhci_readl(host,
+  caps_ptr
+   + SDHCI_UHS2_HOST_CAPS_TRAN_1_OFFSET);
+
+   /* General Caps */
+   mmc->uhs2_caps.dap = caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_DAP_MASK;
+   mmc->uhs2_caps.gap = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_GAP_MASK) >>
+SDHCI_UHS2_HOST_CAPS_GEN_GAP_SHIFT;
+   mmc->uhs2_caps.n_lanes = (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_LANE_MASK)
+   >> SDHCI_UHS2_HOST_CAPS_GEN_LANE_SHIFT;
+   mmc->uhs2_caps.addr64 =
+   (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_ADDR_64) ? 1 : 0;
+   mmc->uhs2_caps.card_type =
+   (caps_gen & SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_MASK) >>
+   SDHCI_UHS2_HOST_CAPS_GEN_DEV_TYPE_SHIFT;
+
+   /* PHY Caps */
+   mmc->uhs2_caps.phy_rev = caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_REV_MASK;
+   mmc->uhs2_caps.speed_range =
+   (caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_RANGE_MASK)
+   >> SDHCI_UHS2_HOST_CAPS_PHY_RANGE_SHIFT;
+   mmc->uhs2_caps.n_lss_sync =
+   (caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_MASK)
+   >> SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_SYN_SHIFT;
+   mmc->uhs2_caps.n_lss_dir =
+   (caps_phy & SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_MASK)
+   >> SDHCI_UHS2_HOST_CAPS_PHY_N_LSS_DIR_SHIFT;
+   if (mmc->uhs2_caps.n_lss_sync == 0)
+   mmc->uhs2_caps.n_lss_sync = 16 << 2;
+   else
+   mmc->uhs2_caps.n_lss_sync <<= 2;
+   if (mmc->uhs2_caps.n_lss_dir == 0)
+   mmc->uhs2_caps.n_lss_dir = 16 << 3;
+

[RFC PATCH v3.1 24/27] mmc: core: add post-mmc_attach_sd hook

2020-11-05 Thread AKASHI Takahiro
This "post" hook for mmc_attach_sd() will be required to enable UHS-II
support, at least, on GL9755.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/sd.c| 6 ++
 include/linux/mmc/host.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 54e155ff44ff..9e0a5abe9be1 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1411,6 +1411,12 @@ int mmc_attach_sd(struct mmc_host *host)
goto remove_card;
 
mmc_claim_host(host);
+
+   /* TODO: Is this the right place? */
+   if ((host->flags & MMC_UHS2_INITIALIZED) &&
+   host->ops->uhs2_post_attach_sd)
+   host->ops->uhs2_post_attach_sd(host);
+
return 0;
 
 remove_card:
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 19a265190ad3..03131e4504ad 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -181,6 +181,7 @@ struct mmc_host_ops {
int (*uhs2_set_reg)(struct mmc_host *host, enum uhs2_act act);
void(*uhs2_disable_clk)(struct mmc_host *host);
void(*uhs2_enable_clk)(struct mmc_host *host);
+   void(*uhs2_post_attach_sd)(struct mmc_host *host);
 };
 
 struct mmc_cqe_ops {
-- 
2.28.0



[RFC PATCH v3.1 26/27] mmc: sdhci-pci: add UHS-II support framework

2020-11-05 Thread AKASHI Takahiro
This patch prepares for adding UHS-II support at a specific UHS-II
capable sdhci-pci controller, GL9755 for now.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-pci-core.c | 16 +++-
 drivers/mmc/host/sdhci-pci.h  |  3 +++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-pci-core.c 
b/drivers/mmc/host/sdhci-pci-core.c
index 23da7f7fe093..a896c7b325d0 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -39,6 +39,7 @@
 
 #include "sdhci.h"
 #include "sdhci-pci.h"
+#include "sdhci-uhs2.h"
 
 static void sdhci_pci_hw_reset(struct sdhci_host *host);
 
@@ -2215,7 +2216,10 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot 
*slot)
if (scratch == (u32)-1)
dead = 1;
 
-   sdhci_remove_host(slot->host, dead);
+   if (slot->chip->fixes && slot->chip->fixes->remove_host)
+   slot->chip->fixes->remove_host(slot, dead);
+   else
+   sdhci_remove_host(slot->host, dead);
 
if (slot->chip->fixes && slot->chip->fixes->remove_slot)
slot->chip->fixes->remove_slot(slot, dead);
@@ -2226,6 +2230,16 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot 
*slot)
sdhci_free_host(slot->host);
 }
 
+int sdhci_pci_uhs2_add_host(struct sdhci_pci_slot *slot)
+{
+   return sdhci_uhs2_add_host(slot->host);
+}
+
+void sdhci_pci_uhs2_remove_host(struct sdhci_pci_slot *slot, int dead)
+{
+   sdhci_uhs2_remove_host(slot->host, dead);
+}
+
 static void sdhci_pci_runtime_pm_allow(struct device *dev)
 {
pm_suspend_ignore_children(dev, 1);
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index d0ed232af0eb..c961ec3cec26 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -137,6 +137,7 @@ struct sdhci_pci_fixes {
int (*probe_slot) (struct sdhci_pci_slot *);
int (*add_host) (struct sdhci_pci_slot *);
void(*remove_slot) (struct sdhci_pci_slot *, int);
+   void(*remove_host) (struct sdhci_pci_slot *, int);
 
 #ifdef CONFIG_PM_SLEEP
int (*suspend) (struct sdhci_pci_chip *);
@@ -186,6 +187,8 @@ static inline void *sdhci_pci_priv(struct sdhci_pci_slot 
*slot)
return (void *)slot->private;
 }
 
+int sdhci_pci_uhs2_add_host(struct sdhci_pci_slot *slot);
+void sdhci_pci_uhs2_remove_host(struct sdhci_pci_slot *slot, int dead);
 #ifdef CONFIG_PM_SLEEP
 int sdhci_pci_resume_host(struct sdhci_pci_chip *chip);
 #endif
-- 
2.28.0



[RFC PATCH v3.1 04/27] mmc: core: UHS-II support, try to select UHS-II interface

2020-11-05 Thread AKASHI Takahiro
From: Ben Chuang 

The flow of "interface selection and initialization" was a bit modified
for UHS-II card. This commit follows the sequence defined in SD
specification (Part 1).
See section 7.2.3 in "UHS-II Simplified Addendum."

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/Makefile |   2 +-
 drivers/mmc/core/bus.c|   5 +-
 drivers/mmc/core/core.c   |  33 +-
 drivers/mmc/core/sd.c |  26 ++
 drivers/mmc/core/uhs2.c   | 809 ++
 drivers/mmc/core/uhs2.h   |  20 +
 6 files changed, 891 insertions(+), 4 deletions(-)
 create mode 100644 drivers/mmc/core/uhs2.c
 create mode 100644 drivers/mmc/core/uhs2.h

diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 95ffe008ebdf..e2a90dc98afc 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -8,7 +8,7 @@ mmc_core-y  := core.o bus.o host.o \
   mmc.o mmc_ops.o sd.o sd_ops.o \
   sdio.o sdio_ops.o sdio_bus.o \
   sdio_cis.o sdio_io.o sdio_irq.o \
-  slot-gpio.o regulator.o
+  slot-gpio.o regulator.o uhs2.o
 mmc_core-$(CONFIG_OF)  += pwrseq.o
 obj-$(CONFIG_PWRSEQ_SIMPLE)+= pwrseq_simple.o
 obj-$(CONFIG_PWRSEQ_SD8787)+= pwrseq_sd8787.o
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index c2e70b757dd1..02dcdce54547 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -362,8 +362,9 @@ int mmc_add_card(struct mmc_card *card)
} else {
pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
mmc_hostname(card->host),
-   mmc_card_uhs(card) ? "ultra high speed " :
-   (mmc_card_hs(card) ? "high speed " : ""),
+   mmc_card_uhs2(card) ? "ultra high speed 2 " :
+   (mmc_card_uhs(card) ? "ultra high speed 1 " :
+   (mmc_card_hs(card) ? "high speed " : "")),
mmc_card_hs400(card) ? "HS400 " :
(mmc_card_hs200(card) ? "HS200 " : ""),
mmc_card_hs400es(card) ? "Enhanced strobe " : "",
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 4e12bd98fc08..a08cb1c0f6d2 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define CREATE_TRACE_POINTS
 #include 
@@ -41,6 +42,7 @@
 #include "host.h"
 #include "sdio_bus.h"
 #include "pwrseq.h"
+#include "uhs2.h"
 
 #include "mmc_ops.h"
 #include "sd_ops.h"
@@ -51,6 +53,7 @@
 #define SD_DISCARD_TIMEOUT_MS  (250)
 
 static const unsigned freqs[] = { 40, 30, 20, 10 };
+static const unsigned int uhs2_freqs[] = { 5200, 2600 };
 
 /*
  * Enabling software CRCs on the data blocks can be a significant (30%)
@@ -2176,9 +2179,10 @@ static int mmc_rescan_try_freq(struct mmc_host *host, 
unsigned freq)
if (!mmc_attach_sdio(host))
return 0;
 
-   if (!(host->caps2 & MMC_CAP2_NO_SD))
+   if (!(host->caps2 & MMC_CAP2_NO_SD)) {
if (!mmc_attach_sd(host))
return 0;
+   }
 
if (!(host->caps2 & MMC_CAP2_NO_MMC))
if (!mmc_attach_mmc(host))
@@ -2311,6 +2315,33 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
 
+   if (host->caps & MMC_CAP_UHS2) {
+   /*
+* Start to try UHS-II initialization from 52MHz to 26MHz
+* (RCLK range) per spec.
+*/
+   for (i = 0; i < ARRAY_SIZE(uhs2_freqs); i++) {
+   unsigned int freq = uhs2_freqs[i];
+   int err;
+
+   err = mmc_uhs2_rescan_try_freq(host,
+  max(freq, host->f_min));
+   if (!err) {
+   mmc_release_host(host);
+   goto out;
+   }
+
+   if (err == UHS2_PHY_INIT_ERR)
+   /* UHS2 IF detect or Lane Sync error.
+* Try legacy interface.
+*/
+   break;
+
+   if (freq <= host->f_min)
+   break;
+   }
+   }
+
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
unsigned int freq = freqs[i];
if (freq > host->f_max) {
diff --git a/drivers/mmc/

[RFC PATCH v3.1 05/27] mmc: core: UHS-II support, skip TMODE setup in some cases

2020-11-05 Thread AKASHI Takahiro
UHS-II's data command packet has TMODE fields in which parameters for
data transaction, like Duplex Mode(DM) and Length Mode(LM), are specified.
In some cases, we don't need to initialize them and so set uhs2_tmode0_flag
to 1 in order to skip them in generating a packet.
(The code will be added in the next commit.)

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/block.c  | 7 ++-
 drivers/mmc/core/sd_ops.c | 3 +++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 8d3df0be0355..f09794811042 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -56,6 +56,7 @@
 #include "mmc_ops.h"
 #include "quirks.h"
 #include "sd_ops.h"
+#include "uhs2.h"
 
 MODULE_ALIAS("mmc:block");
 #ifdef MODULE_PARAM_PREFIX
@@ -1523,6 +1524,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct request *req = mmc_queue_req_to_req(mqrq);
struct mmc_blk_data *md = mq->blkdata;
bool do_rel_wr, do_data_tag;
+   bool do_multi;
+
+   do_multi = (card->host->flags & MMC_UHS2_INITIALIZED) ? true : false;
 
mmc_blk_data_prep(mq, mqrq, disable_multi, &do_rel_wr, &do_data_tag);
 
@@ -1533,7 +1537,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
brq->cmd.arg <<= 9;
brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
-   if (brq->data.blocks > 1 || do_rel_wr) {
+   if (brq->data.blocks > 1 || do_rel_wr || do_multi) {
/* SPI multiblock writes terminate using a special
 * token, not a STOP_TRANSMISSION request.
 */
@@ -1546,6 +1550,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
brq->mrq.stop = NULL;
readcmd = MMC_READ_SINGLE_BLOCK;
writecmd = MMC_WRITE_BLOCK;
+   brq->cmd.uhs2_tmode0_flag = 1;
}
brq->cmd.opcode = rq_data_dir(req) == READ ? readcmd : writecmd;
 
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 22bf528294b9..f58bb50872f6 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -235,6 +235,7 @@ int mmc_app_send_scr(struct mmc_card *card)
cmd.opcode = SD_APP_SEND_SCR;
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+   cmd.uhs2_tmode0_flag = 1;
 
data.blksz = 8;
data.blocks = 1;
@@ -282,6 +283,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int 
group,
cmd.arg &= ~(0xF << (group * 4));
cmd.arg |= value << (group * 4);
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+   cmd.uhs2_tmode0_flag = 1;
 
data.blksz = 64;
data.blocks = 1;
@@ -323,6 +325,7 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
cmd.opcode = SD_APP_SD_STATUS;
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC;
+   cmd.uhs2_tmode0_flag = 1;
 
data.blksz = 64;
data.blocks = 1;
-- 
2.28.0



[RFC PATCH v3.1 22/27] mmc: sdhci-uhs2: add add_host() and others to set up the driver

2020-11-05 Thread AKASHI Takahiro
This is a UHS-II version of sdhci's add_host/remove_host operation.
Any sdhci drivers which are capable of handling UHS-II cards must
call those functions instead of the corresponding sdhci's.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 198 ++
 drivers/mmc/host/sdhci-uhs2.h |   2 +
 drivers/mmc/host/sdhci.c  |  24 +++--
 drivers/mmc/host/sdhci.h  |  10 ++
 4 files changed, 226 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index d50134e912f3..5d3362ea138f 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "sdhci.h"
 #include "sdhci-uhs2.h"
@@ -406,6 +407,15 @@ static inline void sdhci_led_deactivate(struct sdhci_host 
*host)
 {
 }
 #else
+static inline int sdhci_led_register(struct sdhci_host *host)
+{
+   return 0;
+}
+
+static inline void sdhci_led_unregister(struct sdhci_host *host)
+{
+}
+
 static inline void sdhci_led_activate(struct sdhci_host *host)
 {
__sdhci_led_activate(host);
@@ -1298,6 +1308,194 @@ static irqreturn_t sdhci_uhs2_thread_irq(int irq, void 
*dev_id)
return IRQ_HANDLED;
 }
 
+/*\
+ *
+ * Device allocation/registration*
+ *   *
+\*/
+
+static int __sdhci_uhs2_add_host_v4(struct sdhci_host *host, u32 caps1)
+{
+   struct mmc_host *mmc;
+   u32 max_current_caps2;
+
+   if (host->version < SDHCI_SPEC_400)
+   return 0;
+
+   mmc = host->mmc;
+
+   /* Support UHS2 */
+   if (caps1 & SDHCI_SUPPORT_UHS2)
+   mmc->caps |= MMC_CAP_UHS2;
+
+   max_current_caps2 = sdhci_readl(host, SDHCI_MAX_CURRENT_1);
+
+   if ((caps1 & SDHCI_SUPPORT_VDD2_180) &&
+   !max_current_caps2 &&
+   !IS_ERR(mmc->supply.vmmc2)) {
+   /* UHS2 - VDD2 */
+   int curr = regulator_get_current_limit(mmc->supply.vmmc2);
+
+   if (curr > 0) {
+   /* convert to SDHCI_MAX_CURRENT format */
+   curr = curr / 1000;  /* convert to mA */
+   curr = curr / SDHCI_MAX_CURRENT_MULTIPLIER;
+   curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
+   max_current_caps2 = curr;
+   }
+   }
+
+   if (caps1 & SDHCI_SUPPORT_VDD2_180) {
+   mmc->ocr_avail_uhs2 |= MMC_VDD2_165_195;
+   /*
+* UHS2 doesn't require this. Only UHS-I bus needs to set
+* max current.
+*/
+   mmc->max_current_180_vdd2 = (max_current_caps2 &
+   SDHCI_MAX_CURRENT_VDD2_180_MASK) *
+   SDHCI_MAX_CURRENT_MULTIPLIER;
+   } else {
+   mmc->caps &= ~MMC_CAP_UHS2;
+   }
+
+   return 0;
+}
+
+static int sdhci_uhs2_host_ops_init(struct sdhci_host *host);
+
+static int __sdhci_uhs2_add_host(struct sdhci_host *host)
+{
+   unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI;
+   struct mmc_host *mmc = host->mmc;
+   int ret;
+
+   if ((mmc->caps2 & MMC_CAP2_CQE) &&
+   (host->quirks & SDHCI_QUIRK_BROKEN_CQE)) {
+   mmc->caps2 &= ~MMC_CAP2_CQE;
+   mmc->cqe_ops = NULL;
+   }
+
+   /* overwrite ops */
+   if (mmc->caps & MMC_CAP_UHS2)
+   sdhci_uhs2_host_ops_init(host);
+
+   host->complete_wq = alloc_workqueue("sdhci", flags, 0);
+   if (!host->complete_wq)
+   return -ENOMEM;
+
+   INIT_WORK(&host->complete_work, sdhci_uhs2_complete_work);
+
+   timer_setup(&host->timer, sdhci_timeout_timer, 0);
+   timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
+
+   init_waitqueue_head(&host->buf_ready_int);
+
+   sdhci_init(host, 0);
+
+   ret = request_threaded_irq(host->irq, sdhci_irq,
+  sdhci_uhs2_thread_irq,
+  IRQF_SHARED, mmc_hostname(mmc), host);
+   if (ret) {
+   pr_err("%s: Failed to request IRQ %d: %d\n",
+  mmc_hostname(mmc), host->irq, ret);
+   goto unwq;
+   }
+
+   ret = sdhci_led_register(host);
+   if (ret) {
+   pr_err("%s: Failed to register LED device: %d\n",
+  mmc_hostname(mmc), ret);
+   goto unirq;
+   }
+

[RFC PATCH v3.1 09/27] mmc: sdhci: add UHS-II related definitions in headers

2020-11-05 Thread AKASHI Takahiro
Add UHS-II related definitions in shdci.h and sdhci-uhs2.h.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.h | 210 ++
 drivers/mmc/host/sdhci.h  |  73 +++-
 2 files changed, 282 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.h

diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
new file mode 100644
index ..3b157df9c89c
--- /dev/null
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *  linux/drivers/mmc/host/sdhci-uhs2.h - Secure Digital Host Controller
+ *  Interface driver
+ *
+ * Header file for Host Controller UHS2 related registers and I/O accessors.
+ *
+ *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ */
+#ifndef __SDHCI_UHS2_H
+#define __SDHCI_UHS2_H
+
+#include 
+
+/*
+ * UHS-II Controller registers
+ * 0x74 preset in sdhci.h
+ * 0x80
+ * 0x84-0xB4
+ * 0xB8-0xCF
+ * 0xE0-0xE7
+ */
+/* UHS2 */
+#define SDHCI_UHS2_BLOCK_SIZE  0x80
+#define  SDHCI_UHS2_MAKE_BLKSZ(dma, blksz) \
+   dma) & 0x7) << 12) | ((blksz) & 0xFFF))
+
+#define SDHCI_UHS2_BLOCK_COUNT 0x84
+
+#define SDHCI_UHS2_CMD_PACKET  0x88
+#define  SDHCI_UHS2_CMD_PACK_MAX_LEN   20
+
+#define SDHCI_UHS2_TRANS_MODE  0x9C
+#define  SDHCI_UHS2_TRNS_DMA   BIT(0)
+#define  SDHCI_UHS2_TRNS_BLK_CNT_ENBIT(1)
+#define  SDHCI_UHS2_TRNS_DATA_TRNS_WRT BIT(4)
+#define  SDHCI_UHS2_TRNS_BLK_BYTE_MODE BIT(5)
+#define  SDHCI_UHS2_TRNS_RES_R5BIT(6)
+#define  SDHCI_UHS2_TRNS_RES_ERR_CHECK_EN  BIT(7)
+#define  SDHCI_UHS2_TRNS_RES_INT_DIS   BIT(8)
+#define  SDHCI_UHS2_TRNS_WAIT_EBSY BIT(14)
+#define  SDHCI_UHS2_TRNS_2L_HD BIT(15)
+
+#define SDHCI_UHS2_COMMAND 0x9E
+#define  SDHCI_UHS2_COMMAND_SUB_CMD0x0004
+#define  SDHCI_UHS2_COMMAND_DATA   0x0020
+#define  SDHCI_UHS2_COMMAND_TRNS_ABORT 0x0040
+#define  SDHCI_UHS2_COMMAND_CMD12  0x0080
+#define  SDHCI_UHS2_COMMAND_DORMANT0x00C0
+#define  SDHCI_UHS2_COMMAND_PACK_LEN_MASK  GENMASK(12,8)
+#define  SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT 8
+
+#define SDHCI_UHS2_RESPONSE0xA0
+#define  SDHCI_UHS2_RESPONSE_MAX_LEN   20
+
+#define SDHCI_UHS2_MSG_SELECT  0xB4
+#define SDHCI_UHS2_MSG_SELECT_CURR 0x0
+#define SDHCI_UHS2_MSG_SELECT_ONE  0x1
+#define SDHCI_UHS2_MSG_SELECT_TWO  0x2
+#define SDHCI_UHS2_MSG_SELECT_THREE0x3
+
+#define SDHCI_UHS2_MSG 0xB8
+
+#define SDHCI_UHS2_DEV_INT_STATUS  0xBC
+
+#define SDHCI_UHS2_DEV_SELECT  0xBE
+#define SDHCI_UHS2_DEV_SELECT_DEV_SEL_MASK GENMASK(3,0)
+#define SDHCI_UHS2_DEV_SELECT_INT_MSG_EN   BIT(7)
+
+#define SDHCI_UHS2_DEV_INT_CODE0xBF
+
+#define SDHCI_UHS2_SW_RESET0xC0
+#define SDHCI_UHS2_SW_RESET_FULL   0x0001
+#define SDHCI_UHS2_SW_RESET_SD 0x0002
+
+#define SDHCI_UHS2_TIMER_CTRL  0xC2
+#define SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT   4
+
+#define SDHCI_UHS2_ERR_INT_STATUS  0xC4
+#define SDHCI_UHS2_ERR_INT_STATUS_EN   0xC8
+#define SDHCI_UHS2_ERR_INT_SIG_EN  0xCC
+#define SDHCI_UHS2_ERR_INT_STATUS_HEADER   BIT(0)
+#define SDHCI_UHS2_ERR_INT_STATUS_RES  BIT(1)
+#define SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXPBIT(2)
+#define SDHCI_UHS2_ERR_INT_STATUS_CRC  BIT(3)
+#define SDHCI_UHS2_ERR_INT_STATUS_FRAMEBIT(4)
+#define SDHCI_UHS2_ERR_INT_STATUS_TID  BIT(5)
+#define SDHCI_UHS2_ERR_INT_STATUS_UNRECOVERBIT(7)
+#define SDHCI_UHS2_ERR_INT_STATUS_EBUSYBIT(8)
+#define SDHCI_UHS2_ERR_INT_STATUS_ADMA BIT(15)
+#define SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT  BIT(16)
+#define SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT BIT(17)
+#define SDHCI_UHS2_ERR_INT_STATUS_VENDOR   BIT(27)
+#define SDHCI_UHS2_ERR_INT_STATUS_MASK \
+   (SDHCI_UHS2_ERR_INT_STATUS_HEADER | \
+   SDHCI_UHS2_ERR_INT_STATUS_RES | \
+   SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP |   \
+   SDHCI_UHS2_ERR_INT_STATUS_CRC | \
+   SDHCI_UHS2_ERR_INT_STATUS_FRAME |   \
+   SDHCI_UHS2_ERR_INT_STATUS_TID | \
+   SDHCI_UHS2_ERR_INT_STATUS_UNRECOVER |   \
+   SDHCI_UHS2_ERR_INT_STATUS_EBUSY |   \
+   SDHCI_UHS2_ERR_INT_STATUS_ADMA |\
+   SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT | \
+   SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT)
+#define SDHCI_UHS2_ERR_INT_STATUS_CMD_MASK \
+   (SDHCI_UHS2_ERR_INT_STATUS_HEADER | \
+   SDHCI_UHS2_ERR_INT_STATUS_RES | \
+   SDHCI_UHS2_ERR_INT_STATUS_FRAME |   \
+   SDHCI_UHS2_ERR_INT_STATUS_TID | \
+   SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT)
+/* CRC Error occurs during a packet receiving */
+#define SDHCI_UHS2_ERR_INT_STATUS_DATA_MASK\
+   (SDHCI_UHS2_ERR_INT_ST

[RFC PATCH v3.1 16/27] mmc: sdhci-uhs2: add set_ios()

2020-11-05 Thread AKASHI Takahiro
This is a sdhci version of mmc's set_ios operation.
It covers both UHS-I and UHS-II.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 100 ++
 drivers/mmc/host/sdhci-uhs2.h |   1 +
 drivers/mmc/host/sdhci.c  |  40 +-
 drivers/mmc/host/sdhci.h  |   2 +
 4 files changed, 128 insertions(+), 15 deletions(-)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index d9e98c097bfe..637464748cc4 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -263,6 +263,74 @@ void sdhci_uhs2_set_timeout(struct sdhci_host *host, 
struct mmc_command *cmd)
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
 
+/**
+ * sdhci_uhs2_clear_set_irqs - set Error Interrupt Status Enable register
+ * @host:  SDHCI host
+ * @clear: bit-wise clear mask
+ * @set:   bit-wise set mask
+ *
+ * Set/unset bits in UHS-II Error Interrupt Status Enable register
+ */
+void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
+{
+   u32 ier;
+
+   ier = sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN);
+   ier &= ~clear;
+   ier |= set;
+   sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_STATUS_EN);
+   sdhci_writel(host, ier, SDHCI_UHS2_ERR_INT_SIG_EN);
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_clear_set_irqs);
+
+static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+   u8 cmd_res, dead_lock;
+   u16 ctrl_2;
+   unsigned long flags;
+
+   /* FIXME: why lock? */
+   spin_lock_irqsave(&host->lock, flags);
+
+   /* UHS2 Timeout Control */
+   sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
+
+   /* change to use calculate value */
+   cmd_res |= dead_lock << SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT;
+
+   sdhci_uhs2_clear_set_irqs(host,
+ SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
+ SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT,
+ 0);
+   sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
+   sdhci_uhs2_clear_set_irqs(host, 0,
+ SDHCI_UHS2_ERR_INT_STATUS_RES_TIMEOUT |
+ SDHCI_UHS2_ERR_INT_STATUS_DEADLOCK_TIMEOUT);
+
+   /* UHS2 timing */
+   ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+   if (ios->timing == MMC_TIMING_UHS2)
+   ctrl_2 |= SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN;
+   else
+   ctrl_2 &= ~(SDHCI_CTRL_UHS_2 | SDHCI_CTRL_UHS2_INTERFACE_EN);
+   sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+   if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
+   sdhci_enable_preset_value(host, true);
+
+   if (host->ops->set_power)
+   host->ops->set_power(host, ios->power_mode, ios->vdd);
+   else
+   sdhci_set_power(host, ios->power_mode, ios->vdd);
+   udelay(100);
+
+   host->timing = ios->timing;
+   sdhci_set_clock(host, host->clock);
+
+   spin_unlock_irqrestore(&host->lock, flags);
+}
+
 /*\
  *   *
  * MMC callbacks *
@@ -286,6 +354,37 @@ static int sdhci_uhs2_start_signal_voltage_switch(struct 
mmc_host *mmc,
return sdhci_start_signal_voltage_switch(mmc, ios);
 }
 
+void sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+
+   if (!(host->version >= SDHCI_SPEC_400) ||
+   !(host->mmc->flags & MMC_UHS2_SUPPORT &&
+ host->mmc->caps & MMC_CAP_UHS2)) {
+   sdhci_set_ios(mmc, ios);
+   return;
+   }
+
+   if (ios->power_mode == MMC_POWER_UNDEFINED)
+   return;
+
+   if (host->flags & SDHCI_DEVICE_DEAD) {
+   if (!IS_ERR(mmc->supply.vmmc) &&
+   ios->power_mode == MMC_POWER_OFF)
+   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+   if (!IS_ERR_OR_NULL(mmc->supply.vmmc2) &&
+   ios->power_mode == MMC_POWER_OFF)
+   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
+   return;
+   }
+
+   /* FIXME: host->timing = ios->timing */
+
+   sdhci_set_ios_common(mmc, ios);
+
+   __sdhci_uhs2_set_ios(mmc, ios);
+}
+
 /*\
  *   *
  * Driver init/exit  

[RFC PATCH v3.1 15/27] mmc: sdhci-uhs2: add set_timeout()

2020-11-05 Thread AKASHI Takahiro
This is a UHS-II version of sdhci's set_timeout() operation.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 85 +++
 drivers/mmc/host/sdhci-uhs2.h |  1 +
 2 files changed, 86 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 1eca89359351..d9e98c097bfe 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -178,6 +178,91 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, 
unsigned char mode,
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
 
+static u8 sdhci_calc_timeout_uhs2(struct sdhci_host *host, u8 *cmd_res,
+ u8 *dead_lock)
+{
+   u8 count;
+   unsigned int cmd_res_timeout, dead_lock_timeout, current_timeout;
+
+   /*
+* If the host controller provides us with an incorrect timeout
+* value, just skip the check and use 0xE.  The hardware may take
+* longer to time out, but that's much better than having a too-short
+* timeout value.
+*/
+   if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) {
+   *cmd_res = 0xE;
+   *dead_lock = 0xE;
+   return 0xE;
+   }
+
+   /* timeout in us */
+   cmd_res_timeout = 5 * 1000;
+   dead_lock_timeout = 1 * 1000 * 1000;
+
+   /*
+* Figure out needed cycles.
+* We do this in steps in order to fit inside a 32 bit int.
+* The first step is the minimum timeout, which will have a
+* minimum resolution of 6 bits:
+* (1) 2^13*1000 > 2^22,
+* (2) host->timeout_clk < 2^16
+* =>
+* (1) / (2) > 2^6
+*/
+   count = 0;
+   current_timeout = (1 << 13) * 1000 / host->timeout_clk;
+   while (current_timeout < cmd_res_timeout) {
+   count++;
+   current_timeout <<= 1;
+   if (count >= 0xF)
+   break;
+   }
+
+   if (count >= 0xF) {
+   DBG("%s: Too large timeout 0x%x requested for CMD_RES!\n",
+   mmc_hostname(host->mmc), count);
+   count = 0xE;
+   }
+   *cmd_res = count;
+
+   count = 0;
+   current_timeout = (1 << 13) * 1000 / host->timeout_clk;
+   while (current_timeout < dead_lock_timeout) {
+   count++;
+   current_timeout <<= 1;
+   if (count >= 0xF)
+   break;
+   }
+
+   if (count >= 0xF) {
+   DBG("%s: Too large timeout 0x%x requested for DEADLOCK!\n",
+   mmc_hostname(host->mmc), count);
+   count = 0xE;
+   }
+   *dead_lock = count;
+
+   return count;
+}
+
+static void __sdhci_uhs2_set_timeout(struct sdhci_host *host)
+{
+   u8 cmd_res, dead_lock;
+
+   sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock);
+   cmd_res |= dead_lock << SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT;
+   sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL);
+}
+
+void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+{
+   __sdhci_set_timeout(host, cmd);
+
+   if (host->mmc->flags & MMC_UHS2_SUPPORT)
+   __sdhci_uhs2_set_timeout(host);
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout);
+
 /*\
  *   *
  * MMC callbacks *
diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
index 3c19d8e44c36..efe70577bc74 100644
--- a/drivers/mmc/host/sdhci-uhs2.h
+++ b/drivers/mmc/host/sdhci-uhs2.h
@@ -213,5 +213,6 @@ void sdhci_uhs2_dump_regs(struct sdhci_host *host);
 void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
 void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode,
  unsigned short vdd);
+void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
 
 #endif /* __SDHCI_UHS2_H */
-- 
2.28.0



[RFC PATCH v3.1 14/27] mmc: sdhci-uhs2: skip signal_voltage_switch()

2020-11-05 Thread AKASHI Takahiro
For UHS2, the signal voltage is supplied by vdd2 which is already 1.8v,
so no voltage switch required.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/sdhci-uhs2.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
index 2bf78cc4e9ed..1eca89359351 100644
--- a/drivers/mmc/host/sdhci-uhs2.c
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -178,6 +178,29 @@ void sdhci_uhs2_set_power(struct sdhci_host *host, 
unsigned char mode,
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
 
+/*\
+ *   *
+ * MMC callbacks *
+ *   *
+\*/
+
+static int sdhci_uhs2_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+   struct sdhci_host *host = mmc_priv(mmc);
+
+   /*
+* For UHS2, the signal voltage is supplied by vdd2 which is
+* already 1.8v so no voltage switch required.
+*/
+if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
+ host->version >= SDHCI_SPEC_400 &&
+ host->mmc->flags & MMC_UHS2_SUPPORT)
+return 0;
+
+   return sdhci_start_signal_voltage_switch(mmc, ios);
+}
+
 /*\
  *   *
  * Driver init/exit  *
@@ -186,6 +209,9 @@ EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power);
 
 static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
 {
+   host->mmc_host_ops.start_signal_voltage_switch =
+   sdhci_uhs2_start_signal_voltage_switch;
+
return 0;
 }
 
-- 
2.28.0



[RFC PATCH v3.1 10/27] mmc: sdhci: add UHS-II module

2020-11-05 Thread AKASHI Takahiro
This patch adds sdhci-uhs2.c as a module for UHS-II support.
This is a skelton for further development in this patch series.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/Makefile |  1 +
 drivers/mmc/host/sdhci-uhs2.c | 46 +++
 2 files changed, 47 insertions(+)
 create mode 100644 drivers/mmc/host/sdhci-uhs2.c

diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 451c25fc2c69..f6e9b05c3b30 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_PXA) += pxamci.o
 obj-$(CONFIG_MMC_MXC)  += mxcmmc.o
 obj-$(CONFIG_MMC_MXS)  += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)+= sdhci.o
+obj-$(CONFIG_MMC_SDHCI_UHS2)   += sdhci-uhs2.o
 obj-$(CONFIG_MMC_SDHCI_PCI)+= sdhci-pci.o
 sdhci-pci-y+= sdhci-pci-core.o sdhci-pci-o2micro.o 
sdhci-pci-arasan.o \
   sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
new file mode 100644
index ..f29d3a4ed43c
--- /dev/null
+++ b/drivers/mmc/host/sdhci-uhs2.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  linux/drivers/mmc/host/sdhci_uhs2.c - Secure Digital Host Controller
+ *  Interface driver
+ *
+ *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
+ *  Copyright (C) 2020 Genesys Logic, Inc.
+ *  Authors: Ben Chuang 
+ *  Copyright (C) 2020 Linaro Limited
+ *  Author: AKASHI Takahiro 
+ */
+
+#include 
+
+#include "sdhci.h"
+#include "sdhci-uhs2.h"
+
+#define DRIVER_NAME "sdhci_uhs2"
+#define DBG(f, x...) \
+   pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x)
+
+/*\
+ *   *
+ * Driver init/exit  *
+ *   *
+\*/
+
+static int sdhci_uhs2_host_ops_init(struct sdhci_host *host)
+{
+   return 0;
+}
+
+static int __init sdhci_uhs2_mod_init(void)
+{
+   return 0;
+}
+module_init(sdhci_uhs2_mod_init);
+
+static void __exit sdhci_uhs2_exit(void)
+{
+}
+module_exit(sdhci_uhs2_exit);
+
+MODULE_AUTHOR("Intel, Genesys Logic, Linaro");
+MODULE_DESCRIPTION("MMC UHS-II Support");
+MODULE_LICENSE("GPL v2");
-- 
2.28.0



[RFC PATCH v3.1 08/27] mmc: sdhci: add a kernel configuration for enabling UHS-II support

2020-11-05 Thread AKASHI Takahiro
This kernel configuration, CONFIG_MMC_SDHCI_UHS2, will be used
in the following commits to indicate UHS-II specific code in sdhci
controllers.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/host/Kconfig | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 31481c9fcc2e..5ca9ac03db40 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -89,6 +89,15 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
 
  This is the case for the Nintendo Wii SDHCI.
 
+config MMC_SDHCI_UHS2
+   tristate "UHS2 support on SDHCI controller"
+   depends on MMC_SDHCI
+   help
+ This option is selected by SDHCI controller drivers that want to
+ support UHS2-capable devices.
+
+ If you have a controller with this feature, say Y or M here.
+
 config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus"
depends on MMC_SDHCI && PCI
-- 
2.28.0



[RFC PATCH v3.1 03/27] mmc: core: UHS-II support, skip set_chip_select()

2020-11-05 Thread AKASHI Takahiro
mmc_set_chip_select() should be called only in UHS-II mode,
and not for UHS-II mode.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/core.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 5541ed956c4d..4e12bd98fc08 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -898,8 +898,10 @@ static inline void mmc_set_ios(struct mmc_host *host)
  */
 void mmc_set_chip_select(struct mmc_host *host, int mode)
 {
-   host->ios.chip_select = mode;
-   mmc_set_ios(host);
+   if (!(host->flags & MMC_UHS2_INITIALIZED)) {
+   host->ios.chip_select = mode;
+   mmc_set_ios(host);
+   }
 }
 
 /*
-- 
2.28.0



[RFC PATCH v3.1 07/27] mmc: core: UHS-II support, set APP_CMD bit if necessary

2020-11-05 Thread AKASHI Takahiro
In UHS-II mode, MMC_APP_CMD command need not to be sent.
Instead, APP_CMD bit in a packet should be set.

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/sd_ops.c | 9 +
 drivers/mmc/core/uhs2.c   | 4 
 2 files changed, 13 insertions(+)

diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index f58bb50872f6..9dc296356928 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -26,6 +26,15 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
if (WARN_ON(card && card->host != host))
return -EINVAL;
 
+   /* UHS2 packet has APP bit so only set APP_CMD flag here.
+* Will set the APP bit when assembling UHS2 packet.
+*/
+   if (host->flags &  MMC_UHS2_SUPPORT &&
+   host->flags & MMC_UHS2_INITIALIZED) {
+   host->flags |= MMC_UHS2_APP_CMD;
+   return 0;
+   }
+
cmd.opcode = MMC_APP_CMD;
 
if (card) {
diff --git a/drivers/mmc/core/uhs2.c b/drivers/mmc/core/uhs2.c
index 1f6d0e0cf355..c0d61e7d9e4b 100644
--- a/drivers/mmc/core/uhs2.c
+++ b/drivers/mmc/core/uhs2.c
@@ -835,6 +835,10 @@ int uhs2_prepare_sd_cmd(struct mmc_host *host, struct 
mmc_request *mrq)
header |= UHS2_PACKET_TYPE_CCMD;
 
arg = cmd->opcode << UHS2_SD_CMD_INDEX_POS;
+   if (host->flags & MMC_UHS2_APP_CMD) {
+   arg |= UHS2_SD_CMD_APP;
+   host->flags &= ~MMC_UHS2_APP_CMD;
+   }
 
uhs2_cmd = cmd->uhs2_cmd;
payload = uhs2_cmd->payload;
-- 
2.28.0



[RFC PATCH v3.1 02/27] mmc: core: UHS-II support, modify power-up sequence

2020-11-05 Thread AKASHI Takahiro
According to Fig. 3-35 in "SD Host Controller Simplified Spec. Ver4.20":
- Prepare vdd1, vdd2 and ios.timing for using after/in step (2)
- chip_select is not used in UHS-II, used to return to the legacy flow

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 drivers/mmc/core/core.c  | 61 +---
 drivers/mmc/core/regulator.c | 14 +
 2 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d42037f0f10d..5541ed956c4d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1315,33 +1315,52 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
if (host->ios.power_mode == MMC_POWER_ON)
return;
 
-   mmc_pwrseq_pre_power_on(host);
+   if (host->flags & MMC_UHS2_SUPPORT) {
+   /* TODO: handle 'ocr' parameter */
+   host->ios.vdd = fls(host->ocr_avail) - 1;
+   host->ios.vdd2 = fls(host->ocr_avail_uhs2) - 1;
+   if (mmc_host_is_spi(host))
+   host->ios.chip_select = MMC_CS_HIGH;
+   else
+   host->ios.chip_select = MMC_CS_DONTCARE;
+   host->ios.timing = MMC_TIMING_UHS2;
+   } else {
+   mmc_pwrseq_pre_power_on(host);
 
-   host->ios.vdd = fls(ocr) - 1;
-   host->ios.power_mode = MMC_POWER_UP;
-   /* Set initial state and call mmc_set_ios */
-   mmc_set_initial_state(host);
+   host->ios.vdd = fls(ocr) - 1;
+   host->ios.power_mode = MMC_POWER_UP;
+   /* Set initial state and call mmc_set_ios */
+   mmc_set_initial_state(host);
 
-   mmc_set_initial_signal_voltage(host);
+   mmc_set_initial_signal_voltage(host);
 
-   /*
-* This delay should be sufficient to allow the power supply
-* to reach the minimum voltage.
-*/
-   mmc_delay(host->ios.power_delay_ms);
+   /*
+* This delay should be sufficient to allow the power supply
+* to reach the minimum voltage.
+*/
+   mmc_delay(host->ios.power_delay_ms);
 
-   mmc_pwrseq_post_power_on(host);
+   mmc_pwrseq_post_power_on(host);
 
+   }
host->ios.clock = host->f_init;
-
host->ios.power_mode = MMC_POWER_ON;
+
mmc_set_ios(host);
 
-   /*
-* This delay must be at least 74 clock sizes, or 1 ms, or the
-* time required to reach a stable voltage.
-*/
-   mmc_delay(host->ios.power_delay_ms);
+   if (host->flags & MMC_UHS2_SUPPORT)
+   /*
+* This delay should be sufficient to allow the power supply
+* to reach the minimum voltage.
+*/
+   /*  TODO: avoid an immediate value */
+   mmc_delay(10);
+   else
+   /*
+* This delay must be at least 74 clock sizes, or 1 ms, or the
+* time required to reach a stable voltage.
+*/
+   mmc_delay(host->ios.power_delay_ms);
 }
 
 void mmc_power_off(struct mmc_host *host)
@@ -2316,7 +2335,11 @@ void mmc_start_host(struct mmc_host *host)
 
if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
mmc_claim_host(host);
-   mmc_power_up(host, host->ocr_avail);
+
+   /* Power up here will make UHS2 init ugly. */
+   if (!(host->caps & MMC_CAP_UHS2))
+   mmc_power_up(host, host->ocr_avail);
+
mmc_release_host(host);
}
 
diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c
index 609201a467ef..629e25bc8cb7 100644
--- a/drivers/mmc/core/regulator.c
+++ b/drivers/mmc/core/regulator.c
@@ -249,6 +249,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
 
mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
+   mmc->supply.vmmc2 = devm_regulator_get_optional(dev, "vmmc2");
 
if (IS_ERR(mmc->supply.vmmc)) {
if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
@@ -268,6 +269,19 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
dev_dbg(dev, "No vqmmc regulator found\n");
}
 
+   if (IS_ERR(mmc->supply.vmmc2)) {
+   if (PTR_ERR(mmc->supply.vmmc2) == -EPROBE_DEFER)
+   return -EPROBE_DEFER;
+   dev_dbg(dev, "No vmmc2 regulator found\n");
+   } else {
+   ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc2);
+   if (ret > 0)
+   mmc->ocr_avail_uhs2 = ret;
+   else
+   dev_warn(dev, "Failed getting UHS2 OCR mask: %d\n",
+ret);
+   }
+
return 0;
 }
 EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
-- 
2.28.0



[RFC PATCH v3.1 01/27] mmc: add UHS-II related definitions in public headers

2020-11-05 Thread AKASHI Takahiro
From: Ben Chuang 

Add UHS-II support in public headers

Signed-off-by: Ben Chuang 
Signed-off-by: AKASHI Takahiro 
---
 include/linux/mmc/card.h |   1 +
 include/linux/mmc/core.h |   6 +
 include/linux/mmc/host.h |  30 +
 include/linux/mmc/uhs2.h | 268 +++
 4 files changed, 305 insertions(+)
 create mode 100644 include/linux/mmc/uhs2.h

diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 42df06c6b19c..c26eada7f62e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -181,6 +181,7 @@ struct sd_switch_caps {
 #define SD_SET_CURRENT_LIMIT_400   1
 #define SD_SET_CURRENT_LIMIT_600   2
 #define SD_SET_CURRENT_LIMIT_800   3
+#define SD_SET_CURRENT_LIMIT_1000   4
 #define SD_SET_CURRENT_NO_CHANGE   (-1)
 
 #define SD_MAX_CURRENT_200 (1 << SD_SET_CURRENT_LIMIT_200)
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 29aa50711626..52cb628d03fd 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -7,6 +7,7 @@
 
 #include 
 #include 
+#include 
 
 struct mmc_data;
 struct mmc_request;
@@ -109,6 +110,11 @@ struct mmc_command {
unsigned intbusy_timeout;   /* busy detect timeout in ms */
struct mmc_data *data;  /* data segment associated with 
cmd */
struct mmc_request  *mrq;   /* associated request */
+
+   struct uhs2_command *uhs2_cmd;  /* UHS2 command */
+   u8  *uhs2_resp; /* UHS2 native cmd resp */
+   u8  uhs2_resp_len;  /* UHS2 native cmd resp len */
+   u8  uhs2_tmode0_flag; /* UHS2 transfer mode flag */
 };
 
 struct mmc_data {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index c079b932330f..19a265190ad3 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -15,10 +15,12 @@
 #include 
 #include 
 #include 
+#include 
 
 struct mmc_ios {
unsigned intclock;  /* clock rate */
unsigned short  vdd;
+   unsigned short  vdd2;   /* UHS2 VDD2 power supply */
unsigned intpower_delay_ms; /* waiting for stable power */
 
 /* vdd stores the bit number of the selected voltage range from below. */
@@ -60,6 +62,7 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52   8
 #define MMC_TIMING_MMC_HS200   9
 #define MMC_TIMING_MMC_HS400   10
+#define MMC_TIMING_UHS211
 
unsigned char   signal_voltage; /* signalling voltage (1.8V or 
3.3V) */
 
@@ -173,6 +176,11 @@ struct mmc_host_ops {
 */
int (*multi_io_quirk)(struct mmc_card *card,
  unsigned int direction, int blk_size);
+   /* UHS2 interfaces */
+   int (*uhs2_detect_init)(struct mmc_host *host);
+   int (*uhs2_set_reg)(struct mmc_host *host, enum uhs2_act act);
+   void(*uhs2_disable_clk)(struct mmc_host *host);
+   void(*uhs2_enable_clk)(struct mmc_host *host);
 };
 
 struct mmc_cqe_ops {
@@ -265,6 +273,7 @@ struct mmc_pwrseq;
 
 struct mmc_supply {
struct regulator *vmmc; /* Card power supply */
+   struct regulator *vmmc2;/* UHS2 VDD2 power supply */
struct regulator *vqmmc;/* Optional Vccq supply */
 };
 
@@ -285,6 +294,7 @@ struct mmc_host {
u32 ocr_avail_sdio; /* SDIO-specific OCR */
u32 ocr_avail_sd;   /* SD-specific OCR */
u32 ocr_avail_mmc;  /* MMC-specific OCR */
+   u32 ocr_avail_uhs2; /* UHS2-specific OCR */
 #ifdef CONFIG_PM_SLEEP
struct notifier_block   pm_notify;
 #endif
@@ -292,6 +302,7 @@ struct mmc_host {
u32 max_current_330;
u32 max_current_300;
u32 max_current_180;
+   u32 max_current_180_vdd2; /* UHS2 vdd2 max curt. */
 
 #define MMC_VDD_165_1950x0080  /* VDD voltage 1.65 - 
1.95 */
 #define MMC_VDD_20_21  0x0100  /* VDD voltage 2.0 ~ 2.1 */
@@ -310,6 +321,7 @@ struct mmc_host {
 #define MMC_VDD_33_34  0x0020  /* VDD voltage 3.3 ~ 3.4 */
 #define MMC_VDD_34_35  0x0040  /* VDD voltage 3.4 ~ 3.5 */
 #define MMC_VDD_35_36  0x0080  /* VDD voltage 3.5 ~ 3.6 */
+#define MMC_VDD2_165_195   0x0080  /* UHS2 VDD2 1.65 ~ 1.95 */
 
u32 caps;   /* Host capabilities */
 
@@ -343,6 +355,7 @@ struct mmc_host {
 #define MMC_CAP_DRIVER_TYPE_A  (1 << 23)   /* Host supports Driver Type A 
*/
 #define MMC_CAP_DRIVER_TYPE_C  (1 << 24)   /* Host supports Driver Type C 
*/
 #define MMC_CAP_DRIVER_TYPE_D  (1 << 25)   /* Host supports Driver Type D 
*/
+#define MMC_CAP_UHS2   (1 << 26)   /* Host 

[RFC PATCH v3.1 00/27] Add support UHS-II for GL9755

2020-11-05 Thread AKASHI Takahiro
This is an interim snapshot of our next version, v4, for enabling
UHS-II on MMC/SD.

It is focused on 'sdhci' side to address Adrian's comments regarding
"modularising" sdhci-uhs2.c.
The whole aim of this version is to get early feedback from Adrian (and
others) on this issue. Without any consensus about the code structure,
it would make little sense to go further ahead on sdhci side.
(Actually, Adrian has made no comments other than "modularising" so far.)

I heavily reworked/refactored sdhci-uhs2.c and re-organised the patch
set to meet what I believe Adrian expects; no UHS-II related code in
Legacy (UHS-I) code or sdhci.c.

Nevertheless, almost of all changes I made are trivial and straightforward
in this direction, and I believe that there is no logic changed since v3
except sdhci_uhs2_irq(), as ops->irq hook, where we must deal with UHS-II
command sequences in addition to UHS-II errors. So I added extra handlings.

I admit that there is plenty of room for improvements (for example,
handling host->flags), but again the focal point here is how sdhci-uhs2.c
should be built as a module.

Please review this series (particularly Patch#8-#26 and #27) from this
viewpoint in the first place.
(Ben is working on 'host' side but there is no change on 'host' side
in this submission except a minor tweak.)

Thanks,
-Takahiro Akashi

-- original cover letter from v3 --
Summary
===
These patches[1] support UHS-II and fix GL9755 UHS-II compatibility.

About UHS-II, roughly deal with the following three parts:
1) A UHS-II detection and initialization:
- Host setup to support UHS-II (Section 3.13.1 Host Controller Setup Sequence
  [2]).
- Detect a UHS-II I/F (Section 3.13.2 Card Interface Detection Sequence[2]).
- In step(9) of Section 3.13.2 in [2], UHS-II initialization is include Section
  3.13.3 UHS-II Card Initialization and Section 3.13.4 UHS-II Setting Register
  Setup Sequence.

2) Send Legacy SD command through SD-TRAN
- Encapsulated SD packets are defined in SD-TRAN in order to ensure Legacy SD
  compatibility and preserve Legacy SD infrastructures (Section 7.1.1 Packet
  Types and Format Overview[3]).
- Host issue a UHS-II CCMD packet or a UHS-II DCMD (Section 3.13.5 UHS-II
  CCMD Packet issuing and Section 3.13.6 UHS-II DCMD Packet issuing[2]).

3) UHS-II Interrupt
- Except for UHS-II error interrupts, most interrupts share the original
  interrupt registers.

Patch structure
===
patch#1-#7: for core
patch#8-#17: for sdhci
patch#18-#21: for GL9755

Tests
=
Ran 'dd' command to evaluate the performance:
(SanDisk UHS-II card on GL9755 controller)
 ReadWrite
UHS-II disabled (UHS-I): 88.3MB/s 60.7MB/s
UHS-II enabled :  206MB/s   80MB/s

TODO

- replace some define with BIT macro

Reference
=
[1] https://gitlab.com/ben.chuang/linux-uhs2-gl9755.git
[2] SD Host Controller Simplified Specification 4.20
[3] UHS-II Simplified Addendum 1.02

Changes in v3 (Jul. 10, 2020)
* rebased to v5.8-rc4
* add copyright notice
* reorganize the patch set and split some commits into smaller ones
* separate uhs-2 headers from others
* correct wrong spellings
* fix most of checkpatch warnings/errors
* remove all k[cz]alloc() from the code
* guard sdhci-uhs2 specific code with
  'if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))'
* make sdhci-uhs2.c as a module
* trivial changes, including
  - rename back sdhci-core.c to sdhci.c
  - allow vendor code to disable uhs2 if v4_mode == 0
  in __sdhci_add_host()
  - merge uhs2_power_up() into mmc_power_up()
  - remove flag_uhs2 from mmc_attach_sd()
  - add function descriptions to EXPORT'ed functions
  - other minor code optimization

Changes in v2 (Jan. 9, 2020)
* rebased to v5.5-rc5

AKASHI Takahiro (23):
  mmc: core: UHS-II support, modify power-up sequence
  mmc: core: UHS-II support, skip set_chip_select()
  mmc: core: UHS-II support, skip TMODE setup in some cases
  mmc: core: UHS-II support, generate UHS-II SD command packet
  mmc: core: UHS-II support, set APP_CMD bit if necessary
  mmc: sdhci: add a kernel configuration for enabling UHS-II support
  mmc: sdhci: add UHS-II related definitions in headers
  mmc: sdhci: add UHS-II module
  mmc: sdhci-uhs2: dump UHS-II registers
  mmc: sdhci-uhs2: add reset function
  mmc: sdhci-uhs2: add set_power() to support vdd2
  mmc: sdhci-uhs2: skip signal_voltage_switch()
  mmc: sdhci-uhs2: add set_timeout()
  mmc: sdhci-uhs2: add set_ios()
  mmc: sdhci-uhs2: add detect_init() to detect the interface
  mmc: sdhci-uhs2: add clock operations
  mmc: sdhci-uhs2: add set_reg() to initialise the interface
  mmc: sdhci-uhs2: add request() and others
  mmc: sdhci-uhs2: add irq() and others
  mmc: sdhci-uhs2: add add_host() and others to set up the driver
  mmc: core: add post-mmc_attach_sd hook
  mmc: sdhci-pci: add UHS-II support framework
  mmc: sdhci-pci-gli: enable UHS-II mode for GL9755

Be

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-24 Thread AKASHI Takahiro
Ben,

On Fri, Sep 18, 2020 at 06:50:24PM +0800, Ben Chuang wrote:
> On Fri, Sep 18, 2020 at 2:38 PM AKASHI Takahiro
>  wrote:
> >
> > Adrian, Ben,
> >
> > Regarding _set_ios() function,
> >
> > On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> > > On 10/07/20 2:10 pm, Ben Chuang wrote:
> > > > From: Ben Chuang 
> > > >
> > > > In this commit, UHS-II related operations will be called via a function
> > > > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > > > a kernel module.
> > > > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> > > > and when the UHS-II module is loaded. Otherwise, all the functions
> > > > stay void.
> > > >
> > > > Signed-off-by: Ben Chuang 
> > > > Signed-off-by: AKASHI Takahiro 
> >
> >   (snip)
> >
> > > > @@ -2261,6 +2324,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > > mmc_ios *ios)
> > > >  {
> > > > struct sdhci_host *host = mmc_priv(mmc);
> > > > u8 ctrl;
> > > > +   u16 ctrl_2;
> > > >
> > > > if (ios->power_mode == MMC_POWER_UNDEFINED)
> > > > return;
> > > > @@ -2287,6 +2351,10 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > > mmc_ios *ios)
> > > > sdhci_enable_preset_value(host, false);
> > > >
> > > > if (!ios->clock || ios->clock != host->clock) {
> > > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > +   ios->timing == MMC_TIMING_UHS2)
> > > > +   host->timing = ios->timing;
> > > > +
> > > > host->ops->set_clock(host, ios->clock);
> > > > host->clock = ios->clock;
> > > >
> > > > @@ -2308,6 +2376,18 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > > mmc_ios *ios)
> > > > else
> > > > sdhci_set_power(host, ios->power_mode, ios->vdd);
> > > >
> > > > +   /* 4.0 host support */
> > > > +   if (host->version >= SDHCI_SPEC_400) {
> > > > +   /* UHS2 Support */
> > > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > +   host->mmc->flags & MMC_UHS2_SUPPORT &&
> > > > +   host->mmc->caps & MMC_CAP_UHS2) {
> > > > +   if (sdhci_uhs2_ops.do_set_ios)
> > > > +   sdhci_uhs2_ops.do_set_ios(host, ios);
> > > > +   return;
> > > > +   }
> > > > +   }
> > > > +
> > >
> > > Please look at using existing callbacks instead, maybe creating 
> > > uhs2_set_ios(), uhs2_set_clock(), uhs2_set_power()
> >
> > I think that we will create uhs2_set_ios() (and uhs2_set_power()
> > as we discussed on patch#15/21), but not uhs_set_clock().
> >
> > Since we have a hook only in struct mmc_host_ops, but not in struct
> > sdhci_ops, all the drivers who want to support UHS-II need to
> > set host->mmc_host_ops->set_ios to sdhci_uhs2_set_ios explicitly
> > in their own init (or probe) function.
> > (Again, sdhci_uhs2_set_ios() seems to be generic though.)
> >
> > Is this okay for you?
> > -> Adrian
> >
> > During refactoring the code, I found that sdhci_set_power() is called
> > twice in sdhci_set_ios():
> > sdhci_set_ios(host, power_mode, vdd1, -1); in sdhci_set_ios(), and
> > sdhci_set_ios(host, power_mode, vdd1, vdd2) in ush2_do_set_ios()
> >
> > Can you please confirm that those are redundant?
> 
> Yes, uhs2 set power is independent with uhs1.
> But set  uhs2 power process  should meet  uhs2 spec.

Can you elaborate a bit more about the last sentence, please?

What I meant above is that
 sdhci_set_ios(host, power_mode, vdd1, vdd2) in ush2_do_set_ios()

this code will 'set_power' both vdd and vdd2 anyway and so
 sdhci_set_ios(host, power_mode, vdd1, -1); in sdhci_set_ios(), and
is just redundant.


> > -> Ben
> >
> > I also wonder why we need spin locks in uhs2_do_set_ios() while
> > not in sdhci_set_ios().
> 
> You can check if  spin locks in uhs2_do_set_ios() is necessary.

I'm asking you.

While calling set_ios() doesn't require spin locks, are you aware of
any cases where we need spin locks in calling set_ios() for uhs-2?
(I mean that callers/contexts are the same either for uhs or uhs-2.)

-Takahiro Akashi

> If set/clear irq can be execute safely without spin locks, you can
> remove spin locks.
> 
> >
> > -> Ben
> >
> > -Takahiro Akashi


Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-24 Thread AKASHI Takahiro
Ben,

On Fri, Sep 18, 2020 at 06:27:01PM +0800, Ben Chuang wrote:
> On Fri, Sep 18, 2020 at 9:15 AM AKASHI Takahiro
>  wrote:
> >
> > Ben,
> >
> > On Thu, Sep 17, 2020 at 06:12:27PM +0800, Ben Chuang wrote:
> > > Hi Takahiro,
> > >
> > > On Thu, Sep 17, 2020 at 1:12 PM AKASHI Takahiro
> > >  wrote:
> > > >
> > > > Adrian, Ben,
> > > >
> > > > Regarding _reset() function,
> > > >
> > > > On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> > > > > On 10/07/20 2:10 pm, Ben Chuang wrote:
> > > > > > From: Ben Chuang 
> > > > > >
> > > > > > In this commit, UHS-II related operations will be called via a 
> > > > > > function
> > > > > > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > > > > > a kernel module.
> > > > > > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is 
> > > > > > enabled
> > > > > > and when the UHS-II module is loaded. Otherwise, all the functions
> > > > > > stay void.
> > > > > >
> > > > > > Signed-off-by: Ben Chuang 
> > > > > > Signed-off-by: AKASHI Takahiro 
> > > > > > ---
> > > > > >  drivers/mmc/host/sdhci.c | 152 
> > > > > > ++-
> > > > > >  1 file changed, 136 insertions(+), 16 deletions(-)
> > > > > >
> > > >
> > > >   (snip)
> > > >
> > > > > > if (host->ops->platform_send_init_74_clocks)
> > > > > > host->ops->platform_send_init_74_clocks(host, 
> > > > > > ios->power_mode);
> > > > > >
> > > > > > @@ -2331,7 +2411,7 @@ void sdhci_set_ios(struct mmc_host *mmc, 
> > > > > > struct mmc_ios *ios)
> > > > > > }
> > > > > >
> > > > > > if (host->version >= SDHCI_SPEC_300) {
> > > > > > -   u16 clk, ctrl_2;
> > > > > > +   u16 clk;
> > > > > >
> > > > > > if (!host->preset_enabled) {
> > > > > > sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
> > > > > > @@ -3173,11 +3253,19 @@ static bool sdhci_request_done(struct 
> > > > > > sdhci_host *host)
> > > > > > /* This is to force an update */
> > > > > > host->ops->set_clock(host, host->clock);
> > > > > >
> > > > > > -   /* Spec says we should do both at the same time, but 
> > > > > > Ricoh
> > > > > > -  controllers do not like that. */
> > > > > > -   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > > > > -   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > > > > -
> > > > > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > > > +   host->mmc->flags & MMC_UHS2_INITIALIZED) {
> > > > > > +   if (sdhci_uhs2_ops.reset)
> > > > > > +   sdhci_uhs2_ops.reset(host,
> > > > > > +
> > > > > > SDHCI_UHS2_SW_RESET_SD);
> > > > > > +   } else {
> > > > > > +   /*
> > > > > > +* Spec says we should do both at the same 
> > > > > > time, but
> > > > > > +* Ricoh controllers do not like that.
> > > > > > +*/
> > > > > > +   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > > > > +   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > > > > +   }
> > > > >
> > > > > Please look at using the existing ->reset() sdhci host op instead.
> > > >
> > > > Well, the second argument to those reset functions is a bit-wise value
> > > > to different "reset" registers, SDHCI_SOFTWARE_RESET and 
> > > > SDHCI_UHS2_SW_RESET,
> > > > respectively.
> > > >
> > > > This fact raises a couple of questions to me:
> > > >
> > 

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-24 Thread AKASHI Takahiro
Adrian,

This is, hopefully, my last reply to your comments on this patch#12.

Regarding _request() and _send_command() (and more),

On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:10 pm, Ben Chuang wrote:
> > From: Ben Chuang 
> > 
> > In this commit, UHS-II related operations will be called via a function
> > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > a kernel module.
> > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> > and when the UHS-II module is loaded. Otherwise, all the functions
> > stay void.
> > 
  (snip)

> Again, this is what I want to avoid.  I would like to have 3 kinds of 
> functions:
>   - SD mode only
>   - UHS-II only
>   - SD functions with no UHS-II code, that can also be used by UHS-II
> i.e. I don't want to mix UHS-II code and SD mode code in the same function.
> 
> I think sdhci-uhs2.c should provide a request function and a send_command 
> function.
> I would start by removing everything you may not need, and then see if you 
> have any problems.
> e.g.
> 
> void uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq)
> {
>   struct sdhci_host *host = mmc_priv(mmc);
>   struct mmc_command *cmd;
>   unsigned long flags;
> 
>   if (!host->uhs2_mode) {
>   sdhci_request(mmc, mrq);
>   return;
>   }
> 
>   spin_lock_irqsave(&host->lock, flags);
>   uhs2_send_command(host, cmd);
>   spin_unlock_irqrestore(&host->lock, flags);
> }
> EXPORT_SYMBOL_GPL(uhs2_request);
> 
> For sdhci_prepare_data(), I would factor out the dma part, so
> 
> static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command 
> *cmd)
> {
>   struct mmc_data *data = cmd->data;
> 
>   sdhci_initialize_data(host, data);
> 
>   sdhci_prepare_dma(host, data);
> 
>   sdhci_set_block_info(host, data);
> }
> 
> The you could export sdhci_initialize_data() and sdhci_prepare_dma() for uhs2.
> 
> >  }
> >  
> >  #if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
> > @@ -1439,6 +1463,13 @@ static void sdhci_set_transfer_mode(struct 
> > sdhci_host *host,
> > u16 mode = 0;
> > struct mmc_data *data = cmd->data;
> >  
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   host->mmc->flags & MMC_UHS2_SUPPORT) {
> > +   if (sdhci_uhs2_ops.set_transfer_mode)
> > +   sdhci_uhs2_ops.set_transfer_mode(host, cmd);
> > +   return;
> > +   }
> > +
> 
> Once you provide uhs2_request() and uhs2_send_command(), the transfer mode 
> setting can be done in sdhci-uhs2.c

If I try to make changes as you suggested above, a lot of other uhs2-flavored
functions will also be created due to calling dependency/sequences
and for "completeness" compared to uhs counterparts.
They probably include
sdhci_uhs2_prepare_data()
sdhci_uhs2_external_dma_prepare_data()
sdhci_uhs2_send_command()
sdhci_uhs2_send_command_try()
sdhci_uhs2_send_tuning()
sdhci_uhs2_request()
sdhci_uhs2_request_atomic()
sdhci_uhs2_thread_irq()
sdhci_uhs2_irq()
sdhci_uhs2_cmd_irq()
sdhci_uhs2_finish_command()
sdhci_uhs2_resume_host()
__sdhci_uhs2_add_host()
sdhci_uhs2_add_host()
(Some may not be used under the current drivers.)

In addition, a bunch of functions in sdhci.c will also have to be exported
to uhs2 as "global" functions instead of "static."

Is this all that you expect to see?

-Takahiro Akashi



> > if (data == NULL) {
> > if (host->quirks2 &
> > SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) {
> > @@ -1570,6 +1601,12 @@ static void __sdhci_finish_data(struct sdhci_host 
> > *host, bool sw_data_timeout)
> > else
> > data->bytes_xfered = data->blksz * data->blocks;
> >  
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   host->mmc->flags & MMC_UHS2_INITIALIZED) {
> > +   __sdhci_finish_mrq(host, data->mrq);
> > +   return;
> > +   }
> 
> At least to start with, I think it would be better to handle UHS-II cmd and 
> data interrupts completely in sdhci-uhs2.c
> 
> > +
> > /*
> >  * Need to send CMD12 if -
> >  * a) open-ended multiblock transfer not using auto CMD12 (no CMD23)
> > @@ -1654,7 +1691,8 @@ static bool sdhci_send_command(struct sdhci_host 
> > *host, struct mmc_command *cmd)
> > sdhci_prepare_data(host, cmd);
> > }
> >  
> > -   sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
> > +   if (!IS_ENABLED(CONFIG_MMC_SDHCI_UHS2))
> > +   sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
> 
> Not needed when instead you provide uhs2_send_command() 
> >  
> > sdhci_set_transfer_mode(host, cmd);
> >  
> > @@ -1699,6 +1737,17 @@ static bool sdhci_send_command(struct sdhci_host 
> > *host, struct mmc_command *cmd)
> > if (host->use_external_dma)
> > sdhci_external_dma_pre_transfer(host, cmd);
> >  
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   (host

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-17 Thread AKASHI Takahiro
Adrian, Ben,

Regarding _set_ios() function,

On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:10 pm, Ben Chuang wrote:
> > From: Ben Chuang 
> > 
> > In this commit, UHS-II related operations will be called via a function
> > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > a kernel module.
> > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> > and when the UHS-II module is loaded. Otherwise, all the functions
> > stay void.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 

  (snip)

> > @@ -2261,6 +2324,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > mmc_ios *ios)
> >  {
> > struct sdhci_host *host = mmc_priv(mmc);
> > u8 ctrl;
> > +   u16 ctrl_2;
> >  
> > if (ios->power_mode == MMC_POWER_UNDEFINED)
> > return;
> > @@ -2287,6 +2351,10 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > mmc_ios *ios)
> > sdhci_enable_preset_value(host, false);
> >  
> > if (!ios->clock || ios->clock != host->clock) {
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   ios->timing == MMC_TIMING_UHS2)
> > +   host->timing = ios->timing;
> > +
> > host->ops->set_clock(host, ios->clock);
> > host->clock = ios->clock;
> >  
> > @@ -2308,6 +2376,18 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > mmc_ios *ios)
> > else
> > sdhci_set_power(host, ios->power_mode, ios->vdd);
> >  
> > +   /* 4.0 host support */
> > +   if (host->version >= SDHCI_SPEC_400) {
> > +   /* UHS2 Support */
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   host->mmc->flags & MMC_UHS2_SUPPORT &&
> > +   host->mmc->caps & MMC_CAP_UHS2) {
> > +   if (sdhci_uhs2_ops.do_set_ios)
> > +   sdhci_uhs2_ops.do_set_ios(host, ios);
> > +   return;
> > +   }
> > +   }
> > +
> 
> Please look at using existing callbacks instead, maybe creating 
> uhs2_set_ios(), uhs2_set_clock(), uhs2_set_power()

I think that we will create uhs2_set_ios() (and uhs2_set_power()
as we discussed on patch#15/21), but not uhs_set_clock().

Since we have a hook only in struct mmc_host_ops, but not in struct
sdhci_ops, all the drivers who want to support UHS-II need to
set host->mmc_host_ops->set_ios to sdhci_uhs2_set_ios explicitly
in their own init (or probe) function.
(Again, sdhci_uhs2_set_ios() seems to be generic though.)

Is this okay for you?
-> Adrian

During refactoring the code, I found that sdhci_set_power() is called
twice in sdhci_set_ios():
sdhci_set_ios(host, power_mode, vdd1, -1); in sdhci_set_ios(), and
sdhci_set_ios(host, power_mode, vdd1, vdd2) in ush2_do_set_ios()

Can you please confirm that those are redundant?
-> Ben

I also wonder why we need spin locks in uhs2_do_set_ios() while
not in sdhci_set_ios().

-> Ben

-Takahiro Akashi


Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-17 Thread AKASHI Takahiro
Ben,

On Thu, Sep 17, 2020 at 06:12:27PM +0800, Ben Chuang wrote:
> Hi Takahiro,
> 
> On Thu, Sep 17, 2020 at 1:12 PM AKASHI Takahiro
>  wrote:
> >
> > Adrian, Ben,
> >
> > Regarding _reset() function,
> >
> > On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> > > On 10/07/20 2:10 pm, Ben Chuang wrote:
> > > > From: Ben Chuang 
> > > >
> > > > In this commit, UHS-II related operations will be called via a function
> > > > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > > > a kernel module.
> > > > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> > > > and when the UHS-II module is loaded. Otherwise, all the functions
> > > > stay void.
> > > >
> > > > Signed-off-by: Ben Chuang 
> > > > Signed-off-by: AKASHI Takahiro 
> > > > ---
> > > >  drivers/mmc/host/sdhci.c | 152 ++-
> > > >  1 file changed, 136 insertions(+), 16 deletions(-)
> > > >
> >
> >   (snip)
> >
> > > > if (host->ops->platform_send_init_74_clocks)
> > > > host->ops->platform_send_init_74_clocks(host, 
> > > > ios->power_mode);
> > > >
> > > > @@ -2331,7 +2411,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > > > mmc_ios *ios)
> > > > }
> > > >
> > > > if (host->version >= SDHCI_SPEC_300) {
> > > > -   u16 clk, ctrl_2;
> > > > +   u16 clk;
> > > >
> > > > if (!host->preset_enabled) {
> > > > sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
> > > > @@ -3173,11 +3253,19 @@ static bool sdhci_request_done(struct 
> > > > sdhci_host *host)
> > > > /* This is to force an update */
> > > > host->ops->set_clock(host, host->clock);
> > > >
> > > > -   /* Spec says we should do both at the same time, but Ricoh
> > > > -  controllers do not like that. */
> > > > -   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > > -   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > > -
> > > > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > +   host->mmc->flags & MMC_UHS2_INITIALIZED) {
> > > > +   if (sdhci_uhs2_ops.reset)
> > > > +   sdhci_uhs2_ops.reset(host,
> > > > +
> > > > SDHCI_UHS2_SW_RESET_SD);
> > > > +   } else {
> > > > +   /*
> > > > +* Spec says we should do both at the same time, but
> > > > +* Ricoh controllers do not like that.
> > > > +*/
> > > > +   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > > > +   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > > > +   }
> > >
> > > Please look at using the existing ->reset() sdhci host op instead.
> >
> > Well, the second argument to those reset functions is a bit-wise value
> > to different "reset" registers, SDHCI_SOFTWARE_RESET and 
> > SDHCI_UHS2_SW_RESET,
> > respectively.
> >
> > This fact raises a couple of questions to me:
> >
> > 1) Does it make sense to merge two functionality into one, i.e.
> >sdhci_do_reset(), which is set to call ->reset hook?
> >
> > -> Adrian
> >
> > 2) UHS2_SW_RESET_SD is done only at this place while there are many 
> > callsites
> >of reset(RESET_CMD|RESET_DATA) in sdhci.c.
> >Why does the current code work?
> >
> >I found, in sdhci-pci-gli.c,
> >sdhci_gl9755_reset()
> > /* reset sd-tran on UHS2 mode if need to reset cmd/data */
> > if ((mask & SDHCI_RESET_CMD) | (mask & SDHCI_RESET_DATA))
> > gl9755_uhs2_reset_sd_tran(host);

(A)

> >
> >Is this the trick to avoid the issue?
> >(It looks redundant in terms of the hack above in sdhci_request_done()
> >and even quite dirty to me. Moreover, no corresponding code for gl9750
> >and gl9763.)
> 
> GL9755 currently does SD reset and UHS-II reset together.

Do you mean that, in UHS-II operations, you need only the reset on
SDHCI_

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-16 Thread AKASHI Takahiro
On Thu, Sep 17, 2020 at 07:52:03AM +0300, Adrian Hunter wrote:
> On 17/09/20 5:31 am, AKASHI Takahiro wrote:
> > Adrian,
> > 
> > On Wed, Sep 16, 2020 at 01:00:35PM +0300, Adrian Hunter wrote:
> >> On 16/09/20 11:05 am, AKASHI Takahiro wrote:
> >>> Adrian,
> >>>
> >>> Your comments are scattered over various functions, and so
> >>> I would like to address them in separate replies.
> >>>
> >>> First, I'd like to discuss sdhci_[add|remove]_host().
> >>>
> >>> On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> >>>> On 10/07/20 2:10 pm, Ben Chuang wrote:
> >>>>> From: Ben Chuang 
> >>>>>
> >>>>> In this commit, UHS-II related operations will be called via a function
> >>>>> pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> >>>>> a kernel module.
> >>>>> This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> >>>>> and when the UHS-II module is loaded. Otherwise, all the functions
> >>>>> stay void.
> >>>>>
> >>>>> Signed-off-by: Ben Chuang 
> >>>>> Signed-off-by: AKASHI Takahiro 
> >>>>> ---
> >>>
> >>>  (snip)
> >>>
> >>>>> if (intmask & (SDHCI_INT_CARD_INSERT | 
> >>>>> SDHCI_INT_CARD_REMOVE)) {
> >>>>> u32 present = sdhci_readl(host, 
> >>>>> SDHCI_PRESENT_STATE) &
> >>>>>   SDHCI_CARD_PRESENT;
> >>>>> @@ -4717,6 +4812,14 @@ int sdhci_setup_host(struct sdhci_host *host)
> >>>>> /* This may alter mmc->*_blk_* parameters */
> >>>>> sdhci_allocate_bounce_buffer(host);
> >>>>>  
> >>>>> +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> >>>>> +   host->version >= SDHCI_SPEC_400 &&
> >>>>> +   sdhci_uhs2_ops.add_host) {
> >>>>> +   ret = sdhci_uhs2_ops.add_host(host, host->caps1);
> >>>>> +   if (ret)
> >>>>> +   goto unreg;
> >>>>> +   }
> >>>>> +
> >>>>
> >>>> I think you should look at creating uhs2_add_host() instead
> >>>>
> >>>>> return 0;
> >>>>>  
> >>>>>  unreg:
> >>>>> @@ -4738,6 +4841,8 @@ void sdhci_cleanup_host(struct sdhci_host *host)
> >>>>>  {
> >>>>> struct mmc_host *mmc = host->mmc;
> >>>>>  
> >>>>> +   /* FIXME: Do we have to do some cleanup for UHS2 here? */
> >>>>> +
> >>>>> if (!IS_ERR(mmc->supply.vqmmc))
> >>>>> regulator_disable(mmc->supply.vqmmc);
> >>>>>  
> >>>>> @@ -4766,6 +4871,14 @@ int __sdhci_add_host(struct sdhci_host *host)
> >>>>> mmc->cqe_ops = NULL;
> >>>>> }
> >>>>>  
> >>>>> +   if ((mmc->caps & MMC_CAP_UHS2) && !host->v4_mode) {
> >>>>> +   /* host doesn't want to enable UHS2 support */
> >>>>> +   mmc->caps &= ~MMC_CAP_UHS2;
> >>>>> +   mmc->flags &= ~MMC_UHS2_SUPPORT;
> >>>>> +
> >>>>> +   /* FIXME: Do we have to do some cleanup here? */
> >>>>> +   }
> >>>>> +
> >>>>> host->complete_wq = alloc_workqueue("sdhci", flags, 0);
> >>>>> if (!host->complete_wq)
> >>>>> return -ENOMEM;
> >>>>> @@ -4812,6 +4925,9 @@ int __sdhci_add_host(struct sdhci_host *host)
> >>>>>  unled:
> >>>>> sdhci_led_unregister(host);
> >>>>>  unirq:
> >>>>> +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> >>>>> +   sdhci_uhs2_ops.remove_host)
> >>>>> +   sdhci_uhs2_ops.remove_host(host, 0);
> >>>>> sdhci_do_reset(host, SDHCI_RESET_ALL);
> >>>>> sdhci_writel(host, 0, SDHCI_INT_ENABLE);
> >>&

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-16 Thread AKASHI Takahiro
Adrian, Ben,

Regarding _reset() function,

On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:10 pm, Ben Chuang wrote:
> > From: Ben Chuang 
> > 
> > In this commit, UHS-II related operations will be called via a function
> > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > a kernel module.
> > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> > and when the UHS-II module is loaded. Otherwise, all the functions
> > stay void.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci.c | 152 ++-
> >  1 file changed, 136 insertions(+), 16 deletions(-)
> > 

  (snip)

> > if (host->ops->platform_send_init_74_clocks)
> > host->ops->platform_send_init_74_clocks(host, ios->power_mode);
> >  
> > @@ -2331,7 +2411,7 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > mmc_ios *ios)
> > }
> >  
> > if (host->version >= SDHCI_SPEC_300) {
> > -   u16 clk, ctrl_2;
> > +   u16 clk;
> >  
> > if (!host->preset_enabled) {
> > sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
> > @@ -3173,11 +3253,19 @@ static bool sdhci_request_done(struct sdhci_host 
> > *host)
> > /* This is to force an update */
> > host->ops->set_clock(host, host->clock);
> >  
> > -   /* Spec says we should do both at the same time, but Ricoh
> > -  controllers do not like that. */
> > -   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > -   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > -
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   host->mmc->flags & MMC_UHS2_INITIALIZED) {
> > +   if (sdhci_uhs2_ops.reset)
> > +   sdhci_uhs2_ops.reset(host,
> > +SDHCI_UHS2_SW_RESET_SD);
> > +   } else {
> > +   /*
> > +* Spec says we should do both at the same time, but
> > +* Ricoh controllers do not like that.
> > +*/
> > +   sdhci_do_reset(host, SDHCI_RESET_CMD);
> > +   sdhci_do_reset(host, SDHCI_RESET_DATA);
> > +   }
> 
> Please look at using the existing ->reset() sdhci host op instead.

Well, the second argument to those reset functions is a bit-wise value
to different "reset" registers, SDHCI_SOFTWARE_RESET and SDHCI_UHS2_SW_RESET,
respectively.

This fact raises a couple of questions to me:

1) Does it make sense to merge two functionality into one, i.e.
   sdhci_do_reset(), which is set to call ->reset hook?

-> Adrian

2) UHS2_SW_RESET_SD is done only at this place while there are many callsites
   of reset(RESET_CMD|RESET_DATA) in sdhci.c.
   Why does the current code work?

   I found, in sdhci-pci-gli.c,
   sdhci_gl9755_reset()
/* reset sd-tran on UHS2 mode if need to reset cmd/data */
if ((mask & SDHCI_RESET_CMD) | (mask & SDHCI_RESET_DATA))
gl9755_uhs2_reset_sd_tran(host);

   Is this the trick to avoid the issue?
   (It looks redundant in terms of the hack above in sdhci_request_done()
   and even quite dirty to me. Moreover, no corresponding code for gl9750
   and gl9763.)

-> Ben

3) (More or less SD specification issue)
   In UHS-II mode, do we have to call reset(SHCI_RESET_ALL) along with
   reset(UHS2_SW_RESET_FULL)?
   Under the current implementation, both will be called at the end.

-> Adrian, Ben

4) (Not directly linked to UHS-II support)
  In some places, we see the sequence:
sdhci_do_reset(host, SDHCI_RESET_CMD);
sdhci_do_reset(host, SDHCI_RESET_DATA);
  while in other places,
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);

  If the statement below is true,
> > -   /* Spec says we should do both at the same time, but Ricoh
> > -  controllers do not like that. */
  the latter should be wrong.

-> Adrian

-Takahiro Akashi



> > host->pending_reset = false;
> > }
> >  
> > @@ -3532,6 +3620,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
> >   SDHCI_INT_BUS_POWER);
> > sdhci_writel(host, mask, SDHCI_INT_STATUS);
> >  
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   intmask & SDHCI_INT_ERROR &&
> > +   

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-16 Thread AKASHI Takahiro
Adrian,

On Wed, Sep 16, 2020 at 01:00:35PM +0300, Adrian Hunter wrote:
> On 16/09/20 11:05 am, AKASHI Takahiro wrote:
> > Adrian,
> > 
> > Your comments are scattered over various functions, and so
> > I would like to address them in separate replies.
> > 
> > First, I'd like to discuss sdhci_[add|remove]_host().
> > 
> > On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> >> On 10/07/20 2:10 pm, Ben Chuang wrote:
> >>> From: Ben Chuang 
> >>>
> >>> In this commit, UHS-II related operations will be called via a function
> >>> pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> >>> a kernel module.
> >>> This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> >>> and when the UHS-II module is loaded. Otherwise, all the functions
> >>> stay void.
> >>>
> >>> Signed-off-by: Ben Chuang 
> >>> Signed-off-by: AKASHI Takahiro 
> >>> ---
> > 
> >  (snip)
> > 
> >>>   if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
> >>>   u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
> >>> SDHCI_CARD_PRESENT;
> >>> @@ -4717,6 +4812,14 @@ int sdhci_setup_host(struct sdhci_host *host)
> >>>   /* This may alter mmc->*_blk_* parameters */
> >>>   sdhci_allocate_bounce_buffer(host);
> >>>  
> >>> + if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> >>> + host->version >= SDHCI_SPEC_400 &&
> >>> + sdhci_uhs2_ops.add_host) {
> >>> + ret = sdhci_uhs2_ops.add_host(host, host->caps1);
> >>> + if (ret)
> >>> + goto unreg;
> >>> + }
> >>> +
> >>
> >> I think you should look at creating uhs2_add_host() instead
> >>
> >>>   return 0;
> >>>  
> >>>  unreg:
> >>> @@ -4738,6 +4841,8 @@ void sdhci_cleanup_host(struct sdhci_host *host)
> >>>  {
> >>>   struct mmc_host *mmc = host->mmc;
> >>>  
> >>> + /* FIXME: Do we have to do some cleanup for UHS2 here? */
> >>> +
> >>>   if (!IS_ERR(mmc->supply.vqmmc))
> >>>   regulator_disable(mmc->supply.vqmmc);
> >>>  
> >>> @@ -4766,6 +4871,14 @@ int __sdhci_add_host(struct sdhci_host *host)
> >>>   mmc->cqe_ops = NULL;
> >>>   }
> >>>  
> >>> + if ((mmc->caps & MMC_CAP_UHS2) && !host->v4_mode) {
> >>> + /* host doesn't want to enable UHS2 support */
> >>> + mmc->caps &= ~MMC_CAP_UHS2;
> >>> + mmc->flags &= ~MMC_UHS2_SUPPORT;
> >>> +
> >>> + /* FIXME: Do we have to do some cleanup here? */
> >>> + }
> >>> +
> >>>   host->complete_wq = alloc_workqueue("sdhci", flags, 0);
> >>>   if (!host->complete_wq)
> >>>   return -ENOMEM;
> >>> @@ -4812,6 +4925,9 @@ int __sdhci_add_host(struct sdhci_host *host)
> >>>  unled:
> >>>   sdhci_led_unregister(host);
> >>>  unirq:
> >>> + if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> >>> + sdhci_uhs2_ops.remove_host)
> >>> + sdhci_uhs2_ops.remove_host(host, 0);
> >>>   sdhci_do_reset(host, SDHCI_RESET_ALL);
> >>>   sdhci_writel(host, 0, SDHCI_INT_ENABLE);
> >>>   sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
> >>> @@ -4869,6 +4985,10 @@ void sdhci_remove_host(struct sdhci_host *host, 
> >>> int dead)
> >>>  
> >>>   sdhci_led_unregister(host);
> >>>  
> >>> + if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> >>> + sdhci_uhs2_ops.remove_host)
> >>> + sdhci_uhs2_ops.remove_host(host, dead);
> >>> +
> >>
> >> I think you should look at creating uhs2_remove_host() instead
> > 
> > You suggest that we will have separate sdhci_uhs2_[add|remove]_host(),
> > but I don't think it's always convenient.
> > 
> > UHS-II capable host will be set to call sdhci_uhs2_add_host() explicitly,
> > but we can't do that in case of pci and pltfm based drivers as they utilize
> > common helper functions, sdhci_pci_probe() and sdhci_pltfm_register(),
> > respectively.
> 
> sdhci-pci has an add_host op
> 
> sdhci_pltfm_init can be used instead of sdhci_pltfm_register
> 
> 
> > Therefore, we inevitably have to call sdhci_uhs2_add_host() there.
> > 
> > If so, why should we distinguish sdhci_uhs2_add_host from 
> > sdhci_uhs_add_host?
> > I don't see any good reason.
> > Moreover, as a result, there exists a mixed usage of sdhci_ interfaces
> > and sdhci_uhs2_ interfaces in sdhci-pci-core.c and sdhci-pltfm.c.
> > 
> > It sounds odd to me.
> 
> It is already done that way for cqhci.

Okay, if it is your policy, I will follow that.
Then, I'm going to add
- remove_host field to struct sdhci_pci_fixes
- a controller specific helper function to each driver (only pci-gli for now)
  even though it looks quite generic.

  sdhci_gli_[add|remove]_host(struct sdhci_pci_slot *slot)
  {
  return sdhci_uhs2_[add|remove]_host(slot->host);
  }

# Or do you want to create a file like sdhci-uhs2-pci.c for those functions?

-Takahiro Akashi

> > 
> > -Takahiro Akashi
> > 
> > 
> >>
> >>>   if (!dead)
> >>>   sdhci_do_reset(host, SDHCI_RESET_ALL);
> >>>  
> >>>
> >>
> 


Re: [RFC PATCH V3 13/21] mmc: sdhci: UHS-II support, skip signal_voltage_switch()

2020-09-16 Thread AKASHI Takahiro
Ben,

On Wed, Sep 16, 2020 at 05:42:07PM +0800, Ben Chuang wrote:
> On Wed, Sep 16, 2020 at 8:52 AM AKASHI Takahiro
>  wrote:
> >
> > On Tue, Sep 15, 2020 at 07:36:14PM +0800, Ben Chuang wrote:
> > > Hi Takahiro,
> > >
> > > On Tue, Sep 15, 2020 at 2:03 PM AKASHI Takahiro
> > >  wrote:
> > > >
> > > > Ben, Adrian,
> > > >
> > > > On Mon, Sep 14, 2020 at 11:08:14AM +0300, Adrian Hunter wrote:
> > > > > On 14/09/20 9:40 am, AKASHI Takahiro wrote:
> > > > > > Adrian,
> > > > > >
> > > > > > On Fri, Aug 21, 2020 at 05:09:01PM +0300, Adrian Hunter wrote:
> > > > > >> On 10/07/20 2:11 pm, Ben Chuang wrote:
> > > > > >>> From: AKASHI Takahiro 
> > > > > >>>
> > > > > >>> sdhci_start_signal_voltage_switch() should be called only in 
> > > > > >>> UHS-I mode,
> > > > > >>> and not for UHS-II mode.
> > > > > >>>
> > > > > >>> Signed-off-by: Ben Chuang 
> > > > > >>> Signed-off-by: AKASHI Takahiro 
> > > > > >>> ---
> > > > > >>>  drivers/mmc/host/sdhci.c | 7 ++-
> > > > > >>>  1 file changed, 6 insertions(+), 1 deletion(-)
> > > > > >>>
> > > > > >>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > > > > >>> index 5511649946b9..7f2537648a08 100644
> > > > > >>> --- a/drivers/mmc/host/sdhci.c
> > > > > >>> +++ b/drivers/mmc/host/sdhci.c
> > > > > >>> @@ -2623,8 +2623,13 @@ int 
> > > > > >>> sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
> > > > > >>>   /*
> > > > > >>>* Signal Voltage Switching is only applicable for Host 
> > > > > >>> Controllers
> > > > > >>>* v3.00 and above.
> > > > > >>> +  * But for UHS2, the signal voltage is supplied by vdd2 which is
> > > > > >>> +  * already 1.8v so no voltage switch required.
> > > >
> > > > I have been confused with this comment.
> > > > (I know it came from the original Intel code, not from Ben.)
> > > >
> > > > If this comment is true,
> > > >
> > > > > >>>*/
> > > > > >>> - if (host->version < SDHCI_SPEC_300)
> > > > > >>> + if (host->version < SDHCI_SPEC_300 ||
> > > > > >>> + (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > > > >>> +  host->version >= SDHCI_SPEC_400 &&
> > > > > >>> +  host->mmc->flags & MMC_UHS2_SUPPORT))
> > > >
> > > > the condition above must be wrong since 'flags & MMC_UHS2_SUPPORT'
> > > > is one of capabilities for a host controller, not a card
> > > > while the selection of voltage depends on a card type.
> > >
> > > The flag MMC_UHS2_SUPPORT is set at the beginning of 
> > > mmc_uhs2_rescan_try_freq().
> > > In UHS-II flow, it stays set.
> > > If the attempt to UHS-II fails finally, it will be unset.
> >
> > Right, but MMC_UHS2_SUPPORT is also set, at least initially,
> > in sdhci_uhs2_add_host(). It is confusing, isn't it?
> 
> I think it can be removed from sdhci_uhs2_add_host() to avoid making 
> confusion.

Okay,

> >
> > As we discussed before, any card-specific properties, like UHS-II mode,
> > should be placed in a card structure, not a host structure.

Do you have any idea on this?
I remember that Ulf also made a similar comment on the "core" side.

-Takahiro Akashi

> >
> > > >
> > > > So I wonder why this code still works.
> > > > I guess that it is because set_signal_voltage(), or other variant 
> > > > functions,
> > > > will never be called for UHS-II cards under the current implementation.
> > > >
> > > > Looking at mmc_sd_init_card(), we have added some hack:
> > > > mmc_sd_init_card()
> > > > {
> > > > ...
> > > > /* For UHS2, skip the UHS-I initialization. */
> > > > if ((host->flags & MMC_UHS2_SUPPORT) &&
> > > > (host->flags & MMC_UHS2_INITIALIZED))
> > > >  

Re: [RFC PATCH V3 12/21] mmc: sdhci: UHS-II support, add hooks for additional operations

2020-09-16 Thread AKASHI Takahiro
Adrian,

Your comments are scattered over various functions, and so
I would like to address them in separate replies.

First, I'd like to discuss sdhci_[add|remove]_host().

On Fri, Aug 21, 2020 at 05:08:32PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:10 pm, Ben Chuang wrote:
> > From: Ben Chuang 
> > 
> > In this commit, UHS-II related operations will be called via a function
> > pointer array, sdhci_uhs2_ops, in order to make UHS-II support as
> > a kernel module.
> > This array will be initialized only if CONFIG_MMC_SDHCI_UHS2 is enabled
> > and when the UHS-II module is loaded. Otherwise, all the functions
> > stay void.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---

 (snip)

> > if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
> > u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
> >   SDHCI_CARD_PRESENT;
> > @@ -4717,6 +4812,14 @@ int sdhci_setup_host(struct sdhci_host *host)
> > /* This may alter mmc->*_blk_* parameters */
> > sdhci_allocate_bounce_buffer(host);
> >  
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   host->version >= SDHCI_SPEC_400 &&
> > +   sdhci_uhs2_ops.add_host) {
> > +   ret = sdhci_uhs2_ops.add_host(host, host->caps1);
> > +   if (ret)
> > +   goto unreg;
> > +   }
> > +
> 
> I think you should look at creating uhs2_add_host() instead
> 
> > return 0;
> >  
> >  unreg:
> > @@ -4738,6 +4841,8 @@ void sdhci_cleanup_host(struct sdhci_host *host)
> >  {
> > struct mmc_host *mmc = host->mmc;
> >  
> > +   /* FIXME: Do we have to do some cleanup for UHS2 here? */
> > +
> > if (!IS_ERR(mmc->supply.vqmmc))
> > regulator_disable(mmc->supply.vqmmc);
> >  
> > @@ -4766,6 +4871,14 @@ int __sdhci_add_host(struct sdhci_host *host)
> > mmc->cqe_ops = NULL;
> > }
> >  
> > +   if ((mmc->caps & MMC_CAP_UHS2) && !host->v4_mode) {
> > +   /* host doesn't want to enable UHS2 support */
> > +   mmc->caps &= ~MMC_CAP_UHS2;
> > +   mmc->flags &= ~MMC_UHS2_SUPPORT;
> > +
> > +   /* FIXME: Do we have to do some cleanup here? */
> > +   }
> > +
> > host->complete_wq = alloc_workqueue("sdhci", flags, 0);
> > if (!host->complete_wq)
> > return -ENOMEM;
> > @@ -4812,6 +4925,9 @@ int __sdhci_add_host(struct sdhci_host *host)
> >  unled:
> > sdhci_led_unregister(host);
> >  unirq:
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   sdhci_uhs2_ops.remove_host)
> > +   sdhci_uhs2_ops.remove_host(host, 0);
> > sdhci_do_reset(host, SDHCI_RESET_ALL);
> > sdhci_writel(host, 0, SDHCI_INT_ENABLE);
> > sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
> > @@ -4869,6 +4985,10 @@ void sdhci_remove_host(struct sdhci_host *host, int 
> > dead)
> >  
> > sdhci_led_unregister(host);
> >  
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   sdhci_uhs2_ops.remove_host)
> > +   sdhci_uhs2_ops.remove_host(host, dead);
> > +
> 
> I think you should look at creating uhs2_remove_host() instead

You suggest that we will have separate sdhci_uhs2_[add|remove]_host(),
but I don't think it's always convenient.

UHS-II capable host will be set to call sdhci_uhs2_add_host() explicitly,
but we can't do that in case of pci and pltfm based drivers as they utilize
common helper functions, sdhci_pci_probe() and sdhci_pltfm_register(),
respectively.
Therefore, we inevitably have to call sdhci_uhs2_add_host() there.

If so, why should we distinguish sdhci_uhs2_add_host from sdhci_uhs_add_host?
I don't see any good reason.
Moreover, as a result, there exists a mixed usage of sdhci_ interfaces
and sdhci_uhs2_ interfaces in sdhci-pci-core.c and sdhci-pltfm.c.

It sounds odd to me.

-Takahiro Akashi


> 
> > if (!dead)
> > sdhci_do_reset(host, SDHCI_RESET_ALL);
> >  
> > 
> 


Re: [RFC PATCH V3 15/21] mmc: sdhci: UHS-II support, modify set_power() to handle vdd2

2020-09-16 Thread AKASHI Takahiro
Adrian,

On Wed, Sep 16, 2020 at 09:42:28AM +0300, Adrian Hunter wrote:
> On 15/09/20 9:24 am, AKASHI Takahiro wrote:
> > Adrain,
> > 
> > On Mon, Sep 14, 2020 at 09:36:02AM +0300, Adrian Hunter wrote:
> >> On 14/09/20 8:45 am, AKASHI Takahiro wrote:
> >>> Adrian,
> >>>
> >>> On Fri, Aug 21, 2020 at 05:11:18PM +0300, Adrian Hunter wrote:
> >>>> On 10/07/20 2:11 pm, Ben Chuang wrote:
> >>>>> From: AKASHI Takahiro 
> >>>>>
> >>>>> VDD2 is used for powering UHS-II interface.
> >>>>> Modify sdhci_set_power_and_bus_voltage(), sdhci_set_power_noreg()
> >>>>> and sdhci_set_power_noreg() to handle VDD2.
> >>>>
> >>>> vdd2 is always 1.8 V and I suspect there may never be support for 
> >>>> anything
> >>>> else, so we should start with 1.8 V only.
> >>>
> >>> What do you mean here?
> >>> You don't want to add an extra argument, vdd2, to sdhci_set_power().
> >>> Correct?
> >>
> >> Yes
> >>
> >>>
> >>>> Also can we create uhs2_set_power_reg() and uhs2_set_power_noreg() and 
> >>>> use
> >>>> the existing ->set_power() callback
> >>>
> >>> Again what do you expect here?
> >>>
> >>> Do you want to see any platform-specific mmc driver who supports UHS-II
> >>> to implement its own call back like:
> >>
> >> Not exactly.  I expect there to be a common implementation in sdhci-uhs2.c
> >> called sdhci_uhs2_set_power() for example, that drivers can use by setting
> >> their .set_power = sdhci_uhs2_set_power.  If they need platform-specific
> >> code as well then their platform-specific code can call
> >> sdhci_uhs2_set_power() if desired.
> >>
> >>>
> >>> void sdhci_foo_set_power(struct sdhci_host *host, unsigned char mode,
> >>>   unsigned short vdd)
> >>> {
> >>> sdhci_set_power(host, mode,vdd);
> >>>
> >>> /* in case that sdhci_uhs2 module is not inserted */
> >>> if (!(mmc->caps & MMC_CAP_UHS2))
> >>> return;
> >>>
> >>> /* vdd2 specific operation */
> >>> if (IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
> >>> sdhci_uhs2_set_power_noreg(host, mode);
> >>> else
> >>> sdhci_uhs2_set_power_reg(host, mode);
> >>>
> >>> /* maybe more platform-specific initialization */
> >>> }
> >>>
> >>> struct sdhci_ops sdhci_foo_ops = {
> >>> .set_power = sdhci_foo_set_power,
> >>> ...
> >>> }
> > 
> > What do you think about this logic in general?
> > (If necessary, read it replacing "foo" to "uhs2".)
> > 
> > What I'm concerned about is SDHCI_POWER_CONTROL register.
> > Vdd and vdd2 are controlled with corresponding bits in this register.
> > It seems to be "natural" to me that vdd and vdd2 are enabled
> > in a single function rather than putting them in separate ones.
> > 
> > In particular, in the case of sdhci_set_power_noreg(), there exist a couple
> > of "quirks" around writing the bits to SDHCI_POWER_CONTROL register.
> 
> We can treat UHS-II support as being for new hardware and therefore
> we don't necessarily need to support old quirks.  Just make sure if
> a quirk is not being supported, to add a comment to that effect.
> 
> > I don't know how we should handle them if we have a separate function,
> > say, sdhci_uhs2_set_power_noreg().
> > Do you want to see a copy of the same logic in 
> > sdhci_uhs2_set_power_noreg()? 
> 
> I would probably consider making another function that non-UHS-II
> drivers do not need to care about e.g. existing drivers can keep using
> sdhci_set_power_noreg() and sdhci_uhs2 can call __sdhci_set_power_noreg()

Well, but


> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 592a55a34b58..ffe54f06fe38 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -2013,8 +2013,8 @@ static void sdhci_set_power_reg(struct sdhci_host 
> *host, unsigned char mode,
>   sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
>  }
>  
> -void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
> -unsi

Re: [RFC PATCH V3 13/21] mmc: sdhci: UHS-II support, skip signal_voltage_switch()

2020-09-15 Thread AKASHI Takahiro
On Wed, Sep 16, 2020 at 09:01:20AM +0300, Adrian Hunter wrote:
> On 15/09/20 9:03 am, AKASHI Takahiro wrote:
> > Ben, Adrian,
> > 
> > On Mon, Sep 14, 2020 at 11:08:14AM +0300, Adrian Hunter wrote:
> >> On 14/09/20 9:40 am, AKASHI Takahiro wrote:
> >>> Adrian,
> >>>
> >>> On Fri, Aug 21, 2020 at 05:09:01PM +0300, Adrian Hunter wrote:
> >>>> On 10/07/20 2:11 pm, Ben Chuang wrote:
> >>>>> From: AKASHI Takahiro 
> >>>>>
> >>>>> sdhci_start_signal_voltage_switch() should be called only in UHS-I mode,
> >>>>> and not for UHS-II mode.
> >>>>>
> >>>>> Signed-off-by: Ben Chuang 
> >>>>> Signed-off-by: AKASHI Takahiro 
> >>>>> ---
> >>>>>  drivers/mmc/host/sdhci.c | 7 ++-
> >>>>>  1 file changed, 6 insertions(+), 1 deletion(-)
> >>>>>
> >>>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> >>>>> index 5511649946b9..7f2537648a08 100644
> >>>>> --- a/drivers/mmc/host/sdhci.c
> >>>>> +++ b/drivers/mmc/host/sdhci.c
> >>>>> @@ -2623,8 +2623,13 @@ int sdhci_start_signal_voltage_switch(struct 
> >>>>> mmc_host *mmc,
> >>>>> /*
> >>>>>  * Signal Voltage Switching is only applicable for Host 
> >>>>> Controllers
> >>>>>  * v3.00 and above.
> >>>>> +* But for UHS2, the signal voltage is supplied by vdd2 which is
> >>>>> +* already 1.8v so no voltage switch required.
> >>>>>  */
> >>>>> -   if (host->version < SDHCI_SPEC_300)
> >>>>> +   if (host->version < SDHCI_SPEC_300 ||
> >>>>> +   (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> >>>>> +host->version >= SDHCI_SPEC_400 &&
> >>>>> +host->mmc->flags & MMC_UHS2_SUPPORT))
> >>>> Please look at hooking ->start_signal_voltage_switch() instead
> >>>
> >>> Do you mean that you want every platform driver who wants to support 
> >>> UHS-II
> >>> to set NULL to start_signal_voltage_switch hook even if this hack is
> >>> platform agnostic?
> >>
> >> No, I see UHS-II as a separate layer i.e.
> >>
> >>  UHS-II host controller driver
> >>   |   |
> >>   |   v
> >>   |   sdhci-uhs2 e.g. sdhci_uhs2_start_signal_voltage_switch
> >>   |   |
> >>   v   v
> >>   sdhci e.g. sdhci_start_signal_voltage_switch
> >>
> >> Most things should go through sdhci-uhs2 but not nessarily everything.
> > 
> > What I meant by my previous comment is that we don't have to
> > call any function, sdhci_uhs2_start_signal_voltage_switch in above example,
> > for UHS-II cards in any case since it is always simply empty.
> 
> Please treat the sdhci_uhs2_... host ops as functions for a UHS-II host
> controller in either UHS-II or legacy mode. i.e. it is up to sdhci-uhs2.c to
> call through to sdhci.c not the other way around.  e.g.
>
> int sdhci_uhs2_start_signal_voltage_switch(blah)
> {
>   if (sdhci_uhs2_mode(host))
>   return 0;
>   return sdhci_start_signal_valtage_switch(blah);
> }

Okay, the remaining issue is to clarify the meaning of MMC_UHS2_SUPPORT.

-Takhiro Akashi


Re: [RFC PATCH V3 13/21] mmc: sdhci: UHS-II support, skip signal_voltage_switch()

2020-09-15 Thread AKASHI Takahiro
On Tue, Sep 15, 2020 at 07:36:14PM +0800, Ben Chuang wrote:
> Hi Takahiro,
> 
> On Tue, Sep 15, 2020 at 2:03 PM AKASHI Takahiro
>  wrote:
> >
> > Ben, Adrian,
> >
> > On Mon, Sep 14, 2020 at 11:08:14AM +0300, Adrian Hunter wrote:
> > > On 14/09/20 9:40 am, AKASHI Takahiro wrote:
> > > > Adrian,
> > > >
> > > > On Fri, Aug 21, 2020 at 05:09:01PM +0300, Adrian Hunter wrote:
> > > >> On 10/07/20 2:11 pm, Ben Chuang wrote:
> > > >>> From: AKASHI Takahiro 
> > > >>>
> > > >>> sdhci_start_signal_voltage_switch() should be called only in UHS-I 
> > > >>> mode,
> > > >>> and not for UHS-II mode.
> > > >>>
> > > >>> Signed-off-by: Ben Chuang 
> > > >>> Signed-off-by: AKASHI Takahiro 
> > > >>> ---
> > > >>>  drivers/mmc/host/sdhci.c | 7 ++-
> > > >>>  1 file changed, 6 insertions(+), 1 deletion(-)
> > > >>>
> > > >>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > > >>> index 5511649946b9..7f2537648a08 100644
> > > >>> --- a/drivers/mmc/host/sdhci.c
> > > >>> +++ b/drivers/mmc/host/sdhci.c
> > > >>> @@ -2623,8 +2623,13 @@ int sdhci_start_signal_voltage_switch(struct 
> > > >>> mmc_host *mmc,
> > > >>>   /*
> > > >>>* Signal Voltage Switching is only applicable for Host Controllers
> > > >>>* v3.00 and above.
> > > >>> +  * But for UHS2, the signal voltage is supplied by vdd2 which is
> > > >>> +  * already 1.8v so no voltage switch required.
> >
> > I have been confused with this comment.
> > (I know it came from the original Intel code, not from Ben.)
> >
> > If this comment is true,
> >
> > > >>>*/
> > > >>> - if (host->version < SDHCI_SPEC_300)
> > > >>> + if (host->version < SDHCI_SPEC_300 ||
> > > >>> + (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > > >>> +  host->version >= SDHCI_SPEC_400 &&
> > > >>> +  host->mmc->flags & MMC_UHS2_SUPPORT))
> >
> > the condition above must be wrong since 'flags & MMC_UHS2_SUPPORT'
> > is one of capabilities for a host controller, not a card
> > while the selection of voltage depends on a card type.
> 
> The flag MMC_UHS2_SUPPORT is set at the beginning of 
> mmc_uhs2_rescan_try_freq().
> In UHS-II flow, it stays set.
> If the attempt to UHS-II fails finally, it will be unset.

Right, but MMC_UHS2_SUPPORT is also set, at least initially,
in sdhci_uhs2_add_host(). It is confusing, isn't it?

As we discussed before, any card-specific properties, like UHS-II mode,
should be placed in a card structure, not a host structure.

> >
> > So I wonder why this code still works.
> > I guess that it is because set_signal_voltage(), or other variant functions,
> > will never be called for UHS-II cards under the current implementation.
> >
> > Looking at mmc_sd_init_card(), we have added some hack:
> > mmc_sd_init_card()
> > {
> > ...
> > /* For UHS2, skip the UHS-I initialization. */
> > if ((host->flags & MMC_UHS2_SUPPORT) &&
> > (host->flags & MMC_UHS2_INITIALIZED))
> > goto done;
> > ...
> > if (mmc_sd_card_using_v18(card)) {
> > if (mmc_host_set_uhs_voltage(host) ||
> > mmc_sd_init_uhs_card(card)) {
> > ...
> > }
> >
> > Ben, can you confirm this?
> > (There is another callsite of mmc_host_set_uhs_voltage() though.)
> 
> UHS-II cards use differential signals and don't need to signal voltage switch.
> But the main task is to set the parameters of UHS-II card interface.

Whoever sets MMC_UHS2_SUPPORT (and MMC_UHS2_INITIALIZED), my assertion above
(mmc_host_set_uhs_voltage, and hence [sdhci_]start_signal_voltage_switch(), is
never called for UHS-II cards) will be valid, isn't it?

-Takahiro Akashi

> >
> > > >> Please look at hooking ->start_signal_voltage_switch() instead
> > > >
> > > > Do you mean that you want every platform driver who wants to support 
> > > > UHS-II
> > > > to set NULL to start_signal_voltage_switch hook even if this hack is
> > > > platform agnostic?
> > >
> > > No, I see UHS-II as a separate layer i.e.
> > >
> > >  UHS-II host controller driver
> > >   |   |
> > >   |   v
> > >   |   sdhci-uhs2 e.g. sdhci_uhs2_start_signal_voltage_switch
> > >   |   |
> > >   v   v
> > >   sdhci e.g. sdhci_start_signal_voltage_switch
> > >
> > > Most things should go through sdhci-uhs2 but not nessarily everything.
> >
> > What I meant by my previous comment is that we don't have to
> > call any function, sdhci_uhs2_start_signal_voltage_switch in above example,
> > for UHS-II cards in any case since it is always simply empty.
> >
> > -Takahiro Akashi


Re: [RFC PATCH V3 14/21] mmc: sdhci: UHS-II support, handle vdd2 in case of power-off

2020-09-15 Thread AKASHI Takahiro
On Fri, Aug 21, 2020 at 05:09:55PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:11 pm, Ben Chuang wrote:
> > From: AKASHI Takahiro 
> > 
> > Configure a regulator for VDD2 in case of power-off.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci.c | 5 +
> >  1 file changed, 5 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index 7f2537648a08..d38d734ec83f 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -2333,6 +2333,11 @@ void sdhci_set_ios(struct mmc_host *mmc, struct 
> > mmc_ios *ios)
> > if (!IS_ERR(mmc->supply.vmmc) &&
> > ios->power_mode == MMC_POWER_OFF)
> > mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   host->mmc->caps & MMC_CAP_UHS2 &&
> > +   !IS_ERR(mmc->supply.vmmc2) &&
> > +   ios->power_mode == MMC_POWER_OFF)
> 
> Probably this can be just:
> 
>   if (!IS_ERR_OR_NULL(mmc->supply.vmmc2) &&
>   ios->power_mode == MMC_POWER_OFF)

Yeah, probably.

-Takahiro Akashi

> 
> > +   mmc_regulator_set_ocr(mmc, mmc->supply.vmmc2, 0);
> > return;
> > }
> >  
> > 
> 


Re: [RFC PATCH V3 11/21] mmc: sdhci: UHS-II support, export host operations to core

2020-09-14 Thread AKASHI Takahiro
On Fri, Aug 21, 2020 at 05:05:44PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:10 pm, Ben Chuang wrote:
> > From: AKASHI Takahiro 
> > 
> > Export sdhci-specific UHS-II operations to core.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci.c | 70 
> >  1 file changed, 70 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index c2f6923d296c..aaf41954511a 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -2977,6 +2977,70 @@ static void sdhci_card_event(struct mmc_host *mmc)
> > spin_unlock_irqrestore(&host->lock, flags);
> >  }
> >  
> > +#if IS_ENABLED(CONFIG_MMC_SDHCI_UHS2)
> > +static int sdhci_uhs2_detect_init(struct mmc_host *mmc)
> > +{
> > +   struct sdhci_host *host = mmc_priv(mmc);
> > +   int ret;
> > +
> > +   if (sdhci_uhs2_ops.do_detect_init)
> > +   ret = sdhci_uhs2_ops.do_detect_init(host);
> > +   else
> > +   return 0;
> > +
> > +   return ret;
> > +}
> > +
> > +static int sdhci_uhs2_set_reg(struct mmc_host *mmc, enum uhs2_act act)
> > +{
> > +   struct sdhci_host *host = mmc_priv(mmc);
> > +   int ret;
> > +
> > +   if (sdhci_uhs2_ops.do_set_reg)
> > +   ret = sdhci_uhs2_ops.do_set_reg(host, act);
> > +   else
> > +   ret = 0;
> > +
> > +   return ret;
> > +}
> > +
> > +static void sdhci_uhs2_disable_clk(struct mmc_host *mmc)
> > +{
> > +   struct sdhci_host *host = mmc_priv(mmc);
> > +   u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> > +
> > +   clk &= ~SDHCI_CLOCK_CARD_EN;
> > +   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> > +}
> > +
> > +static void sdhci_uhs2_enable_clk(struct mmc_host *mmc)
> > +{
> > +   struct sdhci_host *host = mmc_priv(mmc);
> > +   u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> > +   ktime_t timeout;
> > +
> > +   clk |= SDHCI_CLOCK_CARD_EN;
> > +   sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> > +
> > +   /* Wait max 20 ms */
> > +   timeout = ktime_add_ms(ktime_get(), 20);
> > +   while (1) {
> > +   bool timedout = ktime_after(ktime_get(), timeout);
> > +
> > +   clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> > +   if (clk & SDHCI_CLOCK_INT_STABLE)
> > +   break;
> > +   if (timedout) {
> > +   pr_err("%s: Internal clock never stabilised.\n",
> > +  mmc_hostname(host->mmc));
> > +   sdhci_dumpregs(host);
> > +   return;
> > +   }
> > +   udelay(10);
> > +   }
> > +}
> > +#endif /* CONFIG_MMC_SDHCI_UHS2 */
> 
> Please put all uhs2 functions in sdhci-uhs2.c and call them through sdhci_ops.

Okay although the logic itself in sdhci_uhs2_[enable|disable]_clk()
doesn't seem to be UHS-II specific.

-Takahiro Akashi

> 
> > +
> >  static const struct mmc_host_ops sdhci_ops = {
> > .request= sdhci_request,
> > .post_req   = sdhci_post_req,
> > @@ -2992,6 +3056,12 @@ static const struct mmc_host_ops sdhci_ops = {
> > .execute_tuning = sdhci_execute_tuning,
> > .card_event = sdhci_card_event,
> > .card_busy  = sdhci_card_busy,
> > +#if IS_ENABLED(CONFIG_MMC_SDHCI_UHS2)
> > +   .uhs2_detect_init   = sdhci_uhs2_detect_init,
> > +   .uhs2_set_reg   = sdhci_uhs2_set_reg,
> > +   .uhs2_disable_clk   = sdhci_uhs2_disable_clk,
> > +   .uhs2_enable_clk= sdhci_uhs2_enable_clk,
> > +#endif /* CONFIG_MMC_SDHCI_UHS2 */
> >  };
> >  
> >  
> > /*\
> > 
> 


Re: [RFC PATCH V3 10/21] mmc: sdhci: UHS-II support, dump UHS-II registers

2020-09-14 Thread AKASHI Takahiro
On Fri, Aug 21, 2020 at 05:04:54PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:10 pm, Ben Chuang wrote:
> > From: AKASHI Takahiro 
> > 
> > Dump UHS-II specific registers, if available, in sdhci_dumpregs()
> > for informative/debugging use.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci.c | 24 
> >  1 file changed, 24 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index 37b1158c1c0c..c2f6923d296c 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -111,6 +111,30 @@ void sdhci_dumpregs(struct sdhci_host *host)
> > }
> > }
> >  
> > +   if (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +   host->mmc && host->mmc->flags & MMC_UHS2_SUPPORT) {
> > +   SDHCI_DUMP(" UHS2 ==\n");
> > +   SDHCI_DUMP("Blk Size:  0x%08x | Blk Cnt:  0x%08x\n",
> > +  sdhci_readw(host, SDHCI_UHS2_BLOCK_SIZE),
> > +  sdhci_readl(host, SDHCI_UHS2_BLOCK_COUNT));
> > +   SDHCI_DUMP("Cmd:   0x%08x | Trn mode: 0x%08x\n",
> > +  sdhci_readw(host, SDHCI_UHS2_COMMAND),
> > +  sdhci_readw(host, SDHCI_UHS2_TRANS_MODE));
> > +   SDHCI_DUMP("Int Stat:  0x%08x | Dev Sel : 0x%08x\n",
> > +  sdhci_readw(host, SDHCI_UHS2_DEV_INT_STATUS),
> > +  sdhci_readb(host, SDHCI_UHS2_DEV_SELECT));
> > +   SDHCI_DUMP("Dev Int Code:  0x%08x\n",
> > +  sdhci_readb(host, SDHCI_UHS2_DEV_INT_CODE));
> > +   SDHCI_DUMP("Reset: 0x%08x | Timer:0x%08x\n",
> > +  sdhci_readw(host, SDHCI_UHS2_SW_RESET),
> > +  sdhci_readw(host, SDHCI_UHS2_TIMER_CTRL));
> > +   SDHCI_DUMP("ErrInt:0x%08x | ErrIntEn: 0x%08x\n",
> > +  sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS),
> > +  sdhci_readl(host, SDHCI_UHS2_ERR_INT_STATUS_EN));
> > +   SDHCI_DUMP("ErrSigEn:  0x%08x\n",
> > +  sdhci_readl(host, SDHCI_UHS2_ERR_INT_SIG_EN));
> > +   }
> > +
> 
> Let's make this a host op instead ie.
> 
>   if (host->ops->dump_uhs2_regs)
>   host->ops->dump_uhs2_regs(host);

Sure.

-Takahiro Akashi

> > if (host->ops->dump_vendor_regs)
> > host->ops->dump_vendor_regs(host);
> >  
> > 
> 


Re: [RFC PATCH V3 09/21] mmc: sdhci: add UHS-II related definitions in headers

2020-09-14 Thread AKASHI Takahiro
Adrian,

On Fri, Aug 21, 2020 at 05:04:16PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:10 pm, Ben Chuang wrote:
> > From: AKASHI Takahiro 
> > 
> > Add UHS-II related definitions in shdci.h and sdhci-uhs2.h.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-uhs2.h | 215 ++
> >  drivers/mmc/host/sdhci.h  |  91 +-
> >  2 files changed, 305 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/mmc/host/sdhci-uhs2.h
> > 
> > diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
> > new file mode 100644
> > index ..a7f53f95d69a
> > --- /dev/null
> > +++ b/drivers/mmc/host/sdhci-uhs2.h
> > @@ -0,0 +1,215 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + *  linux/drivers/mmc/host/sdhci-uhs2.h - Secure Digital Host Controller
> > + *  Interface driver
> > + *
> > + * Header file for Host Controller UHS2 related registers and I/O 
> > accessors.
> > + *
> > + *  Copyright (C) 2014 Intel Corp, All Rights Reserved.
> > + */
> > +#ifndef __SDHCI_UHS2_H
> > +#define __SDHCI_UHS2_H
> > +
> > +#include 
> > +#include 
> > +#include 
> 
> These includes should not be here unless this file needs them, which doesn't
> look like it.

Okay.

> Wouldn't hurt to make use of BIT and GENMASK macros since this is a new file.

Will try to convert all.

> > +
> > +/*
> > + * UHS-II Controller registers
> > + * 0x74 preset in sdhci.h
> > + * 0x80
> > + * 0x84-0xB4
> > + * 0xB8-0xCF
> > + * 0xE0-0xE7
> > + */
> > +/* UHS2 */
> > +#define SDHCI_UHS2_BLOCK_SIZE  0x80
> > +#define  SDHCI_UHS2_MAKE_BLKSZ(dma, blksz) \
> > +   dma) & 0x7) << 12) | ((blksz) & 0xFFF))
> > +
> > +#define SDHCI_UHS2_BLOCK_COUNT 0x84
> > +
> > +#define SDHCI_UHS2_CMD_PACKET  0x88
> > +#define  SDHCI_UHS2_CMD_PACK_MAX_LEN   20
> > +
> > +#define SDHCI_UHS2_TRANS_MODE  0x9C
> > +#define  SDHCI_UHS2_TRNS_DMA   0x0001
> > +#define  SDHCI_UHS2_TRNS_BLK_CNT_EN0x0002
> > +#define  SDHCI_UHS2_TRNS_DATA_TRNS_WRT 0x0010
> > +#define  SDHCI_UHS2_TRNS_BLK_BYTE_MODE 0x0020
> > +#define  SDHCI_UHS2_TRNS_RES_R50x0040
> > +#define  SDHCI_UHS2_TRNS_RES_ERR_CHECK_EN  0x0080
> > +#define  SDHCI_UHS2_TRNS_RES_INT_DIS   0x0100
> > +#define  SDHCI_UHS2_TRNS_WAIT_EBSY 0x4000
> > +#define  SDHCI_UHS2_TRNS_2L_HD 0x8000
> > +
> > +#define SDHCI_UHS2_COMMAND 0x9E
> > +#define  SDHCI_UHS2_COMMAND_SUB_CMD0x0004
> > +#define  SDHCI_UHS2_COMMAND_DATA   0x0020
> > +#define  SDHCI_UHS2_COMMAND_TRNS_ABORT 0x0040
> > +#define  SDHCI_UHS2_COMMAND_CMD12  0x0080
> > +#define  SDHCI_UHS2_COMMAND_DORMANT0x00C0
> > +#define  SDHCI_UHS2_COMMAND_PACK_LEN_MASK  0x1F00
> > +#define  SDHCI_UHS2_COMMAND_PACK_LEN_SHIFT 8
> > +
> > +#define SDHCI_UHS2_RESPONSE0xA0
> > +#define  SDHCI_UHS2_RESPONSE_MAX_LEN   20
> > +
> > +#define SDHCI_UHS2_MSG_SELECT  0xB4
> > +#define SDHCI_UHS2_MSG_SELECT_CURR 0x0
> > +#define SDHCI_UHS2_MSG_SELECT_ONE  0x1
> > +#define SDHCI_UHS2_MSG_SELECT_TWO  0x2
> > +#define SDHCI_UHS2_MSG_SELECT_THREE0x3
> > +
> > +#define SDHCI_UHS2_MSG 0xB8
> > +
> > +#define SDHCI_UHS2_DEV_INT_STATUS  0xBC
> > +
> > +#define SDHCI_UHS2_DEV_SELECT  0xBE
> > +#define SDHCI_UHS2_DEV_SELECT_DEV_SEL_MASK 0x0F
> > +#define SDHCI_UHS2_DEV_SELECT_INT_MSG_EN   0x80
> > +
> > +#define SDHCI_UHS2_DEV_INT_CODE0xBF
> > +
> > +#define SDHCI_UHS2_SW_RESET0xC0
> > +#define SDHCI_UHS2_SW_RESET_FULL   0x0001
> > +#define SDHCI_UHS2_SW_RESET_SD 0x0002
> > +
> > +#define SDHCI_UHS2_TIMER_CTRL  0xC2
> > +#define SDHCI_UHS2_TIMER_CTRL_DEADLOCK_SHIFT   4
> > +
> > +#define SDHCI_UHS2_ERR_INT_STATUS  0xC4
> > +#define SDHCI_UHS2_ERR_INT_STATUS_EN   0xC8
> > +#define SDHCI_UHS2_ERR_INT_SIG_EN  0xCC
> > +#define SDHCI_UHS2_ERR_INT_STATUS_HEADER   0x0001
> > +#define SDHCI_UHS2_ERR_INT_STATUS_RES  0x0002
> > +#define SDHCI_UHS2_ERR_INT_STATUS_RETRY_EXP0x0004
> > +#define SDHCI_UHS2_ERR_INT_STATUS_CRC  0x0008
> > +#define SDHCI_UHS2_ERR_INT_STATUS_FRAME0x0010
> > +#define SDHCI_UHS2_ERR_INT_STATUS_TID 

Re: [RFC PATCH V3 15/21] mmc: sdhci: UHS-II support, modify set_power() to handle vdd2

2020-09-14 Thread AKASHI Takahiro
Adrain,

On Mon, Sep 14, 2020 at 09:36:02AM +0300, Adrian Hunter wrote:
> On 14/09/20 8:45 am, AKASHI Takahiro wrote:
> > Adrian,
> > 
> > On Fri, Aug 21, 2020 at 05:11:18PM +0300, Adrian Hunter wrote:
> >> On 10/07/20 2:11 pm, Ben Chuang wrote:
> >>> From: AKASHI Takahiro 
> >>>
> >>> VDD2 is used for powering UHS-II interface.
> >>> Modify sdhci_set_power_and_bus_voltage(), sdhci_set_power_noreg()
> >>> and sdhci_set_power_noreg() to handle VDD2.
> >>
> >> vdd2 is always 1.8 V and I suspect there may never be support for anything
> >> else, so we should start with 1.8 V only.
> > 
> > What do you mean here?
> > You don't want to add an extra argument, vdd2, to sdhci_set_power().
> > Correct?
> 
> Yes
> 
> > 
> >> Also can we create uhs2_set_power_reg() and uhs2_set_power_noreg() and use
> >> the existing ->set_power() callback
> > 
> > Again what do you expect here?
> > 
> > Do you want to see any platform-specific mmc driver who supports UHS-II
> > to implement its own call back like:
> 
> Not exactly.  I expect there to be a common implementation in sdhci-uhs2.c
> called sdhci_uhs2_set_power() for example, that drivers can use by setting
> their .set_power = sdhci_uhs2_set_power.  If they need platform-specific
> code as well then their platform-specific code can call
> sdhci_uhs2_set_power() if desired.
> 
> > 
> > void sdhci_foo_set_power(struct sdhci_host *host, unsigned char mode,
> >   unsigned short vdd)
> > {
> > sdhci_set_power(host, mode,vdd);
> > 
> > /* in case that sdhci_uhs2 module is not inserted */
> > if (!(mmc->caps & MMC_CAP_UHS2))
> > return;
> > 
> > /* vdd2 specific operation */
> > if (IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
> > sdhci_uhs2_set_power_noreg(host, mode);
> > else
> > sdhci_uhs2_set_power_reg(host, mode);
> > 
> > /* maybe more platform-specific initialization */
> > }
> > 
> > struct sdhci_ops sdhci_foo_ops = {
> > .set_power = sdhci_foo_set_power,
> > ...
> > }

What do you think about this logic in general?
(If necessary, read it replacing "foo" to "uhs2".)

What I'm concerned about is SDHCI_POWER_CONTROL register.
Vdd and vdd2 are controlled with corresponding bits in this register.
It seems to be "natural" to me that vdd and vdd2 are enabled
in a single function rather than putting them in separate ones.

In particular, in the case of sdhci_set_power_noreg(), there exist a couple
of "quirks" around writing the bits to SDHCI_POWER_CONTROL register.
I don't know how we should handle them if we have a separate function,
say, sdhci_uhs2_set_power_noreg().
Do you want to see a copy of the same logic in sdhci_uhs2_set_power_noreg()? 

-Takahiro Akashi


> > 
> > Is this what you mean?
> > (I'm not quite sure yet that sdhci_ush2_set_power_noreg() can be split off
> > from sdhci_set_power_noreg().)
> > 
> > -Takahiro Akashi


Re: [RFC PATCH V3 13/21] mmc: sdhci: UHS-II support, skip signal_voltage_switch()

2020-09-14 Thread AKASHI Takahiro
Ben, Adrian,

On Mon, Sep 14, 2020 at 11:08:14AM +0300, Adrian Hunter wrote:
> On 14/09/20 9:40 am, AKASHI Takahiro wrote:
> > Adrian,
> > 
> > On Fri, Aug 21, 2020 at 05:09:01PM +0300, Adrian Hunter wrote:
> >> On 10/07/20 2:11 pm, Ben Chuang wrote:
> >>> From: AKASHI Takahiro 
> >>>
> >>> sdhci_start_signal_voltage_switch() should be called only in UHS-I mode,
> >>> and not for UHS-II mode.
> >>>
> >>> Signed-off-by: Ben Chuang 
> >>> Signed-off-by: AKASHI Takahiro 
> >>> ---
> >>>  drivers/mmc/host/sdhci.c | 7 ++-
> >>>  1 file changed, 6 insertions(+), 1 deletion(-)
> >>>
> >>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> >>> index 5511649946b9..7f2537648a08 100644
> >>> --- a/drivers/mmc/host/sdhci.c
> >>> +++ b/drivers/mmc/host/sdhci.c
> >>> @@ -2623,8 +2623,13 @@ int sdhci_start_signal_voltage_switch(struct 
> >>> mmc_host *mmc,
> >>>   /*
> >>>* Signal Voltage Switching is only applicable for Host Controllers
> >>>* v3.00 and above.
> >>> +  * But for UHS2, the signal voltage is supplied by vdd2 which is
> >>> +  * already 1.8v so no voltage switch required.

I have been confused with this comment.
(I know it came from the original Intel code, not from Ben.)

If this comment is true,

> >>>*/
> >>> - if (host->version < SDHCI_SPEC_300)
> >>> + if (host->version < SDHCI_SPEC_300 ||
> >>> + (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> >>> +  host->version >= SDHCI_SPEC_400 &&
> >>> +  host->mmc->flags & MMC_UHS2_SUPPORT))

the condition above must be wrong since 'flags & MMC_UHS2_SUPPORT'
is one of capabilities for a host controller, not a card
while the selection of voltage depends on a card type.

So I wonder why this code still works.
I guess that it is because set_signal_voltage(), or other variant functions,
will never be called for UHS-II cards under the current implementation.

Looking at mmc_sd_init_card(), we have added some hack:
mmc_sd_init_card()
{
...
/* For UHS2, skip the UHS-I initialization. */
if ((host->flags & MMC_UHS2_SUPPORT) &&
(host->flags & MMC_UHS2_INITIALIZED))
goto done;
...
if (mmc_sd_card_using_v18(card)) {
if (mmc_host_set_uhs_voltage(host) ||
mmc_sd_init_uhs_card(card)) {
...
}

Ben, can you confirm this?
(There is another callsite of mmc_host_set_uhs_voltage() though.)

> >> Please look at hooking ->start_signal_voltage_switch() instead
> > 
> > Do you mean that you want every platform driver who wants to support UHS-II
> > to set NULL to start_signal_voltage_switch hook even if this hack is
> > platform agnostic?
> 
> No, I see UHS-II as a separate layer i.e.
> 
>  UHS-II host controller driver
>   |   |
>   |   v
>   |   sdhci-uhs2 e.g. sdhci_uhs2_start_signal_voltage_switch
>   |   |
>   v   v
>   sdhci e.g. sdhci_start_signal_voltage_switch
> 
> Most things should go through sdhci-uhs2 but not nessarily everything.

What I meant by my previous comment is that we don't have to
call any function, sdhci_uhs2_start_signal_voltage_switch in above example,
for UHS-II cards in any case since it is always simply empty.

-Takahiro Akashi


Re: [RFC PATCH V3 13/21] mmc: sdhci: UHS-II support, skip signal_voltage_switch()

2020-09-13 Thread AKASHI Takahiro
Adrian,

On Fri, Aug 21, 2020 at 05:09:01PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:11 pm, Ben Chuang wrote:
> > From: AKASHI Takahiro 
> > 
> > sdhci_start_signal_voltage_switch() should be called only in UHS-I mode,
> > and not for UHS-II mode.
> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci.c | 7 ++-
> >  1 file changed, 6 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> > index 5511649946b9..7f2537648a08 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -2623,8 +2623,13 @@ int sdhci_start_signal_voltage_switch(struct 
> > mmc_host *mmc,
> > /*
> >  * Signal Voltage Switching is only applicable for Host Controllers
> >  * v3.00 and above.
> > +* But for UHS2, the signal voltage is supplied by vdd2 which is
> > +* already 1.8v so no voltage switch required.
> >  */
> > -   if (host->version < SDHCI_SPEC_300)
> > +   if (host->version < SDHCI_SPEC_300 ||
> > +   (IS_ENABLED(CONFIG_MMC_SDHCI_UHS2) &&
> > +host->version >= SDHCI_SPEC_400 &&
> > +host->mmc->flags & MMC_UHS2_SUPPORT))
> 
> Please look at hooking ->start_signal_voltage_switch() instead

Do you mean that you want every platform driver who wants to support UHS-II
to set NULL to start_signal_voltage_switch hook even if this hack is
platform agnostic?
(Another option is that it would be put in sdhci_uhs2_add_host() which
is responsible to set MMC_UHS2_SUPPORT.)

-Takahiro Akashi

> 
> 
> > return 0;
> >  
> > ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> > 
> 


Re: [RFC PATCH V3 15/21] mmc: sdhci: UHS-II support, modify set_power() to handle vdd2

2020-09-13 Thread AKASHI Takahiro
Adrian,

On Fri, Aug 21, 2020 at 05:11:18PM +0300, Adrian Hunter wrote:
> On 10/07/20 2:11 pm, Ben Chuang wrote:
> > From: AKASHI Takahiro 
> > 
> > VDD2 is used for powering UHS-II interface.
> > Modify sdhci_set_power_and_bus_voltage(), sdhci_set_power_noreg()
> > and sdhci_set_power_noreg() to handle VDD2.
> 
> vdd2 is always 1.8 V and I suspect there may never be support for anything
> else, so we should start with 1.8 V only.

What do you mean here?
You don't want to add an extra argument, vdd2, to sdhci_set_power().
Correct?

> Also can we create uhs2_set_power_reg() and uhs2_set_power_noreg() and use
> the existing ->set_power() callback

Again what do you expect here?

Do you want to see any platform-specific mmc driver who supports UHS-II
to implement its own call back like:

void sdhci_foo_set_power(struct sdhci_host *host, unsigned char mode,
  unsigned short vdd)
{
sdhci_set_power(host, mode,vdd);

/* in case that sdhci_uhs2 module is not inserted */
if (!(mmc->caps & MMC_CAP_UHS2))
return;

/* vdd2 specific operation */
if (IS_ERR_OR_NULL(host->mmc->supply.vmmc2))
sdhci_uhs2_set_power_noreg(host, mode);
else
sdhci_uhs2_set_power_reg(host, mode);

/* maybe more platform-specific initialization */
}

struct sdhci_ops sdhci_foo_ops = {
.set_power = sdhci_foo_set_power,
...
}

Is this what you mean?
(I'm not quite sure yet that sdhci_ush2_set_power_noreg() can be split off
from sdhci_set_power_noreg().)

-Takahiro Akashi

}

> > 
> > Signed-off-by: Ben Chuang 
> > Signed-off-by: AKASHI Takahiro 
> > ---
> >  drivers/mmc/host/sdhci-omap.c |  2 +-
> >  drivers/mmc/host/sdhci-pci-core.c |  4 +--
> >  drivers/mmc/host/sdhci-pxav3.c|  4 +--
> >  drivers/mmc/host/sdhci-xenon.c|  4 +--
> >  drivers/mmc/host/sdhci.c  | 42 ---
> >  drivers/mmc/host/sdhci.h  |  9 +++
> >  6 files changed, 43 insertions(+), 22 deletions(-)
> > 
> > diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
> > index 1ec74c2d5c17..1926585debe5 100644
> > --- a/drivers/mmc/host/sdhci-omap.c
> > +++ b/drivers/mmc/host/sdhci-omap.c
> > @@ -678,7 +678,7 @@ static void sdhci_omap_set_clock(struct sdhci_host 
> > *host, unsigned int clock)
> >  }
> >  
> >  static void sdhci_omap_set_power(struct sdhci_host *host, unsigned char 
> > mode,
> > - unsigned short vdd)
> > + unsigned short vdd, unsigned short vdd2)
> >  {
> > struct mmc_host *mmc = host->mmc;
> >  
> > diff --git a/drivers/mmc/host/sdhci-pci-core.c 
> > b/drivers/mmc/host/sdhci-pci-core.c
> > index bb6802448b2f..40f5a24a8982 100644
> > --- a/drivers/mmc/host/sdhci-pci-core.c
> > +++ b/drivers/mmc/host/sdhci-pci-core.c
> > @@ -629,12 +629,12 @@ static int bxt_get_cd(struct mmc_host *mmc)
> >  #define SDHCI_INTEL_PWR_TIMEOUT_UDELAY 100
> >  
> >  static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char 
> > mode,
> > - unsigned short vdd)
> > + unsigned short vdd, unsigned short vdd2)
> >  {
> > int cntr;
> > u8 reg;
> >  
> > -   sdhci_set_power(host, mode, vdd);
> > +   sdhci_set_power(host, mode, vdd, -1);
> >  
> > if (mode == MMC_POWER_OFF)
> > return;
> > diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
> > index e55037ceda73..457e9425339a 100644
> > --- a/drivers/mmc/host/sdhci-pxav3.c
> > +++ b/drivers/mmc/host/sdhci-pxav3.c
> > @@ -298,12 +298,12 @@ static void pxav3_set_uhs_signaling(struct sdhci_host 
> > *host, unsigned int uhs)
> >  }
> >  
> >  static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
> > -   unsigned short vdd)
> > +   unsigned short vdd, unsigned short vdd2)
> >  {
> > struct mmc_host *mmc = host->mmc;
> > u8 pwr = host->pwr;
> >  
> > -   sdhci_set_power_noreg(host, mode, vdd);
> > +   sdhci_set_power_noreg(host, mode, vdd, -1);
> >  
> > if (host->pwr == pwr)
> > return;
> > diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c
> > index 4703cd540c7f..2b0ebb91895a 100644
> > --- a/drivers/mmc/host/sdhci-xenon.c
> > +++ b/drivers/mmc/host/sdhci-xenon.c
> > @@ -214,12 +214,12 @@ static void xenon_set_uhs_signaling(struct sdhc

Re: [RFC patch 17/41] tracing: Make stack_trace_print() static and rename it

2019-04-10 Thread AKASHI Takahiro
On Wed, Apr 10, 2019 at 08:47:03AM -0400, Steven Rostedt wrote:
> On Wed, 10 Apr 2019 12:28:11 +0200
> Thomas Gleixner  wrote:
> 
> > It's only used in the source file where it is defined and it's using the
> > stack_trace_ namespace. Rename it to free it up for stack trace related
> > functions.
> > 
> 
> Can you put it back to its original name "print_max_stack()" which was
> changed by this commit:
> 
> bb99d8ccec7 ("tracing: Allow arch-specific stack tracer")
> 
> I actually want to do a clean up and remove all "trace_" functions that
> are not a tracepoint. It's getting confusing to see a "trace_..." and
> search for the corresponding TRACE_EVENT() macro and not being able to
> find it.
> 
> Hmm, I'm not sure why Akashi changed that function to be global in the
> first place. It looks like only check_stack() needed to be changed.
> 
> Akashi?

Well, as indicated in the commit log, I implemented arch64-specific
check_stack() and used stack_trace_print() in there. At the end of the day,
however, only the first part of my patch set[1], including 'bb99d8ccec7',
was merged. Since then the said function was never used outside of the file.

[1] 
http://lists.infradead.org/pipermail/linux-arm-kernel/2015-December/393716.html

Thanks,
-Takahiro Akashi

> -- Steve
> 
> 
> > Signed-off-by: Thomas Gleixner 
> > Cc: Steven Rostedt 
> > ---
> >  include/linux/ftrace.h |1 -
> >  kernel/trace/trace_stack.c |4 ++--
> >  2 files changed, 2 insertions(+), 3 deletions(-)
> > 
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
> > @@ -251,7 +251,6 @@ extern unsigned long stack_trace_max_siz
> >  extern arch_spinlock_t stack_trace_max_lock;
> >  
> >  extern int stack_tracer_enabled;
> > -void stack_trace_print(void);
> >  int
> >  stack_trace_sysctl(struct ctl_table *table, int write,
> >void __user *buffer, size_t *lenp,
> > --- a/kernel/trace/trace_stack.c
> > +++ b/kernel/trace/trace_stack.c
> > @@ -41,7 +41,7 @@ static DEFINE_MUTEX(stack_sysctl_mutex);
> >  int stack_tracer_enabled;
> >  static int last_stack_tracer_enabled;
> >  
> > -void stack_trace_print(void)
> > +static void trace_stack_trace_print(void)
> >  {
> > long i;
> > int size;
> > @@ -179,7 +179,7 @@ check_stack(unsigned long ip, unsigned l
> > stack_trace_max.nr_entries = x;
> >  
> > if (task_stack_end_corrupted(current)) {
> > -   stack_trace_print();
> > +   trace_stack_trace_print();
> > BUG();
> > }
> >  
> > 
> 


Re: [PATCH v16 06/16] lib: fdt: add a helper function for handling memory range property

2018-12-11 Thread AKASHI, Takahiro
On Tue, Dec 11, 2018 at 10:09:07AM +, James Morse wrote:
> Hi Akashi,
> 
> On 11/12/2018 06:17, AKASHI, Takahiro wrote:
> > On Fri, Dec 07, 2018 at 10:12:47AM +, James Morse wrote:
> >> On 06/12/2018 15:54, Will Deacon wrote:
> >>> On Thu, Dec 06, 2018 at 08:47:04AM -0600, Rob Herring wrote:
> >>>> On Wed, Nov 14, 2018 at 11:52 PM AKASHI Takahiro
> >>>>  wrote:
> >>>>>
> >>>>> Added function, fdt_setprop_reg(), will be used later to handle
> >>>>> kexec-specific property in arm64's kexec_file implementation.
> >>>>> It will possibly be merged into libfdt in the future.
> >>>>
> >>>> You generally can't modify libfdt files. Any changes will be blown
> >>>> away with the next dtc sync (there's one in -next now). Though here
> >>>> you are creating a new location with fdt code. lib/ is just a shim to
> >>>> the actual libfdt code. Don't put any implementation there. You can
> >>>> add this to drivers/of/fdt_address.c for the short term, but it still
> >>>> needs to go upstream.
> >>>>
> >>>> Otherwise, the implementation looks fine to me.
> >>>
> >>> I agree, but I don't think there's a real need for us to hack
> >>> drivers/of/fdt_address.c in the meantime -- let's just target upstream
> >>> and not carry this in the kernel.
> >>>
> >>> Akashi -- for now, I'll drop the kdump parts of this series which rely
> >>> on this helper. The majority of the series is actually independent and
> >>> can go in as-is.
> >>>
> >>> I've pushed out a kexec branch to the arm64 tree for you to take a look
> >>> at:
> >>>
> >>> https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git/log/?h=kexec
> >>
> >> I gave this a quick spin. Without the elfcorehdr/usable-memory-range arm64 
> >> needs
> >> to explicitly forbid kdump via kexec_file_load. (like powerpc does 
> >> already).
> > 
> > Thank you for pointing this out.
> > 
> >> Without this kdump works, but the second kernel overwrites the first as 
> >> those DT
> >> properties are missing.
> >>
> >> I'll post a patch momentarily,
> > 
> > Fine, but anyhow I'm going to submit a new version (*without* kdump),
> > I will fix the issue along with others.
> 
> I had a quick look at the arm64 for-next/core branch. Will has queued the
> non-kdump parts of this series.
> 
> If you have changes, they need to be against the arm64 tree.

Okay!

-Takahiro Akashi

> 
> Thanks,
> 
> James


Re: [PATCH v16 16/16] arm64: kexec_file: add kaslr support

2018-12-10 Thread AKASHI Takahiro
On Tue, Dec 11, 2018 at 02:50:02PM +0900, AKASHI Takahiro wrote:
> On Fri, Nov 30, 2018 at 01:19:44PM +, Will Deacon wrote:
> > On Thu, Nov 15, 2018 at 02:52:55PM +0900, AKASHI Takahiro wrote:
> > > Adding "kaslr-seed" to dtb enables triggering kaslr, or kernel virtual
> > > address randomization, at secondary kernel boot. We always do this as
> > > it will have no harm on kaslr-incapable kernel.
> > > 
> > > We don't have any "switch" to turn off this feature directly, but still
> > > can suppress it by passing "nokaslr" as a kernel boot argument.
> > > 
> > > Signed-off-by: AKASHI Takahiro 
> > > Cc: Catalin Marinas 
> > > Cc: Will Deacon 
> > > ---
> > >  arch/arm64/kernel/machine_kexec_file.c | 46 +-
> > >  1 file changed, 45 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> > > b/arch/arm64/kernel/machine_kexec_file.c
> > > index ab296b98d633..a0a730bd9be6 100644
> > > --- a/arch/arm64/kernel/machine_kexec_file.c
> > > +++ b/arch/arm64/kernel/machine_kexec_file.c
> > > @@ -16,6 +16,7 @@
> > >  #include 
> > >  #include 
> > >  #include 
> > > +#include 
> > >  #include 
> > >  #include 
> > >  #include 
> > > @@ -28,6 +29,7 @@
> > >  #define FDT_PSTR_INITRD_STA  "linux,initrd-start"
> > >  #define FDT_PSTR_INITRD_END  "linux,initrd-end"
> > >  #define FDT_PSTR_BOOTARGS"bootargs"
> > > +#define FDT_PSTR_KASLR_SEED  "kaslr-seed"
> > >  
> > >  const struct kexec_file_ops * const kexec_file_loaders[] = {
> > >   &kexec_image_ops,
> > > @@ -46,11 +48,38 @@ int arch_kimage_file_post_load_cleanup(struct kimage 
> > > *image)
> > >   return kexec_image_post_load_cleanup_default(image);
> > >  }
> > >  
> > > +/* crng needs to have been initialized for providing kaslr-seed */
> > > +static int random_ready;
> > > +
> > > +static void random_ready_notified(struct random_ready_callback *unused)
> > > +{
> > > + random_ready = 1;
> > > +}
> > > +
> > > +static struct random_ready_callback random_ready_cb = {
> > > + .func = random_ready_notified,
> > > +};
> > > +
> > > +static __init int init_random_ready_cb(void)
> > > +{
> > > + int ret;
> > > +
> > > + ret = add_random_ready_callback(&random_ready_cb);
> > > + if (ret == -EALREADY)
> > > + random_ready = 1;
> > > + else if (ret)
> > > + pr_warn("failed to add a callback for random_ready\n");
> > > +
> > > + return 0;
> > > +}
> > > +late_initcall(init_random_ready_cb)
> > 
> > Why can't we just call crng_ready()?
> 
> because crng_ready() is locally defined in drivers/char/random.c.
> Instead, I'd like to use
> wait_for_random_bytes();
> value = get_random_u64();

Correction:
After several tests, I now don't think that calling wait_for_random_bytes()
is a good idea since it can make kexec_file_load() syscall stalled.
So, I would go for
if (rng_is_initialized())
value = get_random_u64();

-Takahiro Akashi

> > > +
> > >  static int setup_dtb(struct kimage *image,
> > >unsigned long initrd_load_addr, unsigned long initrd_len,
> > >char *cmdline, void *dtb)
> > >  {
> > >   int nodeoffset;
> > > + u64 value;
> > >   int ret;
> > >  
> > >   nodeoffset = fdt_path_offset(dtb, "/chosen");
> > > @@ -106,12 +135,27 @@ static int setup_dtb(struct kimage *image,
> > >   return -EINVAL;
> > >   }
> > >  
> > > + /* add kaslr-seed */
> > > + ret = fdt_delprop(dtb, nodeoffset, FDT_PSTR_KASLR_SEED);
> > > + if (ret && (ret != -FDT_ERR_NOTFOUND))
> > > + return -EINVAL;
> > > +
> > > + if (random_ready) {
> > > + get_random_bytes(&value, sizeof(value));
> > 
> > get_random_u64() ?
> 
> OK.
> 
> > > + ret = fdt_setprop_u64(dtb, nodeoffset, FDT_PSTR_KASLR_SEED,
> > > + value);
> > > + if (ret)
> > > + return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
> > > + } else {
> > 
> > Wouldn't we be better off preserving the previous seed here, if it was
> > present?
> 
> While there's no guarantee that dtb won't be (partially) broken
> on failure, I will let this function return successfully
> by deleting succeeding fdt_delprop().
> 
> 
> > > + pr_notice("kaslr-seed won't be fed\n");
> > 
> > "fed" is probably not the right word here.
> 
> => won't be *provided* on kexec?
> 
> -Takahiro Akashi
> 
> > Will


Re: [PATCH v16 06/16] lib: fdt: add a helper function for handling memory range property

2018-12-10 Thread AKASHI, Takahiro
James,

On Fri, Dec 07, 2018 at 10:12:47AM +, James Morse wrote:
> Hi Akashi, Will,
> 
> On 06/12/2018 15:54, Will Deacon wrote:
> > On Thu, Dec 06, 2018 at 08:47:04AM -0600, Rob Herring wrote:
> >> On Wed, Nov 14, 2018 at 11:52 PM AKASHI Takahiro
> >>  wrote:
> >>>
> >>> Added function, fdt_setprop_reg(), will be used later to handle
> >>> kexec-specific property in arm64's kexec_file implementation.
> >>> It will possibly be merged into libfdt in the future.
> >>
> >> You generally can't modify libfdt files. Any changes will be blown
> >> away with the next dtc sync (there's one in -next now). Though here
> >> you are creating a new location with fdt code. lib/ is just a shim to
> >> the actual libfdt code. Don't put any implementation there. You can
> >> add this to drivers/of/fdt_address.c for the short term, but it still
> >> needs to go upstream.
> >>
> >> Otherwise, the implementation looks fine to me.
> > 
> > I agree, but I don't think there's a real need for us to hack
> > drivers/of/fdt_address.c in the meantime -- let's just target upstream
> > and not carry this in the kernel.
> > 
> > Akashi -- for now, I'll drop the kdump parts of this series which rely
> > on this helper. The majority of the series is actually independent and
> > can go in as-is.
> > 
> > I've pushed out a kexec branch to the arm64 tree for you to take a look
> > at:
> > 
> > https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git/log/?h=kexec
> 
> I gave this a quick spin. Without the elfcorehdr/usable-memory-range arm64 
> needs
> to explicitly forbid kdump via kexec_file_load. (like powerpc does already).

Thank you for pointing this out.

> Without this kdump works, but the second kernel overwrites the first as those 
> DT
> properties are missing.
> 
> I'll post a patch momentarily,

Fine, but anyhow I'm going to submit a new version (*without* kdump),
I will fix the issue along with others.

-Takahiro Akashi


> 
> Thanks,
> 
> James
> 


Re: [PATCH v16 16/16] arm64: kexec_file: add kaslr support

2018-12-10 Thread AKASHI Takahiro
On Fri, Nov 30, 2018 at 01:19:44PM +, Will Deacon wrote:
> On Thu, Nov 15, 2018 at 02:52:55PM +0900, AKASHI Takahiro wrote:
> > Adding "kaslr-seed" to dtb enables triggering kaslr, or kernel virtual
> > address randomization, at secondary kernel boot. We always do this as
> > it will have no harm on kaslr-incapable kernel.
> > 
> > We don't have any "switch" to turn off this feature directly, but still
> > can suppress it by passing "nokaslr" as a kernel boot argument.
> > 
> > Signed-off-by: AKASHI Takahiro 
> > Cc: Catalin Marinas 
> > Cc: Will Deacon 
> > ---
> >  arch/arm64/kernel/machine_kexec_file.c | 46 +-
> >  1 file changed, 45 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> > b/arch/arm64/kernel/machine_kexec_file.c
> > index ab296b98d633..a0a730bd9be6 100644
> > --- a/arch/arm64/kernel/machine_kexec_file.c
> > +++ b/arch/arm64/kernel/machine_kexec_file.c
> > @@ -16,6 +16,7 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >  #include 
> >  #include 
> >  #include 
> > @@ -28,6 +29,7 @@
> >  #define FDT_PSTR_INITRD_STA"linux,initrd-start"
> >  #define FDT_PSTR_INITRD_END"linux,initrd-end"
> >  #define FDT_PSTR_BOOTARGS  "bootargs"
> > +#define FDT_PSTR_KASLR_SEED"kaslr-seed"
> >  
> >  const struct kexec_file_ops * const kexec_file_loaders[] = {
> > &kexec_image_ops,
> > @@ -46,11 +48,38 @@ int arch_kimage_file_post_load_cleanup(struct kimage 
> > *image)
> > return kexec_image_post_load_cleanup_default(image);
> >  }
> >  
> > +/* crng needs to have been initialized for providing kaslr-seed */
> > +static int random_ready;
> > +
> > +static void random_ready_notified(struct random_ready_callback *unused)
> > +{
> > +   random_ready = 1;
> > +}
> > +
> > +static struct random_ready_callback random_ready_cb = {
> > +   .func = random_ready_notified,
> > +};
> > +
> > +static __init int init_random_ready_cb(void)
> > +{
> > +   int ret;
> > +
> > +   ret = add_random_ready_callback(&random_ready_cb);
> > +   if (ret == -EALREADY)
> > +   random_ready = 1;
> > +   else if (ret)
> > +   pr_warn("failed to add a callback for random_ready\n");
> > +
> > +   return 0;
> > +}
> > +late_initcall(init_random_ready_cb)
> 
> Why can't we just call crng_ready()?

because crng_ready() is locally defined in drivers/char/random.c.
Instead, I'd like to use
wait_for_random_bytes();
value = get_random_u64();

> > +
> >  static int setup_dtb(struct kimage *image,
> >  unsigned long initrd_load_addr, unsigned long initrd_len,
> >  char *cmdline, void *dtb)
> >  {
> > int nodeoffset;
> > +   u64 value;
> > int ret;
> >  
> > nodeoffset = fdt_path_offset(dtb, "/chosen");
> > @@ -106,12 +135,27 @@ static int setup_dtb(struct kimage *image,
> > return -EINVAL;
> > }
> >  
> > +   /* add kaslr-seed */
> > +   ret = fdt_delprop(dtb, nodeoffset, FDT_PSTR_KASLR_SEED);
> > +   if (ret && (ret != -FDT_ERR_NOTFOUND))
> > +   return -EINVAL;
> > +
> > +   if (random_ready) {
> > +   get_random_bytes(&value, sizeof(value));
> 
> get_random_u64() ?

OK.

> > +   ret = fdt_setprop_u64(dtb, nodeoffset, FDT_PSTR_KASLR_SEED,
> > +   value);
> > +   if (ret)
> > +   return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
> > +   } else {
> 
> Wouldn't we be better off preserving the previous seed here, if it was
> present?

While there's no guarantee that dtb won't be (partially) broken
on failure, I will let this function return successfully
by deleting succeeding fdt_delprop().


> > +   pr_notice("kaslr-seed won't be fed\n");
> 
> "fed" is probably not the right word here.

=> won't be *provided* on kexec?

-Takahiro Akashi

> Will


Re: [PATCH v16 15/16] arm64: kexec_file: add kernel signature verification support

2018-12-10 Thread AKASHI Takahiro
On Fri, Nov 30, 2018 at 01:21:14PM +, Will Deacon wrote:
> On Thu, Nov 15, 2018 at 02:52:54PM +0900, AKASHI Takahiro wrote:
> > With this patch, kernel verification can be done without IMA security
> > subsystem enabled. Turn on CONFIG_KEXEC_VERIFY_SIG instead.
> > 
> > On x86, a signature is embedded into a PE file (Microsoft's format) header
> > of binary. Since arm64's "Image" can also be seen as a PE file as far as
> > CONFIG_EFI is enabled, we adopt this format for kernel signing.
> > 
> > You can create a signed kernel image with:
> >     $ sbsign --key ${KEY} --cert ${CERT} Image
> > 
> > Signed-off-by: AKASHI Takahiro 
> > Cc: Catalin Marinas 
> > Cc: Will Deacon 
> > Reviewed-by: James Morse 
> > ---
> >  arch/arm64/Kconfig  | 24 
> >  arch/arm64/kernel/kexec_image.c | 17 +
> >  2 files changed, 41 insertions(+)
> > 
> > diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> > index 93dc4d36d6db..11f3e1a00588 100644
> > --- a/arch/arm64/Kconfig
> > +++ b/arch/arm64/Kconfig
> > @@ -867,6 +867,30 @@ config KEXEC_FILE
> >   for kernel and initramfs as opposed to list of segments as
> >   accepted by previous system call.
> >  
> > +config KEXEC_VERIFY_SIG
> > +   bool "Verify kernel signature during kexec_file_load() syscall"
> > +   depends on KEXEC_FILE
> > +   help
> > + Select this option to verify a signature with loaded kernel
> > + image. If configured, any attempt of loading a image without
> > + valid signature will fail.
> > +
> > + In addition to that option, you need to enable signature
> > + verification for the corresponding kernel image type being
> > + loaded in order for this to work.
> > +
> > +config KEXEC_IMAGE_VERIFY_SIG
> > +   bool "Enable Image signature verification support"
> > +   default y
> > +   depends on KEXEC_VERIFY_SIG
> > +   depends on EFI && SIGNED_PE_FILE_VERIFICATION
> > +   help
> > + Enable Image signature verification support.
> > +
> > +comment "Support for PE file signature verification disabled"
> > +   depends on KEXEC_VERIFY_SIG
> > +   depends on !EFI || !SIGNED_PE_FILE_VERIFICATION
> > +
> >  config CRASH_DUMP
> > bool "Build kdump crash kernel"
> > help
> > diff --git a/arch/arm64/kernel/kexec_image.c 
> > b/arch/arm64/kernel/kexec_image.c
> > index 9f0d8b5d62d3..d1c6c54c22e3 100644
> > --- a/arch/arm64/kernel/kexec_image.c
> > +++ b/arch/arm64/kernel/kexec_image.c
> > @@ -12,7 +12,9 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >  #include 
> > +#include 
> >  #include 
> >  #include 
> >  #include 
> > @@ -29,6 +31,10 @@ static int image_probe(const char *kernel_buf, unsigned 
> > long kernel_len)
> > sizeof(h->magic)))
> > return -EINVAL;
> >  
> > +   pr_debug("PE format: %s\n",
> > +   memcmp(&((struct mz_hdr *)h)->magic, "MZ", 2) ?
> > +   "no" : "yes");
> > 
> 
> Is this hunk really necessary? I'd prefer not to commit pr_debug()
> invocations.

This line comes from kexec-tools' code, but I don't mind removing it.
(as lots of lines diverge now from kexec-tools.)

-Takahiro Akashi


> Will


[PATCH v14 12/16] arm64: kexec_file: add crash dump support

2018-09-07 Thread AKASHI Takahiro
Enabling crash dump (kdump) includes
* prepare contents of ELF header of a core dump file, /proc/vmcore,
  using crash_prepare_elf64_headers(), and
* add two device tree properties, "linux,usable-memory-range" and
  "linux,elfcorehdr", which represent respectively a memory range
  to be used by crash dump kernel and the header's location

Signed-off-by: AKASHI Takahiro 
Cc: Catalin Marinas 
Cc: Will Deacon 
Reviewed-by: James Morse 
---
 arch/arm64/include/asm/kexec.h |   4 +
 arch/arm64/kernel/machine_kexec_file.c | 113 -
 2 files changed, 114 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 5e673481b3a3..1b2c27026ae0 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -99,6 +99,10 @@ static inline void crash_post_resume(void) {}
 struct kimage_arch {
void *dtb;
unsigned long dtb_mem;
+   /* Core ELF header buffer */
+   void *elf_headers;
+   unsigned long elf_headers_mem;
+   unsigned long elf_headers_sz;
 };
 
 /**
diff --git a/arch/arm64/kernel/machine_kexec_file.c 
b/arch/arm64/kernel/machine_kexec_file.c
index 05fb2d4e6fef..ecaecb122cad 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -16,10 +16,14 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 
 /* relevant device tree properties */
+#define FDT_PSTR_KEXEC_ELFHDR  "linux,elfcorehdr"
+#define FDT_PSTR_MEM_RANGE "linux,usable-memory-range"
 #define FDT_PSTR_INITRD_STA"linux,initrd-start"
 #define FDT_PSTR_INITRD_END"linux,initrd-end"
 #define FDT_PSTR_BOOTARGS  "bootargs"
@@ -34,6 +38,10 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
vfree(image->arch.dtb);
image->arch.dtb = NULL;
 
+   vfree(image->arch.elf_headers);
+   image->arch.elf_headers = NULL;
+   image->arch.elf_headers_sz = 0;
+
return kexec_image_post_load_cleanup_default(image);
 }
 
@@ -43,12 +51,29 @@ static int setup_dtb(struct kimage *image,
void **dtb_buf, unsigned long *dtb_buf_len)
 {
void *buf = NULL;
-   size_t buf_size;
+   size_t buf_size, range_size;
int nodeoffset;
int ret;
 
+   /* check ranges against root's #address-cells and #size-cells */
+   if (image->type == KEXEC_TYPE_CRASH &&
+   (!of_fdt_cells_size_fitted(image->arch.elf_headers_mem,
+   image->arch.elf_headers_sz) ||
+!of_fdt_cells_size_fitted(crashk_res.start,
+   crashk_res.end - crashk_res.start + 1))) {
+   pr_err("Crash memory region doesn't fit into DT's root cell 
sizes.\n");
+   ret = -EINVAL;
+   goto out_err;
+   }
+
/* duplicate dt blob */
buf_size = fdt_totalsize(initial_boot_params);
+   range_size = of_fdt_reg_cells_size();
+
+   if (image->type == KEXEC_TYPE_CRASH) {
+   buf_size += fdt_prop_len(FDT_PSTR_KEXEC_ELFHDR, range_size);
+   buf_size += fdt_prop_len(FDT_PSTR_MEM_RANGE, range_size);
+   }
 
if (initrd_load_addr) {
/* can be redundant, but trimmed at the end */
@@ -78,6 +103,22 @@ static int setup_dtb(struct kimage *image,
goto out_err;
}
 
+   if (image->type == KEXEC_TYPE_CRASH) {
+   /* add linux,elfcorehdr */
+   ret = fdt_setprop_reg(buf, nodeoffset, FDT_PSTR_KEXEC_ELFHDR,
+   image->arch.elf_headers_mem,
+   image->arch.elf_headers_sz);
+   if (ret)
+   goto out_err;
+
+   /* add linux,usable-memory-range */
+   ret = fdt_setprop_reg(buf, nodeoffset, FDT_PSTR_MEM_RANGE,
+   crashk_res.start,
+   crashk_res.end - crashk_res.start + 1);
+   if (ret)
+   goto out_err;
+   }
+
/* add bootargs */
if (cmdline) {
ret = fdt_setprop_string(buf, nodeoffset, FDT_PSTR_BOOTARGS,
@@ -135,6 +176,43 @@ static int setup_dtb(struct kimage *image,
return ret;
 }
 
+static int prepare_elf_headers(void **addr, unsigned long *sz)
+{
+   struct crash_mem *cmem;
+   unsigned int nr_ranges;
+   int ret;
+   u64 i;
+   phys_addr_t start, end;
+
+   nr_ranges = 1; /* for exclusion of crashkernel region */
+   for_each_mem_range(i, &memblock.memory, NULL, NUMA_NO_NODE,
+   MEMBLOCK_NONE, &start, &end, NULL)
+   nr_ranges++;
+
+   cmem = kmalloc(sizeof(struct crash_mem) +
+   sizeof(struct crash_me

[PATCH v14 11/16] arm64: kexec_file: allow for loading Image-format kernel

2018-09-07 Thread AKASHI Takahiro
This patch provides kexec_file_ops for "Image"-format kernel. In this
implementation, a binary is always loaded with a fixed offset identified
in text_offset field of its header.

Regarding signature verification for trusted boot, this patch doesn't
contains CONFIG_KEXEC_VERIFY_SIG support, which is to be added later
in this series, but file-attribute-based verification is still a viable
option by enabling IMA security subsystem.

You can sign(label) a to-be-kexec'ed kernel image on target file system
with:
$ evmctl ima_sign --key /path/to/private_key.pem Image

On live system, you must have IMA enforced with, at least, the following
security policy:
"appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig"

See more details about IMA here:
https://sourceforge.net/p/linux-ima/wiki/Home/

Signed-off-by: AKASHI Takahiro 
Cc: Catalin Marinas 
Cc: Will Deacon 
Reviewed-by: James Morse 
---
 arch/arm64/include/asm/kexec.h |  28 +++
 arch/arm64/kernel/Makefile |   2 +-
 arch/arm64/kernel/kexec_image.c| 108 +
 arch/arm64/kernel/machine_kexec_file.c |   1 +
 4 files changed, 138 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/kernel/kexec_image.c

diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 157b2897d911..5e673481b3a3 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -101,6 +101,34 @@ struct kimage_arch {
unsigned long dtb_mem;
 };
 
+/**
+ * struct arm64_image_header - arm64 kernel image header
+ * See Documentation/arm64/booting.txt for details
+ *
+ * @mz_magic: DOS header magic number ('MZ', optional)
+ * @code1: Instruction (branch to stext)
+ * @text_offset: Image load offset
+ * @image_size: Effective image size
+ * @flags: Bit-field flags
+ * @reserved: Reserved
+ * @magic: Magic number
+ * @pe_header: Offset to PE COFF header (optional)
+ **/
+
+struct arm64_image_header {
+   __le16 mz_magic; /* also code0 */
+   __le16 pad;
+   __le32 code1;
+   __le64 text_offset;
+   __le64 image_size;
+   __le64 flags;
+   __le64 reserved[3];
+   __le32 magic;
+   __le32 pe_header;
+};
+
+extern const struct kexec_file_ops kexec_image_ops;
+
 struct kimage;
 
 extern int arch_kimage_file_post_load_cleanup(struct kimage *image);
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 8f1326b2d327..8cd514855eec 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -51,7 +51,7 @@ arm64-obj-$(CONFIG_RANDOMIZE_BASE)+= kaslr.o
 arm64-obj-$(CONFIG_HIBERNATION)+= hibernate.o hibernate-asm.o
 arm64-obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o
\
   cpu-reset.o
-arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o
+arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o
 arm64-obj-$(CONFIG_ARM64_RELOC_TEST)   += arm64-reloc-test.o
 arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
 arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
new file mode 100644
index ..d64f5e9f9d22
--- /dev/null
+++ b/arch/arm64/kernel/kexec_image.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec image loader
+
+ * Copyright (C) 2018 Linaro Limited
+ * Author: AKASHI Takahiro 
+ */
+
+#define pr_fmt(fmt)"kexec_file(Image): " fmt
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static int image_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+   const struct arm64_image_header *h;
+
+   h = (const struct arm64_image_header *)(kernel_buf);
+
+   if (!h || (kernel_len < sizeof(*h)) ||
+   memcmp(&h->magic, ARM64_MAGIC, sizeof(h->magic)))
+   return -EINVAL;
+
+   return 0;
+}
+
+static void *image_load(struct kimage *image,
+   char *kernel, unsigned long kernel_len,
+   char *initrd, unsigned long initrd_len,
+   char *cmdline, unsigned long cmdline_len)
+{
+   struct arm64_image_header *h;
+   u64 flags, value;
+   struct kexec_buf kbuf;
+   unsigned long text_offset;
+   struct kexec_segment *kernel_segment;
+   int ret;
+
+   /* Don't support old kernel */
+   h = (struct arm64_image_header *)kernel;
+   if (!h->text_offset)
+   return ERR_PTR(-EINVAL);
+
+   /* Check cpu features */
+   flags = le64_to_cpu(h->flags);
+   value = head_flag_field(flags, HEAD_FLAG_BE);
+   if (((value == HEAD_FLAG_BE) && !IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) ||
+   ((value != HEAD_FLAG_BE) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)))
+

[PATCH v14 08/16] arm64: cpufeature: add MMFR0 helper functions

2018-09-07 Thread AKASHI Takahiro
Those helper functions for MMFR0 register will be used later by kexec_file
loader.

Signed-off-by: AKASHI Takahiro 
Cc: Catalin Marinas 
Cc: Will Deacon 
Reviewed-by: James Morse 
---
 arch/arm64/include/asm/cpufeature.h | 48 +
 1 file changed, 48 insertions(+)

diff --git a/arch/arm64/include/asm/cpufeature.h 
b/arch/arm64/include/asm/cpufeature.h
index 1717ba1db35d..cd90b5252d6d 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -486,11 +486,59 @@ static inline bool system_supports_32bit_el0(void)
return cpus_have_const_cap(ARM64_HAS_32BIT_EL0);
 }
 
+static inline bool system_supports_4kb_granule(void)
+{
+   u64 mmfr0;
+   u32 val;
+
+   mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+   val = cpuid_feature_extract_unsigned_field(mmfr0,
+   ID_AA64MMFR0_TGRAN4_SHIFT);
+
+   return val == ID_AA64MMFR0_TGRAN4_SUPPORTED;
+}
+
+static inline bool system_supports_64kb_granule(void)
+{
+   u64 mmfr0;
+   u32 val;
+
+   mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+   val = cpuid_feature_extract_unsigned_field(mmfr0,
+   ID_AA64MMFR0_TGRAN64_SHIFT);
+
+   return val == ID_AA64MMFR0_TGRAN64_SUPPORTED;
+}
+
+static inline bool system_supports_16kb_granule(void)
+{
+   u64 mmfr0;
+   u32 val;
+
+   mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+   val = cpuid_feature_extract_unsigned_field(mmfr0,
+   ID_AA64MMFR0_TGRAN16_SHIFT);
+
+   return val == ID_AA64MMFR0_TGRAN16_SUPPORTED;
+}
+
 static inline bool system_supports_mixed_endian_el0(void)
 {
return 
id_aa64mmfr0_mixed_endian_el0(read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1));
 }
 
+static inline bool system_supports_mixed_endian(void)
+{
+   u64 mmfr0;
+   u32 val;
+
+   mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
+   val = cpuid_feature_extract_unsigned_field(mmfr0,
+   ID_AA64MMFR0_BIGENDEL_SHIFT);
+
+   return val == 0x1;
+}
+
 static inline bool system_supports_fpsimd(void)
 {
return !cpus_have_const_cap(ARM64_HAS_NO_FPSIMD);
-- 
2.18.0



Re: [PATCH v2 1/3] arm64: implement ftrace with regs

2018-08-29 Thread AKASHI Takahiro
On Fri, Aug 17, 2018 at 12:27:24PM +0200, Torsten Duwe wrote:
> Check for compiler support of -fpatchable-function-entry and use it
> to intercept functions immediately on entry, saving the LR in x9.
> Disable ftracing in efi/libstub, because this triggers cross-section
> linker errors now (-pg is disabled already for those files).
> Add an ftrace_caller which can handle LR in x9, as well as an

I think that we have a bit detailed descriptions about what a function's
initial prologue looks like and how it will be patched to enable or
disable ftrace on that function for the sake of better understandings.
(in entry-ftrace.S or ftrace.c?)

> ftrace_regs_caller that additionally writes out a set of pt_regs
> for inspection.
> 
> Signed-off-by: Torsten Duwe 
> 
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -110,6 +110,7 @@ config ARM64
>   select HAVE_DEBUG_KMEMLEAK
>   select HAVE_DMA_CONTIGUOUS
>   select HAVE_DYNAMIC_FTRACE
> + select HAVE_DYNAMIC_FTRACE_WITH_REGS
>   select HAVE_EFFICIENT_UNALIGNED_ACCESS
>   select HAVE_FTRACE_MCOUNT_RECORD
>   select HAVE_FUNCTION_TRACER
> --- a/arch/arm64/Makefile
> +++ b/arch/arm64/Makefile
> @@ -78,6 +78,15 @@ ifeq ($(CONFIG_ARM64_MODULE_PLTS),y)
>  KBUILD_LDFLAGS_MODULE+= -T $(srctree)/arch/arm64/kernel/module.lds
>  endif
>  
> +ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
> +  CC_FLAGS_FTRACE := -fpatchable-function-entry=2
> +  KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
> +  ifeq ($(call cc-option,-fpatchable-function-entry=2),)
> +$(error Cannot use CONFIG_DYNAMIC_FTRACE_WITH_REGS: \
> + -fpatchable-function-entry not supported by compiler)
> +  endif
> +endif
> +
>  # Default value
>  head-y   := arch/arm64/kernel/head.o
>  
> --- a/arch/arm64/include/asm/ftrace.h
> +++ b/arch/arm64/include/asm/ftrace.h
> @@ -16,6 +16,13 @@
>  #define MCOUNT_ADDR  ((unsigned long)_mcount)
>  #define MCOUNT_INSN_SIZE AARCH64_INSN_SIZE
>  
> +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
> +#define ARCH_SUPPORTS_FTRACE_OPS 1
> +#define REC_IP_BRANCH_OFFSET 4

Some explanation about "4" will be helpful here.

> +#else
> +#define REC_IP_BRANCH_OFFSET 0
> +#endif
> +
>  #ifndef __ASSEMBLY__
>  #include 
>  
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -7,9 +7,9 @@ CPPFLAGS_vmlinux.lds  := -DTEXT_OFFSET=$(
>  AFLAGS_head.o:= -DTEXT_OFFSET=$(TEXT_OFFSET)
>  CFLAGS_armv8_deprecated.o := -I$(src)
>  
> -CFLAGS_REMOVE_ftrace.o = -pg
> -CFLAGS_REMOVE_insn.o = -pg
> -CFLAGS_REMOVE_return_address.o = -pg
> +CFLAGS_REMOVE_ftrace.o = -pg $(CC_FLAGS_FTRACE)
> +CFLAGS_REMOVE_insn.o = -pg $(CC_FLAGS_FTRACE)
> +CFLAGS_REMOVE_return_address.o = -pg $(CC_FLAGS_FTRACE)

You don't need to remove "-pg" explicitly here because it won't be added to
XX_CFLAGS when you defines CC_FLAGS_FTRACE.

>  # Object file lists.
>  arm64-obj-y  := debug-monitors.o entry.o irq.o fpsimd.o  
> \
> --- a/drivers/firmware/efi/libstub/Makefile
> +++ b/drivers/firmware/efi/libstub/Makefile
> @@ -11,7 +11,8 @@ cflags-$(CONFIG_X86)+= -m$(BITS) -D__K
>  -fPIC -fno-strict-aliasing -mno-red-zone \
>  -mno-mmx -mno-sse -fshort-wchar
>  
> -cflags-$(CONFIG_ARM64)   := $(subst -pg,,$(KBUILD_CFLAGS)) -fpie
> +cflags-$(CONFIG_ARM64)   := $(filter-out -pg $(CC_FLAGS_FTRACE)\
> +   ,$(KBUILD_CFLAGS)) -fpie
>  cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \
>  -fno-builtin -fpic -mno-single-pic-base
>  
> --- a/arch/arm64/kernel/entry-ftrace.S
> +++ b/arch/arm64/kernel/entry-ftrace.S
> @@ -13,6 +13,8 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
>  
>  /*
>   * Gcc with -pg will put the following code in the beginning of each 
> function:
> @@ -123,6 +125,7 @@ skip_ftrace_call: // }
>  ENDPROC(_mcount)
>  
>  #else /* CONFIG_DYNAMIC_FTRACE */
> +#ifndef CC_USING_PATCHABLE_FUNCTION_ENTRY

I think that using CONFIG_DYNAMIC_FTRACE_WITH_REG here sounds more consistent.

>  /*
>   * _mcount() is used to build the kernel with -pg option, but all the branch
>   * instructions to _mcount() are replaced to NOP initially at kernel start 
> up,
> @@ -162,6 +165,88 @@ ftrace_graph_call:   // 
> ftrace_graph_cal
>  
>   mcount_exit
>  ENDPROC(ftrace_caller)
> +#else /* CC_USING_PATCHABLE_FUNCTION_ENTRY */
> +ENTRY(_mcount)
> + mov x10, lr
> + mov lr, x9
> + ret x10
> +ENDPROC(_mcount)

I don't think we need a definition of _mcount because patchable-function-entry
won't generate a call site of _mcount nor other code does.
You can simply define MCOUNT_ADDR as ULONG_MAX.

> +ENTRY(ftrace_regs_caller)
> + stp x29, x9, [sp, #-16]!
> + sub sp, sp, #S_FRAME_SIZE
> +
> + stp x10, x11, [sp, #80]
> + stp x12, x13, [s

[PATCH v13 16/16] arm64: kexec_file: add kaslr support

2018-08-01 Thread AKASHI Takahiro
Adding "kaslr-seed" to dtb enables triggering kaslr, or kernel virtual
address randomization, at secondary kernel boot. We always do this as
it will have no harm on kaslr-incapable kernel.

We don't have any "switch" to turn off this feature directly, but still
can suppress it by passing "nokaslr" as a kernel boot argument.

Signed-off-by: AKASHI Takahiro 
Cc: Catalin Marinas 
Cc: Will Deacon 
---
 arch/arm64/kernel/machine_kexec_file.c | 45 ++
 1 file changed, 45 insertions(+)

diff --git a/arch/arm64/kernel/machine_kexec_file.c 
b/arch/arm64/kernel/machine_kexec_file.c
index ecaecb122cad..967db9824e3f 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -27,6 +28,7 @@
 #define FDT_PSTR_INITRD_STA"linux,initrd-start"
 #define FDT_PSTR_INITRD_END"linux,initrd-end"
 #define FDT_PSTR_BOOTARGS  "bootargs"
+#define FDT_PSTR_KASLR_SEED"kaslr-seed"
 
 const struct kexec_file_ops * const kexec_file_loaders[] = {
&kexec_image_ops,
@@ -45,6 +47,32 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
return kexec_image_post_load_cleanup_default(image);
 }
 
+/* crng needs to have been initialized for providing kaslr-seed */
+static int random_ready;
+
+static void random_ready_notified(struct random_ready_callback *unused)
+{
+   random_ready = 1;
+}
+
+static struct random_ready_callback random_ready_cb = {
+   .func = random_ready_notified,
+};
+
+static __init int init_random_ready_cb(void)
+{
+   int ret;
+
+   ret = add_random_ready_callback(&random_ready_cb);
+   if (ret == -EALREADY)
+   random_ready = 1;
+   else if (ret)
+   pr_warn("failed to add a callback for random_ready\n");
+
+   return 0;
+}
+late_initcall(init_random_ready_cb)
+
 static int setup_dtb(struct kimage *image,
unsigned long initrd_load_addr, unsigned long initrd_len,
char *cmdline, unsigned long cmdline_len,
@@ -53,6 +81,7 @@ static int setup_dtb(struct kimage *image,
void *buf = NULL;
size_t buf_size, range_size;
int nodeoffset;
+   u64 value;
int ret;
 
/* check ranges against root's #address-cells and #size-cells */
@@ -85,6 +114,8 @@ static int setup_dtb(struct kimage *image,
/* can be redundant, but trimmed at the end */
buf_size += fdt_prop_len(FDT_PSTR_BOOTARGS, cmdline_len);
 
+   buf_size += fdt_prop_len(FDT_PSTR_KASLR_SEED, sizeof(u64));
+
buf = vmalloc(buf_size);
if (!buf) {
ret = -ENOMEM;
@@ -164,6 +195,20 @@ static int setup_dtb(struct kimage *image,
}
}
 
+   /* add kaslr-seed */
+   fdt_delprop(buf, nodeoffset, FDT_PSTR_KASLR_SEED);
+   if (random_ready) {
+   get_random_bytes(&value, sizeof(value));
+   ret = fdt_setprop_u64(buf, nodeoffset, FDT_PSTR_KASLR_SEED,
+   value);
+   if (ret) {
+   ret = -EINVAL;
+   goto out_err;
+   }
+   } else {
+   pr_notice("kaslr-seed won't be fed\n");
+   }
+
/* trim a buffer */
fdt_pack(buf);
*dtb_buf = buf;
-- 
2.18.0



[PATCH v13 00/16] subject: arm64: kexec: add kexec_file_load() support

2018-08-01 Thread AKASHI Takahiro
 CONFIG_KEXEC_FILE_IMAGE_FMT and introduce
  CONFIG_KEXEC_IMAGE_VERIFY_SIG, much similar to x86 but quite redundant
  for now.
* In addition, update/modify dependencies of KEXEC_IMAGE_VERIFY_SIG

Changes in v7 (Dec 4, 2017)
* rebased to v4.15-rc2
* re-organize the patch set to separate KEXEC_FILE_VERIFY_SIG-related
  code from the others
* revamp factored-out code in kernel/kexec_file.c due to the changes
  in original x86 code
* redefine walk_sys_ram_res_rev() prototype due to change of callback
  type in the counterpart, walk_sys_ram_res()
* make KEXEC_FILE_IMAGE_FMT default on if KEXEC_FILE selected

Changes in v6 (Oct 24, 2017)
* fix a for-loop bug in _kexec_kernel_image_probe() per Julien

Changes in v5 (Oct 10, 2017)
* fix kbuild errors around patch #3
per Julien's comments,
* fix a bug in walk_system_ram_res_rev() with some cleanup
* modify fdt_setprop_range() to use vmalloc()
* modify fill_property() to use memset()

Changes in v4 (Oct 2, 2017)
* reinstate x86's arch_kexec_kernel_image_load()
* rename weak arch_kexec_kernel_xxx() to _kexec_kernel_xxx() for
  better re-use
* constify kexec_file_loaders[]

Changes in v3 (Sep 15, 2017)
* fix kbuild test error
* factor out arch_kexec_kernel_*() & arch_kimage_file_post_load_cleanup()
* remove CONFIG_CRASH_CORE guard from kexec_file.c
* add vmapped kernel region to vmcore for gdb backtracing
  (see prepare_elf64_headers())
* merge asm/kexec_file.h into asm/kexec.h
* and some cleanups

Changes in v2 (Sep 8, 2017)
* move core-header-related functions from crash_core.c to kexec_file.c
* drop hash-check code from purgatory
* modify purgatory asm to remove arch_kexec_apply_relocations_add()
* drop older kernel support
* drop vmlinux support (at least, for this series)


Patch #1 to #10 are essential part for KEXEC_FILE support
(additionally allowing for IMA-based verification):
  Patch #1 to #6 are all preparatory patches on generic side.
  Patch #7 to #11 are to enable kexec_file_load on arm64.

Patch #12 to #13 are for KEXEC_VERIFY_SIG (arch-specific verification)
support

AKASHI Takahiro (16):
  asm-generic: add kexec_file_load system call to unistd.h
  kexec_file: make kexec_image_post_load_cleanup_default() global
  s390, kexec_file: drop arch_kexec_mem_walk()
  powerpc, kexec_file: factor out memblock-based arch_kexec_walk_mem()
  kexec_file: kexec_walk_memblock() only walks a dedicated region at
kdump
  of/fdt: add helper functions for handling properties
  arm64: add image head flag definitions
  arm64: cpufeature: add MMFR0 helper functions
  arm64: enable KEXEC_FILE config
  arm64: kexec_file: load initrd and device-tree
  arm64: kexec_file: allow for loading Image-format kernel
  arm64: kexec_file: add crash dump support
  arm64: kexec_file: invoke the kernel without purgatory
  include: pe.h: remove message[] from mz header definition
  arm64: kexec_file: add kernel signature verification support
  arm64: kexec_file: add kaslr support

 arch/arm64/Kconfig  |  33 ++
 arch/arm64/include/asm/boot.h   |  15 +
 arch/arm64/include/asm/cpufeature.h |  48 +++
 arch/arm64/include/asm/kexec.h  |  49 +++
 arch/arm64/kernel/Makefile  |   3 +-
 arch/arm64/kernel/cpu-reset.S   |   8 +-
 arch/arm64/kernel/head.S|   2 +-
 arch/arm64/kernel/kexec_image.c | 123 +++
 arch/arm64/kernel/machine_kexec.c   |  12 +-
 arch/arm64/kernel/machine_kexec_file.c  | 357 
 arch/arm64/kernel/relocate_kernel.S |   3 +-
 arch/powerpc/kernel/machine_kexec_file_64.c |  54 ---
 arch/s390/kernel/machine_kexec_file.c   |  10 -
 drivers/of/fdt.c|  62 +++-
 include/linux/kexec.h   |   3 +-
 include/linux/of_fdt.h  |  10 +-
 include/linux/pe.h  |   2 +-
 include/uapi/asm-generic/unistd.h   |   4 +-
 kernel/kexec_file.c |  69 +++-
 19 files changed, 782 insertions(+), 85 deletions(-)
 create mode 100644 arch/arm64/kernel/kexec_image.c
 create mode 100644 arch/arm64/kernel/machine_kexec_file.c

-- 
2.18.0



[PATCH v13 04/16] powerpc, kexec_file: factor out memblock-based arch_kexec_walk_mem()

2018-08-01 Thread AKASHI Takahiro
Memblock list is another source for usable system memory layout.
So move powerpc's arch_kexec_walk_mem() to common code so that other
memblock-based architectures, particularly arm64, can also utilise it.
A moved function is now renamed to kexec_walk_memblock() and integrated
into kexec_locate_mem_hole(), which will now be usable for all
architectures with no need for overriding arch_kexec_walk_mem().

With this change, arch_kexec_walk_mem() need no longer be a weak function,
and was now renamed to kexec_walk_resources().

Since powerpc doesn't support kdump in its kexec_file_load(), the current
kexec_walk_memblock() won't work for kdump either in this form, this will
be fixed in the next patch.

Signed-off-by: AKASHI Takahiro 
Cc: "Eric W. Biederman" 
Acked-by: Dave Young 
Cc: Vivek Goyal 
Cc: Baoquan He 
Acked-by: James Morse 
---
 arch/powerpc/kernel/machine_kexec_file_64.c | 54 ---
 include/linux/kexec.h   |  2 -
 kernel/kexec_file.c | 60 +++--
 3 files changed, 57 insertions(+), 59 deletions(-)

diff --git a/arch/powerpc/kernel/machine_kexec_file_64.c 
b/arch/powerpc/kernel/machine_kexec_file_64.c
index 0bd23dc789a4..5357b09902c5 100644
--- a/arch/powerpc/kernel/machine_kexec_file_64.c
+++ b/arch/powerpc/kernel/machine_kexec_file_64.c
@@ -24,7 +24,6 @@
 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -46,59 +45,6 @@ int arch_kexec_kernel_image_probe(struct kimage *image, void 
*buf,
return kexec_image_probe_default(image, buf, buf_len);
 }
 
-/**
- * arch_kexec_walk_mem - call func(data) for each unreserved memory block
- * @kbuf:  Context info for the search. Also passed to @func.
- * @func:  Function to call for each memory block.
- *
- * This function is used by kexec_add_buffer and kexec_locate_mem_hole
- * to find unreserved memory to load kexec segments into.
- *
- * Return: The memory walk will stop when func returns a non-zero value
- * and that value will be returned. If all free regions are visited without
- * func returning non-zero, then zero will be returned.
- */
-int arch_kexec_walk_mem(struct kexec_buf *kbuf,
-   int (*func)(struct resource *, void *))
-{
-   int ret = 0;
-   u64 i;
-   phys_addr_t mstart, mend;
-   struct resource res = { };
-
-   if (kbuf->top_down) {
-   for_each_free_mem_range_reverse(i, NUMA_NO_NODE, 0,
-   &mstart, &mend, NULL) {
-   /*
-* In memblock, end points to the first byte after the
-* range while in kexec, end points to the last byte
-* in the range.
-*/
-   res.start = mstart;
-   res.end = mend - 1;
-   ret = func(&res, kbuf);
-   if (ret)
-   break;
-   }
-   } else {
-   for_each_free_mem_range(i, NUMA_NO_NODE, 0, &mstart, &mend,
-   NULL) {
-   /*
-* In memblock, end points to the first byte after the
-* range while in kexec, end points to the last byte
-* in the range.
-*/
-   res.start = mstart;
-   res.end = mend - 1;
-   ret = func(&res, kbuf);
-   if (ret)
-   break;
-   }
-   }
-
-   return ret;
-}
-
 /**
  * setup_purgatory - initialize the purgatory's global variables
  * @image: kexec image.
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 49ab758f4d91..c196bfd11bee 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -184,8 +184,6 @@ int __weak arch_kexec_apply_relocations(struct 
purgatory_info *pi,
const Elf_Shdr *relsec,
const Elf_Shdr *symtab);
 
-int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,
-  int (*func)(struct resource *, void *));
 extern int kexec_add_buffer(struct kexec_buf *kbuf);
 int kexec_locate_mem_hole(struct kexec_buf *kbuf);
 
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index bf39df5e5bb9..1073ef56a95d 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -501,6 +502,55 @@ static int locate_mem_hole_callback(struct resource *res, 
void *arg)
return locate_mem_hole_bottom_up(start, end, kbuf);
 }
 
+#if defined(CONFIG_HAVE_MEMBLOCK) && !defined(CONFIG_ARCH_DISCARD_MEMBLOCK)
+static int kexec_walk_memblock(struct kexec_buf *kbuf,
+   

Re: [PATCH v12 16/16] arm64: kexec_file: add kaslr support

2018-08-01 Thread AKASHI Takahiro
James,

All the changes mentioned below were applied to my coming v13.

On Fri, Jul 27, 2018 at 10:22:31AM +0100, James Morse wrote:
> Hi Akashi,
> 
> 
> On 07/27/2018 09:31 AM, AKASHI Takahiro wrote:
> >On Thu, Jul 26, 2018 at 02:40:49PM +0100, James Morse wrote:
> >>On 24/07/18 07:57, AKASHI Takahiro wrote:
> >>>Adding "kaslr-seed" to dtb enables triggering kaslr, or kernel virtual
> >>>address randomization, at secondary kernel boot.
> >>Hmm, there are three things that get moved by CONFIG_RANDOMIZE_BASE. The 
> >>kernel
> >>physical placement when booted via the EFIstub, the kernel-text VAs and the
> >>location of memory in the linear-map region. Adding the kaslr-seed only 
> >>does the
> >>last two.
> >Yes, but I think that I and Mark has agreed that "kaslr" meant
> >"virtual" randomisation, not including "physical" randomisation.
> Okay, I'll update my terminology!
> 
> 
> >>This means the physical placement of the new kernel is predictable from
> >>/proc/iomem ... but this also tells you the physical placement of the 
> >>current
> >>kernel, so I don't think this is a problem.
> >>
> >>
> >>>We always do this as it will have no harm on kaslr-incapable kernel.
> >>>We don't have any "switch" to turn off this feature directly, but still
> >>>can suppress it by passing "nokaslr" as a kernel boot argument.
> >>
> >>>diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> >>>b/arch/arm64/kernel/machine_kexec_file.c
> >>>index 7356da5a53d5..47a4fbd0dc34 100644
> >>>--- a/arch/arm64/kernel/machine_kexec_file.c
> >>>+++ b/arch/arm64/kernel/machine_kexec_file.c
> >>>@@ -158,6 +160,12 @@ static int setup_dtb(struct kimage *image,
> >>Don't you need to reserve some space in the area you vmalloc()d for the DT?
> >No, I don't think so.
> >All the data to be loaded are temporarily saved in kexec buffers,
> >which will eventually be copied to target locations in machine_kexec
> >(arm64_relocate_new_kernel, which, unlike its name, will handle
> >not only kernel but also other data as well).
> 
> I think we're speaking at cross purposes. Don't you need:
> 
> | buf_size += fdt_prop_len("kaslr―seed", sizeof(u64));
> 
> 
> You can't assume the existing DTB had a kaslr-seed property, and the
> difference may take us over a PAGE_SIZE boundary.

I see, I will add that.

> 
> >
> >>
> >>>+  /* add kaslr-seed */
> >>>+  get_random_bytes(&value, sizeof(value));
> >>What happens if the crng isn't ready?
> >>
> >>It looks like this will print a warning that these random-bytes aren't 
> >>really up
> >>to standard, but the new kernel doesn't know this happened.
> >>
> >>crng_ready() isn't exposed, all we could do now is
> >>wait_for_random_bytes(), but that may wait forever because we do this
> >>unconditionally.
> >>
> >>I'd prefer to leave this feature until we can check crng_ready(), and skip
> >>adding a dodgy-seed if its not-ready. This avoids polluting the 
> >>next-kernel's
> >>entropy pool.
> >OK. I would try to follow the same way as Bhupesh's userspace patch
> >does for kaslr-seed:
> >http://lists.infradead.org/pipermail/kexec/2018-April/020564.html
> 
> (I really don't understand this 'copying code from user-space' that happens
> with kexec_file_load)
> 
> 
> >   if (not found kaslr-seed in 1st kernel's dtb)
> >  don't care; go ahead
> 
> Don' t bother. As you say in the commit-message its harmless if the new
> kernel doesn't support it.
> Always having this would let you use kexec_file_load as a bootloader that
> can get the crng to
> provide decent entropy even if the platform bootloader can't.

OK, but anyway previous "kaslr-seed" will be dropped first.

> 
> >   else
> >  if (current kaslr-seed != 0)
> > error
> 
> Don't bother. If this happens its a bug in another part of the kernel that
> doesn't affect this one. We aren't second-guessing the file-system when we
> read the kernel-fd, lets keep this simple.

OK

> >  if (crng_ready()) ; FIXME, it's a local macro
> > get_random_bytes(non-blocking)
> > set new kaslr-seed
> >  else
> > error
> error? Something like pr_warn_once().

It was changed to pr_notice() since there is nothing wrong.

Thanks,
-Takahiro AKASHI

> I thought the kaslr-seed was added to the entropy pool, but now I look again
> I see its a separate EFI table. So the new kernel will add the same entropy
> ... that doesn't sound clever. (I can't see where its zero'd or
> re-initialised)
> 
> 
> 
> Thanks,
> 
> James


Re: [PATCH 1/1] arm64: kexec: machine_kexec should call __flush_icache_range

2018-07-30 Thread AKASHI Takahiro
On Mon, Jul 30, 2018 at 04:36:28PM -0500, Dave Kleikamp wrote:
> On 07/30/2018 11:57 AM, Will Deacon wrote:
> > On Mon, Jul 30, 2018 at 11:46:24AM -0500, Dave Kleikamp wrote:
> >> On 07/30/2018 11:22 AM, Will Deacon wrote:
> >>> On Mon, Jul 30, 2018 at 05:16:42PM +0100, Catalin Marinas wrote:
>  On Mon, Jul 30, 2018 at 10:29:21AM -0500, Dave Kleikamp wrote:
> > machine_kexec flushes the reboot_code_buffer from the icache
> > after stopping the other cpus.
> >
> > Commit 3b8c9f1cdfc5 ("arm64: IPI each CPU after invalidating the I-cache
> > for kernel mappings") added an IPI call to flush_icache_range, which
> > causes a hang here, so replace the call with __flush_icache_range
> 
>  While machine_kexec() may be called with interrupts disabled (IIUC) and
>  we shouldn't IPI other CPUs, I don't understand why it hangs here. Are
>  there any other CPUs online at this point?
> >>>
> >>> The BUG_ON and WARN_ON at the start of machine_kexec() suggest to me that
> >>> this should only happen if we're kexec'ing a crash kernel and
> >>> smp_crash_stop_failed(). Is that something we need to care about?
> >>
> >> I observed the hang trying to kexec a crash kernel and I did not see the
> >> warning that smp_crash_stop_failed(). I'm not exactly sure why
> >> flush_icache_range() hung (but it did), but I think that
> >> __flush_icache_range() makes more sense here anyway.
> > 
> > Yeah, I'll pick the patch up, but it would be nice to understand the
> > failure case you observed.
> 
> I see why it failed. ipi_cpu_crash_stop() does not call
> set_cpu_online(cpu, false) the way ipi_cpu_stop() does. So
> cpu_online_mask is still populated with the stopped cpus.
> 
> Any reason why it isn't called there?

Because I wanted that saved cpu-related state be as close to as it was
at panic.
If cpus go offline, the core dump would show that all the cores but
a panicked one be offline whether or not they actually were.

Thanks,
-Takahiro AKASHI

> Thanks,
> Dave
> 
> > 
> > Will
> > 


Re: [PATCH v12 04/16] powerpc, kexec_file: factor out memblock-based arch_kexec_walk_mem()

2018-07-26 Thread AKASHI Takahiro
On Wed, Jul 25, 2018 at 08:31:29PM +0800, Dave Young wrote:
> On 07/24/18 at 03:57pm, AKASHI Takahiro wrote:
> > Memblock list is another source for usable system memory layout.
> > So move powerpc's arch_kexec_walk_mem() to common code so that other
> > memblock-based architectures, particularly arm64, can also utilise it.
> > A moved function is now renamed to kexec_walk_memblock() and integrated
> > into kexec_locate_mem_hole(), which will now be usable for all
> > architectures with no need for overriding arch_kexec_walk_mem().
> > 
> > kexec_walk_memblock() will not work for kdump in this form, this will be
> > fixed in the next patch.
> > 
> > Signed-off-by: AKASHI Takahiro 
> > Cc: "Eric W. Biederman" 
> > Cc: Dave Young 
> > Cc: Vivek Goyal 
> > Cc: Baoquan He 
> > Acked-by: James Morse 
> > ---
> >  arch/powerpc/kernel/machine_kexec_file_64.c | 54 ---
> >  include/linux/kexec.h   |  2 -
> >  kernel/kexec_file.c | 58 -
> >  3 files changed, 56 insertions(+), 58 deletions(-)
> > 
> > diff --git a/arch/powerpc/kernel/machine_kexec_file_64.c 
> > b/arch/powerpc/kernel/machine_kexec_file_64.c
> > index 0bd23dc789a4..5357b09902c5 100644
> > --- a/arch/powerpc/kernel/machine_kexec_file_64.c
> > +++ b/arch/powerpc/kernel/machine_kexec_file_64.c
> > @@ -24,7 +24,6 @@
> >  
> >  #include 
> >  #include 
> > -#include 
> >  #include 
> >  #include 
> >  #include 
> > @@ -46,59 +45,6 @@ int arch_kexec_kernel_image_probe(struct kimage *image, 
> > void *buf,
> > return kexec_image_probe_default(image, buf, buf_len);
> >  }
> >  
> > -/**
> > - * arch_kexec_walk_mem - call func(data) for each unreserved memory block
> > - * @kbuf:  Context info for the search. Also passed to @func.
> > - * @func:  Function to call for each memory block.
> > - *
> > - * This function is used by kexec_add_buffer and kexec_locate_mem_hole
> > - * to find unreserved memory to load kexec segments into.
> > - *
> > - * Return: The memory walk will stop when func returns a non-zero value
> > - * and that value will be returned. If all free regions are visited without
> > - * func returning non-zero, then zero will be returned.
> > - */
> > -int arch_kexec_walk_mem(struct kexec_buf *kbuf,
> > -   int (*func)(struct resource *, void *))
> > -{
> > -   int ret = 0;
> > -   u64 i;
> > -   phys_addr_t mstart, mend;
> > -   struct resource res = { };
> > -
> > -   if (kbuf->top_down) {
> > -   for_each_free_mem_range_reverse(i, NUMA_NO_NODE, 0,
> > -   &mstart, &mend, NULL) {
> > -   /*
> > -* In memblock, end points to the first byte after the
> > -* range while in kexec, end points to the last byte
> > -* in the range.
> > -*/
> > -   res.start = mstart;
> > -   res.end = mend - 1;
> > -   ret = func(&res, kbuf);
> > -   if (ret)
> > -   break;
> > -   }
> > -   } else {
> > -   for_each_free_mem_range(i, NUMA_NO_NODE, 0, &mstart, &mend,
> > -   NULL) {
> > -   /*
> > -* In memblock, end points to the first byte after the
> > -* range while in kexec, end points to the last byte
> > -* in the range.
> > -*/
> > -   res.start = mstart;
> > -   res.end = mend - 1;
> > -   ret = func(&res, kbuf);
> > -   if (ret)
> > -   break;
> > -   }
> > -   }
> > -
> > -   return ret;
> > -}
> > -
> >  /**
> >   * setup_purgatory - initialize the purgatory's global variables
> >   * @image: kexec image.
> > diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> > index 49ab758f4d91..c196bfd11bee 100644
> > --- a/include/linux/kexec.h
> > +++ b/include/linux/kexec.h
> > @@ -184,8 +184,6 @@ int __weak arch_kexec_apply_relocations(struct 
> > purgatory_info *pi,
> > const Elf_Shdr *relsec,
> > const Elf_Shdr *symtab);
> >  
> > -int __w

Re: linux-next: build warning after merge of the arm64 tree

2018-07-23 Thread AKASHI Takahiro
On Tue, Jul 24, 2018 at 09:05:45AM +1000, Stephen Rothwell wrote:
> Hi all,
> 
> After merging the arm64 tree, today's linux-next build (x86_64
> allmodconfig) produced this warning:

Where can I find this specific branch?

> drivers/acpi/Kconfig:6:error: recursive dependency detected!
> drivers/acpi/Kconfig:6:   symbol ACPI depends on EFI

My patch created an additional dependency like:
  menu ACPI
...
depends on IA64 || X86 || (ARM64 && EFI)

> arch/x86/Kconfig:1920:symbol EFI depends on ACPI

So I don't understand why this change makes a warning on x86_64 build.
Is this a real recursive dependency?

Thanks,
-Takahiro AKASHI

> For a resolution refer to Documentation/kbuild/kconfig-language.txt
> subsection "Kconfig recursive dependency limitations"
> 
> Introduced by commit
> 
>   5bcd44083a08 ("drivers: acpi: add dependency of EFI for arm64")
> 
> -- 
> Cheers,
> Stephen Rothwell




[PATCH v3 2/3] efi/arm: map UEFI memory map even w/o runtime services enabled

2018-07-08 Thread AKASHI Takahiro
Under the current implementation, UEFI memory map will be mapped and made
available in virtual mappings only if runtime services are enabled.
But in a later patch, we want to use UEFI memory map in acpi_os_ioremap()
to create mappings of ACPI tables using memory attributes described in
UEFI memory map.
See the following commit:
arm64: acpi: fix alignment fault in accessing ACPI tables

So, as a first step, arm_enter_runtime_services() is modified, alongside
Ard's patch[1], so that UEFI memory map will not be freed even if
efi=noruntime.

[1] https://marc.info/?l=linux-efi&m=152930773507524&w=2

Signed-off-by: AKASHI Takahiro 
Reviewed-by: Ard Biesheuvel 
---
 drivers/firmware/efi/arm-runtime.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/firmware/efi/arm-runtime.c 
b/drivers/firmware/efi/arm-runtime.c
index 59a8c0ec94d5..a00934d263c5 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -117,6 +117,13 @@ static int __init arm_enable_runtime_services(void)
 
efi_memmap_unmap();
 
+   mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
+
+   if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
+   pr_err("Failed to remap EFI memory map\n");
+   return 0;
+   }
+
if (efi_runtime_disabled()) {
pr_info("EFI runtime services will be disabled.\n");
return 0;
@@ -129,13 +136,6 @@ static int __init arm_enable_runtime_services(void)
 
pr_info("Remapping and enabling EFI services.\n");
 
-   mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
-
-   if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
-   pr_err("Failed to remap EFI memory map\n");
-   return -ENOMEM;
-   }
-
if (!efi_virtmap_init()) {
pr_err("UEFI virtual mapping missing or invalid -- runtime 
services will not be available\n");
return -ENOMEM;
-- 
2.17.0



[PATCH v3 3/3] arm64: acpi: fix alignment fault in accessing ACPI

2018-07-08 Thread AKASHI Takahiro
This is a fix against the issue that crash dump kernel may hang up
during booting, which can happen on any ACPI-based system with "ACPI
Reclaim Memory."

(kernel messages after panic kicked off kdump)
   (snip...)
Bye!
   (snip...)
ACPI: Core revision 20170728
pud=2e7d0003, *pmd=2e7c0003, *pte=00e839710707
Internal error: Oops: 9621 [#1] SMP
Modules linked in:
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.14.0-rc6 #1
task: 08d05180 task.stack: 08cc
PC is at acpi_ns_lookup+0x25c/0x3c0
LR is at acpi_ds_load1_begin_op+0xa4/0x294
   (snip...)
Process swapper/0 (pid: 0, stack limit = 0x08cc)
Call trace:
   (snip...)
[] acpi_ns_lookup+0x25c/0x3c0
[] acpi_ds_load1_begin_op+0xa4/0x294
[] acpi_ps_build_named_op+0xc4/0x198
[] acpi_ps_create_op+0x14c/0x270
[] acpi_ps_parse_loop+0x188/0x5c8
[] acpi_ps_parse_aml+0xb0/0x2b8
[] acpi_ns_one_complete_parse+0x144/0x184
[] acpi_ns_parse_table+0x48/0x68
[] acpi_ns_load_table+0x4c/0xdc
[] acpi_tb_load_namespace+0xe4/0x264
[] acpi_load_tables+0x48/0xc0
[] acpi_early_init+0x9c/0xd0
[] start_kernel+0x3b4/0x43c
Code: b9008fb9 2a000318 36380054 32190318 (b94002c0)
---[ end trace c46ed37f9651c58e ]---
Kernel panic - not syncing: Fatal exception
Rebooting in 10 seconds..

(diagnosis)
* This fault is a data abort, alignment fault (ESR=0x9621)
  during reading out ACPI table.
* Initial ACPI tables are normally stored in system ram and marked as
  "ACPI Reclaim memory" by the firmware.
* After the commit f56ab9a5b73c ("efi/arm: Don't mark ACPI reclaim
  memory as MEMBLOCK_NOMAP"), those regions are differently handled
  as they are "memblock-reserved", without NOMAP bit.
* So they are now excluded from device tree's "usable-memory-range"
  which kexec-tools determines based on a current view of /proc/iomem.
* When crash dump kernel boots up, it tries to accesses ACPI tables by
  mapping them with ioremap(), not ioremap_cache(), in acpi_os_ioremap()
  since they are no longer part of mapped system ram.
* Given that ACPI accessor/helper functions are compiled in without
  unaligned access support (ACPI_MISALIGNMENT_NOT_SUPPORTED),
  any unaligned access to ACPI tables can cause a fatal panic.

With this patch, acpi_os_ioremap() always honors memory attribute
information provided by the firmware (EFI) and retaining cacheability
allows the kernel safe access to ACPI tables.

Signed-off-by: AKASHI Takahiro 
Reviewed-by: James Morse 
Reviewed-by: Ard Biesheuvel 
Reported-by and Tested-by: Bhupesh Sharma 
---
 arch/arm64/include/asm/acpi.h | 23 ---
 arch/arm64/kernel/acpi.c  | 11 +++
 2 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 0db62a4cbce2..68bc18cb2b85 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -12,10 +12,12 @@
 #ifndef _ASM_ACPI_H
 #define _ASM_ACPI_H
 
+#include 
 #include 
 #include 
 
 #include 
+#include 
 #include 
 #include 
 
@@ -29,18 +31,22 @@
 
 /* Basic configuration for ACPI */
 #ifdef CONFIG_ACPI
+pgprot_t __acpi_get_mem_attribute(phys_addr_t addr);
+
 /* ACPI table mapping after acpi_permanent_mmap is set */
 static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
acpi_size size)
 {
+   /* For normal memory we already have a cacheable mapping. */
+   if (memblock_is_map_memory(phys))
+   return (void __iomem *)__phys_to_virt(phys);
+
/*
-* EFI's reserve_regions() call adds memory with the WB attribute
-* to memblock via early_init_dt_add_memory_arch().
+* We should still honor the memory's attribute here because
+* crash dump kernel possibly excludes some ACPI (reclaim)
+* regions from memblock list.
 */
-   if (!memblock_is_memory(phys))
-   return ioremap(phys, size);
-
-   return ioremap_cache(phys, size);
+   return __ioremap(phys, size, __acpi_get_mem_attribute(phys));
 }
 #define acpi_os_ioremap acpi_os_ioremap
 
@@ -129,7 +135,10 @@ static inline const char *acpi_get_enable_method(int cpu)
  * for compatibility.
  */
 #define acpi_disable_cmcff 1
-pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr);
+static inline pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr)
+{
+   return __acpi_get_mem_attribute(addr);
+}
 #endif /* CONFIG_ACPI_APEI */
 
 #ifdef CONFIG_ACPI_NUMA
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 7b09487ff8fb..ed46dc188b22 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -18,6 +18,7 @@
 #include 
 #inc

[PATCH v3 0/3] arm64: kexec,kdump: fix boot failures on acpi-only system

2018-07-08 Thread AKASHI Takahiro
This patch series is a set of bug fixes to address kexec/kdump
failures which are sometimes observed on ACPI-only system and reported
in LAK-ML before.

In short, the phenomena are:
1. kexec'ed kernel can fail to boot because some ACPI table is corrupted
   by a new kernel (or other data) being loaded into System RAM. Currently
   kexec may possibly allocate space ignoring such "reserved" regions.
   We will see no messages after "Bye!"

2. crash dump (kdump) kernel can fail to boot and get into panic due to
   an alignment fault when accessing ACPI tables. This can happen because
   those tables are not always properly aligned while they are mapped
   non-cacheable (ioremap'ed) as they are not recognized as part of System
   RAM under the current implementation.

After discussing several possibilities to address those issues,
the agreed approach, in my understanding, is
* to add resource entries for every "reserved", i.e. memblock_reserve(),
  regions to /proc/iomem.
  (NOMAP regions, also marked as "reserved," remains at top-level for
  backward compatibility. User-space can tell the difference between
  reserved-system-ram and reserved-address-space.)
* For case (1), user space (kexec-tools) should rule out such regions
  in searching for free space for loaded data.
* For case (2), the kernel should access ACPI tables by mapping
  them with appropriate memory attributes described in UEFI memory map.
  (This means that it doesn't require any changes in /proc/iomem, and
  hence user space.)

Please find past discussions about /proc/iomem in [1].
--- more words from James ---
Our attempts to fix this just in the kernel reached a dead end, because Kdump
needs to include reserved-system-ram, whereas kexec has to avoid it. User-space
needs to be able to tell reserved-system-ram and reserved-address-space apart.
Hence we need to expose that information, and pick it up in user-space.

Patched-kernel and unpatch-user-space will work the same way it does today, as
the additional reserved regions are ignored by user-space.

Unpatched-kernel and patched-user-space will also work the same way it does
today as the additional reserved regions are missing.
--->8---

Patch#1 addresses kexec case, for which you are also required to update
user space. See necessary patches in [2]. If you want to review Patch#1,
please also take a look at and review [2].

Patch#2 and #3 addresses kdump case. Ard's patch [4] needs to be applied
preliminarily.


Changes in v3 (2018, July 9, 2018)
* drop the v2's patch#3, preferring [4]

Changes in v2 (2018, June 19, 2018)
* re-organise v1's patch#2 and #3 into v2's #2, #3 and #4
  not to break bisect

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2018-March/565980.html
[2] https://git.linaro.org/people/takahiro.akashi/kexec-tools.git arm64/resv_mem
[3] http://lists.infradead.org/pipermail/linux-arm-kernel/2018-April/573655.html
[4] https://marc.info/?l=linux-efi&m=152930773507524&w=2

AKASHI Takahiro (2):
  efi/arm: map UEFI memory map even w/o runtime services enabled
  arm64: acpi: fix alignment fault in accessing ACPI

James Morse (1):
  arm64: export memblock_reserve()d regions via /proc/iomem

 arch/arm64/include/asm/acpi.h  | 23 --
 arch/arm64/kernel/acpi.c   | 11 +++--
 arch/arm64/kernel/setup.c  | 38 ++
 drivers/firmware/efi/arm-runtime.c | 14 +--
 4 files changed, 64 insertions(+), 22 deletions(-)

-- 
2.17.0



[PATCH v3 1/3] arm64: export memblock_reserve()d regions via /proc/iomem

2018-07-08 Thread AKASHI Takahiro
From: James Morse 

There has been some confusion around what is necessary to prevent kexec
overwriting important memory regions. memblock: reserve, or nomap?
Only memblock nomap regions are reported via /proc/iomem, kexec's
user-space doesn't know about memblock_reserve()d regions.

Until commit f56ab9a5b73ca ("efi/arm: Don't mark ACPI reclaim memory
as MEMBLOCK_NOMAP") the ACPI tables were nomap, now they are reserved
and thus possible for kexec to overwrite with the new kernel or initrd.
But this was always broken, as the UEFI memory map is also reserved
and not marked as nomap.

Exporting both nomap and reserved memblock types is a nuisance as
they live in different memblock structures which we can't walk at
the same time.

Take a second walk over memblock.reserved and add new 'reserved'
subnodes for the memblock_reserved() regions that aren't already
described by the existing code. (e.g. Kernel Code)

We use reserve_region_with_split() to find the gaps in existing named
regions. This handles the gap between 'kernel code' and 'kernel data'
which is memblock_reserve()d, but already partially described by
request_standard_resources(). e.g.:
| 8000-dfff : System RAM
|   8008-80ff : Kernel code
|   8100-8158 : reserved
|   8159-8237efff : Kernel data
|   a000-dfff : Crash kernel
| e00f-f949 : System RAM

reserve_region_with_split needs kzalloc() which isn't available when
request_standard_resources() is called, use an initcall.

Reported-by: Bhupesh Sharma 
Reported-by: Tyler Baicar 
Suggested-by: Akashi Takahiro 
Signed-off-by: James Morse 
Fixes: d28f6df1305a ("arm64/kexec: Add core kexec support")
Reviewed-by: Ard Biesheuvel 
CC: Mark Rutland 
---
 arch/arm64/kernel/setup.c | 38 ++
 1 file changed, 38 insertions(+)

diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 30ad2f085d1f..5b4fac434c84 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -241,6 +241,44 @@ static void __init request_standard_resources(void)
}
 }
 
+static int __init reserve_memblock_reserved_regions(void)
+{
+   phys_addr_t start, end, roundup_end = 0;
+   struct resource *mem, *res;
+   u64 i;
+
+   for_each_reserved_mem_region(i, &start, &end) {
+   if (end <= roundup_end)
+   continue; /* done already */
+
+   start = __pfn_to_phys(PFN_DOWN(start));
+   end = __pfn_to_phys(PFN_UP(end)) - 1;
+   roundup_end = end;
+
+   res = kzalloc(sizeof(*res), GFP_ATOMIC);
+   if (WARN_ON(!res))
+   return -ENOMEM;
+   res->start = start;
+   res->end = end;
+   res->name  = "reserved";
+   res->flags = IORESOURCE_MEM;
+
+   mem = request_resource_conflict(&iomem_resource, res);
+   /*
+* We expected memblock_reserve() regions to conflict with
+* memory created by request_standard_resources().
+*/
+   if (WARN_ON_ONCE(!mem))
+   continue;
+   kfree(res);
+
+   reserve_region_with_split(mem, start, end, "reserved");
+   }
+
+   return 0;
+}
+arch_initcall(reserve_memblock_reserved_regions);
+
 u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
 
 void __init setup_arch(char **cmdline_p)
-- 
2.17.0



[PATCH v2 4/4] arm64: acpi: fix alignment fault in accessing ACPI

2018-06-18 Thread AKASHI Takahiro
This is a fix against the issue that crash dump kernel may hang up
during booting, which can happen on any ACPI-based system with "ACPI
Reclaim Memory."

(kernel messages after panic kicked off kdump)
   (snip...)
Bye!
   (snip...)
ACPI: Core revision 20170728
pud=2e7d0003, *pmd=2e7c0003, *pte=00e839710707
Internal error: Oops: 9621 [#1] SMP
Modules linked in:
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.14.0-rc6 #1
task: 08d05180 task.stack: 08cc
PC is at acpi_ns_lookup+0x25c/0x3c0
LR is at acpi_ds_load1_begin_op+0xa4/0x294
   (snip...)
Process swapper/0 (pid: 0, stack limit = 0x08cc)
Call trace:
   (snip...)
[] acpi_ns_lookup+0x25c/0x3c0
[] acpi_ds_load1_begin_op+0xa4/0x294
[] acpi_ps_build_named_op+0xc4/0x198
[] acpi_ps_create_op+0x14c/0x270
[] acpi_ps_parse_loop+0x188/0x5c8
[] acpi_ps_parse_aml+0xb0/0x2b8
[] acpi_ns_one_complete_parse+0x144/0x184
[] acpi_ns_parse_table+0x48/0x68
[] acpi_ns_load_table+0x4c/0xdc
[] acpi_tb_load_namespace+0xe4/0x264
[] acpi_load_tables+0x48/0xc0
[] acpi_early_init+0x9c/0xd0
[] start_kernel+0x3b4/0x43c
Code: b9008fb9 2a000318 36380054 32190318 (b94002c0)
---[ end trace c46ed37f9651c58e ]---
Kernel panic - not syncing: Fatal exception
Rebooting in 10 seconds..

(diagnosis)
* This fault is a data abort, alignment fault (ESR=0x9621)
  during reading out ACPI table.
* Initial ACPI tables are normally stored in system ram and marked as
  "ACPI Reclaim memory" by the firmware.
* After the commit f56ab9a5b73c ("efi/arm: Don't mark ACPI reclaim
  memory as MEMBLOCK_NOMAP"), those regions are differently handled
  as they are "memblock-reserved", without NOMAP bit.
* So they are now excluded from device tree's "usable-memory-range"
  which kexec-tools determines based on a current view of /proc/iomem.
* When crash dump kernel boots up, it tries to accesses ACPI tables by
  mapping them with ioremap(), not ioremap_cache(), in acpi_os_ioremap()
  since they are no longer part of mapped system ram.
* Given that ACPI accessor/helper functions are compiled in without
  unaligned access support (ACPI_MISALIGNMENT_NOT_SUPPORTED),
  any unaligned access to ACPI tables can cause a fatal panic.

With this patch, acpi_os_ioremap() always honors memory attribute
information provided by the firmware (EFI) and retaining cacheability
allows the kernel safe access to ACPI tables.

Signed-off-by: AKASHI Takahiro 
Suggested-by: James Morse 
Suggested-by: Ard Biesheuvel 
Reported-by and Tested-by: Bhupesh Sharma 
---
 arch/arm64/include/asm/acpi.h | 23 ---
 arch/arm64/kernel/acpi.c  | 11 +++
 2 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 0db62a4cbce2..68bc18cb2b85 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -12,10 +12,12 @@
 #ifndef _ASM_ACPI_H
 #define _ASM_ACPI_H
 
+#include 
 #include 
 #include 
 
 #include 
+#include 
 #include 
 #include 
 
@@ -29,18 +31,22 @@
 
 /* Basic configuration for ACPI */
 #ifdef CONFIG_ACPI
+pgprot_t __acpi_get_mem_attribute(phys_addr_t addr);
+
 /* ACPI table mapping after acpi_permanent_mmap is set */
 static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
acpi_size size)
 {
+   /* For normal memory we already have a cacheable mapping. */
+   if (memblock_is_map_memory(phys))
+   return (void __iomem *)__phys_to_virt(phys);
+
/*
-* EFI's reserve_regions() call adds memory with the WB attribute
-* to memblock via early_init_dt_add_memory_arch().
+* We should still honor the memory's attribute here because
+* crash dump kernel possibly excludes some ACPI (reclaim)
+* regions from memblock list.
 */
-   if (!memblock_is_memory(phys))
-   return ioremap(phys, size);
-
-   return ioremap_cache(phys, size);
+   return __ioremap(phys, size, __acpi_get_mem_attribute(phys));
 }
 #define acpi_os_ioremap acpi_os_ioremap
 
@@ -129,7 +135,10 @@ static inline const char *acpi_get_enable_method(int cpu)
  * for compatibility.
  */
 #define acpi_disable_cmcff 1
-pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr);
+static inline pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr)
+{
+   return __acpi_get_mem_attribute(addr);
+}
 #endif /* CONFIG_ACPI_APEI */
 
 #ifdef CONFIG_ACPI_NUMA
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 7b09487ff8fb..ed46dc188b22 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -18,6 +18,7 @@
 #inc

Re: [PATCH v9 07/11] arm64: kexec_file: add crash dump support

2018-05-21 Thread AKASHI Takahiro
Hi Rob,

On Fri, May 18, 2018 at 10:35:52AM -0500, Rob Herring wrote:
> On Tue, May 15, 2018 at 06:12:59PM +0100, James Morse wrote:
> > Hi guys,
> > 
> > (CC: +RobH, devicetree list)
> 
> Thanks.
> 
> > On 25/04/18 07:26, AKASHI Takahiro wrote:
> > > Enabling crash dump (kdump) includes
> > > * prepare contents of ELF header of a core dump file, /proc/vmcore,
> > >   using crash_prepare_elf64_headers(), and
> > > * add two device tree properties, "linux,usable-memory-range" and
> > >   "linux,elfcorehdr", which represent repsectively a memory range
> > >   to be used by crash dump kernel and the header's location
> 
> BTW, I intend to move existing parsing these out of the arch code. 
> Please don't add more DT handling to arch/ unless it is *really* arch 
> specific. I'd assume that the next arch to add kexec support will use 
> these bindings instead of the powerpc way.

So do you expect all the fdt-related stuff in my current implementation
for arm64 to be put into libfdt, or at least drivers/of, from the beginning?

I'm not sure how arch-specific the properties here are. For instance,
it is only arm64 that uses "linux,usable-memory-range" right now but
if some other arch follows, it is no more arch-specific.
# I remember that you didn't like this property :)

> > kexec_file_load() on arm64 needs to be able to create a prop encoded array 
> > to
> > the FDT, but there doesn't appear to be a libfdt helper to do this.
> > 
> > Akashi's code below adds fdt_setprop_range() to the arch code, and 
> > duplicates
> > bits of libfdt_internal.h to do the work.
> > 
> > How should this be done? I'm assuming this is something we need a new API in
> > libfdt.h for. How do these come about, and is there an interim step we can 
> > use
> > until then?
> 
> Submit patches to upstream dtc and then we can pull it in. Ahead of that 
> you can add it to drivers/of/fdt.c (or maybe fdt_address.c because 
> that's really what this is dealing with).

OK, I'm going to try to follow your suggestion.

> libfdt has only recently gained the beginnings of address handling.
> 
> > 
> > Thanks!
> > 
> > James
> > 
> > > diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> > > b/arch/arm64/kernel/machine_kexec_file.c
> > > index 37c0a9dc2e47..ec674f4d267c 100644
> > > --- a/arch/arm64/kernel/machine_kexec_file.c
> > > +++ b/arch/arm64/kernel/machine_kexec_file.c
> > > @@ -76,6 +81,78 @@ int arch_kexec_walk_mem(struct kexec_buf *kbuf,
> > >   return ret;
> > >  }
> > >  
> > > +static int __init arch_kexec_file_init(void)
> > > +{
> > > + /* Those values are used later on loading the kernel */
> > > + __dt_root_addr_cells = dt_root_addr_cells;
> > > + __dt_root_size_cells = dt_root_size_cells;
> 
> I intend to make dt_root_*_cells private, so don't add another user 
> outside of drivers/of/.

Once cells_size_fitted() moves to drivers/of, there will be no users.

> > > +
> > > + return 0;
> > > +}
> > > +late_initcall(arch_kexec_file_init);
> > > +
> > > +#define FDT_ALIGN(x, a)  (((x) + (a) - 1) & ~((a) - 1))
> > > +#define FDT_TAGALIGN(x)  (FDT_ALIGN((x), FDT_TAGSIZE))
> > > +
> > > +static int fdt_prop_len(const char *prop_name, int len)
> > > +{
> > > + return (strlen(prop_name) + 1) +
> > > + sizeof(struct fdt_property) +
> > > + FDT_TAGALIGN(len);
> > > +}
> > > +
> > > +static bool cells_size_fitted(unsigned long base, unsigned long size)
> 
> I can't imagine this would happen. However, when this is moved to 
> drivers/of/ or dtc, these need to be u64 types to work on 32-bit.

OK.

> > > + /* if *_cells >= 2, cells can hold 64-bit values anyway */
> > > + if ((__dt_root_addr_cells == 1) && (base >= (1ULL << 32)))
> > > + return false;
> > > +
> > > + if ((__dt_root_size_cells == 1) && (size >= (1ULL << 32)))
> > > + return false;
> > > +
> > > + return true;
> > > +}
> > > +
> > > +static void fill_property(void *buf, u64 val64, int cells)
> > > +{
> > > + u32 val32;
> 
> This should be a __be32 or fdt32 type. So should buf.

OK for val32, but buf is a local pointer address.

> > > +
> > > + if (cells == 1) {
> > > + val32 = cpu_to_fdt32((u32)val64);
> > > + memcpy(buf, &val32,

Re: [PATCH v9 07/11] arm64: kexec_file: add crash dump support

2018-05-21 Thread AKASHI Takahiro
James,

On Fri, May 18, 2018 at 05:00:55PM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 18/05/18 11:39, AKASHI Takahiro wrote:
> > On Tue, May 15, 2018 at 06:11:15PM +0100, James Morse wrote:
> >> On 25/04/18 07:26, AKASHI Takahiro wrote:
> >>> Enabling crash dump (kdump) includes
> >>> * prepare contents of ELF header of a core dump file, /proc/vmcore,
> >>>   using crash_prepare_elf64_headers(), and
> >>> * add two device tree properties, "linux,usable-memory-range" and
> >>>   "linux,elfcorehdr", which represent repsectively a memory range
> 
> >>> diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> >>> b/arch/arm64/kernel/machine_kexec_file.c
> >>> index 37c0a9dc2e47..ec674f4d267c 100644
> >>> --- a/arch/arm64/kernel/machine_kexec_file.c
> >>> +++ b/arch/arm64/kernel/machine_kexec_file.c
> 
> >>> +static void fill_property(void *buf, u64 val64, int cells)
> >>> +{
> >>> + u32 val32;
> >>> +
> >>> + if (cells == 1) {
> >>> + val32 = cpu_to_fdt32((u32)val64);
> >>> + memcpy(buf, &val32, sizeof(val32));
> >>> + } else {
> >>
> >>> + memset(buf, 0, cells * sizeof(u32) - sizeof(u64));
> >>> + buf += cells * sizeof(u32) - sizeof(u64);
> >>
> >> Is this trying to clear the 'top' cells and shuffle the pointer to point 
> >> at the
> >> 'bottom' 2? I'm pretty sure this isn't endian safe.
> >>
> >> Do we really expect a system to have #address-cells > 2?
> > 
> > I don't know, but just for safety.
> 
> Okay, so this is aiming to be a cover-all-cases library function.
> 
> 
> >>> + val64 = cpu_to_fdt64(val64);
> >>> + memcpy(buf, &val64, sizeof(val64));
> >>> + }
> >>> +}
> >>> +
> >>> +static int fdt_setprop_range(void *fdt, int nodeoffset, const char *name,
> >>> + unsigned long addr, unsigned long size)
> >>
> >> (the device-tree spec describes a 'ranges' property, which had me 
> >> confused. This
> >> is encoding a prop-encoded-array)
> > 
> > Should we rename it to, say, fdt_setprop_reg()?
> 
> Sure, but I'd really like this code to come from libfdt. I'm hoping for some
> temporary workaround, lets see what the DT folk say.

OK, I will follow Rob's suggestion.

> >>> + if (!buf)
> >>> + return -ENOMEM;
> >>> +
> >>> + fill_property(prop, addr, __dt_root_addr_cells);
> >>> + prop += __dt_root_addr_cells * sizeof(u32);
> >>> +
> >>> + fill_property(prop, size, __dt_root_size_cells);
> >>> +
> >>> + result = fdt_setprop(fdt, nodeoffset, name, buf, buf_size);
> >>> +
> >>> + vfree(buf);
> >>> +
> >>> + return result;
> >>> +}
> >>
> >> Doesn't this stuff belong in libfdt? I guess there is no 'add array 
> >> element' api
> >> because this the first time we've wanted to create a node with more than
> >> key=fixed-size-value.
> >>
> >> I don't think this belongs in arch C code. Do we have a plan for getting 
> >> libfdt
> >> to support encoding prop-arrays? Can we put it somewhere anyone else 
> >> duplicating
> >> this will find it, until we can (re)move it?
> > 
> > I will temporarily move all fdt-related stuff to a separate file, but
> > 
> >> I have no idea how that happens... it looks like the devicetree list is the
> >> place to ask.
> > 
> > should we always sync with the original dtc/libfdt repository?
> 
> I thought so, libfdt is one of those external libraries that the kernel
> consumes, like acpica. For acpica at least the rule is changes go upstream, 
> then
> get sync'd back.

Same above.

> >>>  static int setup_dtb(struct kimage *image,
> >>>   unsigned long initrd_load_addr, unsigned long initrd_len,
> >>>   char *cmdline, unsigned long cmdline_len,
> >>> @@ -88,10 +165,26 @@ static int setup_dtb(struct kimage *image,
> >>>   int range_len;
> >>>   int ret;
> >>>  
> >>> + /* check ranges against root's #address-cells and #size-cells */
> >>> + if (image->type == KEXEC_TYPE_CRASH &&
> >>> + (!cells_size_fitted(image->

Re: [PATCH v9 06/11] arm64: kexec_file: allow for loading Image-format kernel

2018-05-21 Thread AKASHI Takahiro
James,

I haven't commented on this email.

On Tue, May 15, 2018 at 06:14:37PM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 15/05/18 06:13, AKASHI Takahiro wrote:
> > On Fri, May 11, 2018 at 06:07:06PM +0100, James Morse wrote:
> >> On 07/05/18 08:21, AKASHI Takahiro wrote:
> >>> On Tue, May 01, 2018 at 06:46:11PM +0100, James Morse wrote:
> >>>> On 25/04/18 07:26, AKASHI Takahiro wrote:
> >>>>> This patch provides kexec_file_ops for "Image"-format kernel. In this
> >>>>> implementation, a binary is always loaded with a fixed offset identified
> >>>>> in text_offset field of its header.
> >>
> >>>>> diff --git a/arch/arm64/include/asm/kexec.h 
> >>>>> b/arch/arm64/include/asm/kexec.h
> >>>>> index e4de1223715f..3cba4161818a 100644
> >>>>> --- a/arch/arm64/include/asm/kexec.h
> >>>>> +++ b/arch/arm64/include/asm/kexec.h
> 
> >>>> Could we check branch_code is non-zero, and text-offset points within 
> >>>> image-size?
> >>>
> >>> We could do it, but I don't think this check is very useful.
> >>>
> >>>>
> >>>> We could check that this platform supports the page-size/endian config 
> >>>> that this
> >>>> Image was built with... We get a message from the EFI stub if the 
> >>>> page-size
> >>>> can't be supported, it would be nice to do the same here (as we can).
> >>>
> >>> There is no restriction on page-size or endianness for kexec.
> >>
> >> No, but it won't boot if the hardware doesn't support it. The kernel will 
> >> spin
> >> at a magic address that is, difficult, to debug without JTAG. The bug 
> >> report
> >> will be "it didn't boot".
> > 
> > OK.
> > Added sanity checks for cpu features, endianness as well as page size.
> > 
> >>
> >>> What will be the purpose of this check?
> >>
> >> These values are in the header so that the bootloader can check them, then 
> >> print
> >> a meaningful error. Here, kexec_file_load() is playing the part of the 
> >> bootloader.
> 
> >> I'm assuming kexec_file_load() can only be used to kexec linux... unlike 
> >> regular
> >> kexec. Is this where I'm going wrong?
> 
> Trying to work this out for myself: we can't support any UEFI application as 
> we
> can't give it the boot-services environment, so I'm pretty sure
> kexec_file_load() must be linux-specific.
> 
> Can we state somewhere that we only expect arm64 linux to be booted with
> kexec_file_load()? Its not clear from the kconfig text, which refers to kexec,
> which explicitly states it can boot other OS. But for kexec_file_load() we're
> following the kernel's booting.txt.

While I don't know anything about requirements in booting other OS's nor
if we can boot them even with kexec, I agree that kexec_file_load is a more
limited form of booting mechanism. I will add some statement in Kconfig.

> >>>>> diff --git a/arch/arm64/kernel/kexec_image.c 
> >>>>> b/arch/arm64/kernel/kexec_image.c
> >>>>> new file mode 100644
> >>>>> index ..4dd524ad6611
> >>>>> --- /dev/null
> >>>>> +++ b/arch/arm64/kernel/kexec_image.c
> >>>>> @@ -0,0 +1,79 @@
> >>>>
> >>>>> +static void *image_load(struct kimage *image,
> >>>>> +   char *kernel, unsigned long kernel_len,
> >>>>> +   char *initrd, unsigned long initrd_len,
> >>>>> +   char *cmdline, unsigned long 
> >>>>> cmdline_len)
> >>>>> +{
> >>>>> +   struct kexec_buf kbuf;
> >>>>> +   struct arm64_image_header *h = (struct arm64_image_header 
> >>>>> *)kernel;
> >>>>> +   unsigned long text_offset;
> >>>>> +   int ret;
> >>>>> +
> >>>>> +   /* Load the kernel */
> >>>>> +   kbuf.image = image;
> >>>>> +   kbuf.buf_min = 0;
> >>>>> +   kbuf.buf_max = ULONG_MAX;
> >>>>> +   kbuf.top_down = false;
> >>>>> +
> >>>>> +   kbuf.buffer = kernel;
> >>>>> +   kbuf.bufsz = ker

Re: [PATCH v9 07/11] arm64: kexec_file: add crash dump support

2018-05-18 Thread AKASHI Takahiro
On Tue, May 15, 2018 at 06:11:15PM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 25/04/18 07:26, AKASHI Takahiro wrote:
> > Enabling crash dump (kdump) includes
> > * prepare contents of ELF header of a core dump file, /proc/vmcore,
> >   using crash_prepare_elf64_headers(), and
> > * add two device tree properties, "linux,usable-memory-range" and
> >   "linux,elfcorehdr", which represent repsectively a memory range
> 
> (Nit: respectively)

Will fix.

> 
> >   to be used by crash dump kernel and the header's location
> 
> >  arch/arm64/include/asm/kexec.h |   4 +
> >  arch/arm64/kernel/kexec_image.c|   9 +-
> >  arch/arm64/kernel/machine_kexec_file.c | 202 +
> 
> In this patch, machine_kexec_file.c gains its own private fdt array encoder.

See below.

> 
> > diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> > b/arch/arm64/kernel/machine_kexec_file.c
> > index 37c0a9dc2e47..ec674f4d267c 100644
> > --- a/arch/arm64/kernel/machine_kexec_file.c
> > +++ b/arch/arm64/kernel/machine_kexec_file.c
> > @@ -76,6 +81,78 @@ int arch_kexec_walk_mem(struct kexec_buf *kbuf,
> > return ret;
> >  }
> >  
> > +static int __init arch_kexec_file_init(void)
> > +{
> > +   /* Those values are used later on loading the kernel */
> > +   __dt_root_addr_cells = dt_root_addr_cells;
> > +   __dt_root_size_cells = dt_root_size_cells;
> > +
> > +   return 0;
> > +}
> > +late_initcall(arch_kexec_file_init);
> 
> If we need these is it worth taking them out of __initdata? I note they've 
> been
> 'temporary' for quite a long time.

I think that I had some reason that I didn't do that, but don't remember now.
If there's no problem, I will take your suggestion.

> 
> > +
> > +#define FDT_ALIGN(x, a)(((x) + (a) - 1) & ~((a) - 1))
> > +#define FDT_TAGALIGN(x)(FDT_ALIGN((x), FDT_TAGSIZE))
> > +
> > +static int fdt_prop_len(const char *prop_name, int len)
> > +{
> > +   return (strlen(prop_name) + 1) +
> > +   sizeof(struct fdt_property) +
> > +   FDT_TAGALIGN(len);
> > +}
> 
> This stuff should really be in libfdt.h  Those macros come from
> libfdt_internal.h, so we're probably doing something wrong here.
> 
> 
> > +static bool cells_size_fitted(unsigned long base, unsigned long size)
> > +{
> > +   /* if *_cells >= 2, cells can hold 64-bit values anyway */
> > +   if ((__dt_root_addr_cells == 1) && (base >= (1ULL << 32)))
> > +   return false;
> > +
> > +   if ((__dt_root_size_cells == 1) && (size >= (1ULL << 32)))
> > +   return false;
> 
> Using '> U32_MAX' here may be more readable.

OK

> 
> > +   return true;
> > +}
> > +
> > +static void fill_property(void *buf, u64 val64, int cells)
> > +{
> > +   u32 val32;
> > +
> > +   if (cells == 1) {
> > +   val32 = cpu_to_fdt32((u32)val64);
> > +   memcpy(buf, &val32, sizeof(val32));
> > +   } else {
> 
> > +   memset(buf, 0, cells * sizeof(u32) - sizeof(u64));
> > +   buf += cells * sizeof(u32) - sizeof(u64);
> 
> Is this trying to clear the 'top' cells and shuffle the pointer to point at 
> the
> 'bottom' 2? I'm pretty sure this isn't endian safe.
> 
> Do we really expect a system to have #address-cells > 2?

I don't know, but just for safety.

> 
> > +   val64 = cpu_to_fdt64(val64);
> > +   memcpy(buf, &val64, sizeof(val64));
> > +   }
> > +}
> > +
> > +static int fdt_setprop_range(void *fdt, int nodeoffset, const char *name,
> > +   unsigned long addr, unsigned long size)
> 
> (the device-tree spec describes a 'ranges' property, which had me confused. 
> This
> is encoding a prop-encoded-array)

Should we rename it to, say, fdt_setprop_reg()?


> > +{
> > +   void *buf, *prop;
> > +   size_t buf_size;
> > +   int result;
> > +
> > +   buf_size = (__dt_root_addr_cells + __dt_root_size_cells) * sizeof(u32);
> > +   prop = buf = vmalloc(buf_size);
> 
> virtual memory allocation for something less than PAGE_SIZE?

I've never cared about that. Let me think again.

> 
> > +   if (!buf)
> > +   return -ENOMEM;
> > +
> > +   fill_property(prop, addr, __dt_root_addr_cells);
> > +   prop += __dt_root_addr_cells * sizeof(u32);
> > +
> > +   fill_property(prop, size, __dt_root_size_

Re: [PATCH v9 07/11] arm64: kexec_file: add crash dump support

2018-05-18 Thread AKASHI Takahiro
On Wed, May 16, 2018 at 09:34:41AM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 15/05/18 18:11, James Morse wrote:
> > On 25/04/18 07:26, AKASHI Takahiro wrote:
> >> Enabling crash dump (kdump) includes
> >> * prepare contents of ELF header of a core dump file, /proc/vmcore,
> >>   using crash_prepare_elf64_headers(), and
> >> * add two device tree properties, "linux,usable-memory-range" and
> >>   "linux,elfcorehdr", which represent repsectively a memory range
> >>   to be used by crash dump kernel and the header's location
> 
> >> diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> >> b/arch/arm64/kernel/machine_kexec_file.c
> >> index 37c0a9dc2e47..ec674f4d267c 100644
> >> --- a/arch/arm64/kernel/machine_kexec_file.c
> >> +++ b/arch/arm64/kernel/machine_kexec_file.c
> >> @@ -76,6 +81,78 @@ int arch_kexec_walk_mem(struct kexec_buf *kbuf,
> 
> >> +static void fill_property(void *buf, u64 val64, int cells)
> >> +{
> >> +  u32 val32;
> >> +
> >> +  if (cells == 1) {
> >> +  val32 = cpu_to_fdt32((u32)val64);
> >> +  memcpy(buf, &val32, sizeof(val32));
> >> +  } else {
> > 
> >> +  memset(buf, 0, cells * sizeof(u32) - sizeof(u64));
> >> +  buf += cells * sizeof(u32) - sizeof(u64);
> > 
> > Is this trying to clear the 'top' cells and shuffle the pointer to point at 
> > the
> > 'bottom' 2? I'm pretty sure this isn't endian safe.
> 
> It came to me at 2am: this only works on big-endian, which is exactly what you
> want as that is the DT format.

Oops, I was almost tricked as I haven't tested kexec on BE
for a long time :)

Thanks,
-Takahiro AKASHI

> 
> > Do we really expect a system to have #address-cells > 2?
> 
> 
> Thanks,
> 
> James


Re: [PATCH v9 07/11] arm64: kexec_file: add crash dump support

2018-05-18 Thread AKASHI Takahiro
On Wed, May 16, 2018 at 11:06:02AM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 15/05/18 18:11, James Morse wrote:
> > On 25/04/18 07:26, AKASHI Takahiro wrote:
> >> Enabling crash dump (kdump) includes
> >> * prepare contents of ELF header of a core dump file, /proc/vmcore,
> >>   using crash_prepare_elf64_headers(), and
> >> * add two device tree properties, "linux,usable-memory-range" and
> >>   "linux,elfcorehdr", which represent repsectively a memory range
> >>   to be used by crash dump kernel and the header's location
> 
> >> diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> >> b/arch/arm64/kernel/machine_kexec_file.c
> >> index 37c0a9dc2e47..ec674f4d267c 100644
> >> --- a/arch/arm64/kernel/machine_kexec_file.c
> >> +++ b/arch/arm64/kernel/machine_kexec_file.c
> 
> >> +static struct crash_mem *get_crash_memory_ranges(void)
> >> +{
> >> +  unsigned int nr_ranges;
> >> +  struct crash_mem *cmem;
> >> +
> >> +  nr_ranges = 1; /* for exclusion of crashkernel region */
> >> +  walk_system_ram_res(0, -1, &nr_ranges, get_nr_ranges_callback);
> >> +
> >> +  cmem = vmalloc(sizeof(struct crash_mem) +
> >> +  sizeof(struct crash_mem_range) * nr_ranges);
> >> +  if (!cmem)
> >> +  return NULL;
> >> +
> >> +  cmem->max_nr_ranges = nr_ranges;
> >> +  cmem->nr_ranges = 0;
> >> +  walk_system_ram_res(0, -1, cmem, add_mem_range_callback);
> >> +
> >> +  /* Exclude crashkernel region */
> >> +  if (crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end)) {
> >> +  vfree(cmem);
> >> +  return NULL;
> >> +  }
> >> +
> >> +  return cmem;
> >> +}
> > 
> > Could this function be included in prepare_elf_headers() so that the 
> > alloc() and
> > free() occur together.
> > 
> > 
> >> +static int prepare_elf_headers(void **addr, unsigned long *sz)
> >> +{
> >> +  struct crash_mem *cmem;
> >> +  int ret = 0;
> >> +
> >> +  cmem = get_crash_memory_ranges();
> >> +  if (!cmem)
> >> +  return -ENOMEM;
> >> +
> >> +  ret =  crash_prepare_elf64_headers(cmem, true, addr, sz);
> >> +
> >> +  vfree(cmem);
> > 
> >> +  return ret;
> >> +}
> > 
> > All this is moving memory-range information from core-code's
> > walk_system_ram_res() into core-code's struct crash_mem, and excluding
> > crashk_res, which again is accessible to the core code.
> > 
> > It looks like this is duplicated in arch/x86 and arch/arm64 because arm64
> > doesn't have a second 'crashk_low_res' region, and always wants elf64, 
> > instead
> > of when IS_ENABLED(CONFIG_X86_64).
> 
> Thinking about it some more: don't we want to walk memblock here, not
> walk_system_ram_res()? What we want is a list of not-nomap regions that the
> kernel may have been using, to form part of vmcore.
> walk_system_ram_res() is becoming a murkier list of maybe-nomap, 
> maybe-reserved.
> 
> I think we should walk the same list here as we do in patch 4.

For consistency, yes.
I missed that.

-Takahiro AKASHI

> 
> 
> Thanks,
> 
> James


Re: [PATCH v9 05/11] arm64: kexec_file: load initrd and device-tree

2018-05-18 Thread AKASHI Takahiro
On Fri, May 18, 2018 at 04:11:35PM +0900, AKASHI Takahiro wrote:
> James,
> 
> On Tue, May 15, 2018 at 05:20:00PM +0100, James Morse wrote:
> > Hi Akashi,
> > 
> > On 25/04/18 07:26, AKASHI Takahiro wrote:
> > > load_other_segments() is expected to allocate and place all the necessary
> > > memory segments other than kernel, including initrd and device-tree
> > > blob (and elf core header for crash).
> > > While most of the code was borrowed from kexec-tools' counterpart,
> > > users may not be allowed to specify dtb explicitly, instead, the dtb
> > > presented by a boot loader is reused.
> > 
> > (Nit: "a boot loader" -> "the original boot loader")
> 
> OK
> 
> > > arch_kimage_kernel_post_load_cleanup() is responsible for freeing arm64-
> > > specific data allocated in load_other_segments().
> > 
> > 
> > > diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> > > b/arch/arm64/kernel/machine_kexec_file.c
> > > index f9ebf54ca247..b3b9b1725d8a 100644
> > > --- a/arch/arm64/kernel/machine_kexec_file.c
> > > +++ b/arch/arm64/kernel/machine_kexec_file.c
> > > @@ -13,7 +13,26 @@
> > >  #include 
> > >  #include 
> > >  #include 
> > > +#include 
> > >  #include 
> > > +#include 
> > > +#include 
> > > +#include 
> > > +
> > > +static int __dt_root_addr_cells;
> > > +static int __dt_root_size_cells;
> > 
> > > @@ -55,3 +74,144 @@ int arch_kexec_walk_mem(struct kexec_buf *kbuf,
> > >  
> > >   return ret;
> > >  }
> > > +
> > > +static int setup_dtb(struct kimage *image,
> > > + unsigned long initrd_load_addr, unsigned long initrd_len,
> > > + char *cmdline, unsigned long cmdline_len,
> > > + char **dtb_buf, size_t *dtb_buf_len)
> > > +{
> > > + char *buf = NULL;
> > > + size_t buf_size;
> > > + int nodeoffset;
> > > + u64 value;
> > > + int range_len;
> > > + int ret;
> > > +
> > > + /* duplicate dt blob */
> > > + buf_size = fdt_totalsize(initial_boot_params);
> > > + range_len = (__dt_root_addr_cells + __dt_root_size_cells) * sizeof(u32);
> > 
> > These two cells values are 0 here. Did you want
> > arch_kexec_file_init() in patch 7 in this patch?
> > 
> > Ah, range_len isn't used, so, did you want the cells values and this 
> > range_len
> > thing in in patch 7!?
> 
> Umm, this problem has long existed since my v1 :)
> I might better re-think about patch order.
> 
> > 
> > > +
> > > + if (initrd_load_addr)
> > > + buf_size += fdt_prop_len("linux,initrd-start", sizeof(u64))
> > > + + fdt_prop_len("linux,initrd-end", sizeof(u64));
> > > +
> > > + if (cmdline)
> > > + buf_size += fdt_prop_len("bootargs", cmdline_len + 1);
> > 
> > I can't find where fdt_prop_len()  oh, patch 7. fdt_prop_len() doesn't 
> > look
> > like the sort of thing that should be created here, but I agree there isn't 
> > an
> > existing API to do this.
> 
> Will take care of it.
> 
> 
> > (This must be why powerpc guesses that the fdt won't be more than double in 
> > size).
> > 
> > 
> > > + buf = vmalloc(buf_size);
> > > + if (!buf) {
> > > + ret = -ENOMEM;
> > > + goto out_err;
> > > + }
> > > +
> > > + ret = fdt_open_into(initial_boot_params, buf, buf_size);
> > > + if (ret)
> > > + goto out_err;
> > > +
> > > + nodeoffset = fdt_path_offset(buf, "/chosen");
> > > + if (nodeoffset < 0)
> > > + goto out_err;
> > > +
> > > + /* add bootargs */
> > > + if (cmdline) {
> > > + ret = fdt_setprop(buf, nodeoffset, "bootargs",
> > > + cmdline, cmdline_len + 1);
> > 
> > fdt_setprop_string()?
> 
> OK

cmdline_len is passed by system call, kexec_file_load(), and this means
that we can't believe that cmdline is always terminated with '\0'.
> 
> > 
> > > + if (ret)
> > > + goto out_err;
> > > + }
> > > +
> > > + /* add initrd-* */
> > > + if (initrd_load_addr) {
> > > + value = cpu_to_fdt64(initrd_load_addr);
> > > + ret = fdt_set

Re: [PATCH v9 05/11] arm64: kexec_file: load initrd and device-tree

2018-05-18 Thread AKASHI Takahiro
James,

On Tue, May 15, 2018 at 05:20:00PM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 25/04/18 07:26, AKASHI Takahiro wrote:
> > load_other_segments() is expected to allocate and place all the necessary
> > memory segments other than kernel, including initrd and device-tree
> > blob (and elf core header for crash).
> > While most of the code was borrowed from kexec-tools' counterpart,
> > users may not be allowed to specify dtb explicitly, instead, the dtb
> > presented by a boot loader is reused.
> 
> (Nit: "a boot loader" -> "the original boot loader")

OK

> > arch_kimage_kernel_post_load_cleanup() is responsible for freeing arm64-
> > specific data allocated in load_other_segments().
> 
> 
> > diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> > b/arch/arm64/kernel/machine_kexec_file.c
> > index f9ebf54ca247..b3b9b1725d8a 100644
> > --- a/arch/arm64/kernel/machine_kexec_file.c
> > +++ b/arch/arm64/kernel/machine_kexec_file.c
> > @@ -13,7 +13,26 @@
> >  #include 
> >  #include 
> >  #include 
> > +#include 
> >  #include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +static int __dt_root_addr_cells;
> > +static int __dt_root_size_cells;
> 
> > @@ -55,3 +74,144 @@ int arch_kexec_walk_mem(struct kexec_buf *kbuf,
> >  
> > return ret;
> >  }
> > +
> > +static int setup_dtb(struct kimage *image,
> > +   unsigned long initrd_load_addr, unsigned long initrd_len,
> > +   char *cmdline, unsigned long cmdline_len,
> > +   char **dtb_buf, size_t *dtb_buf_len)
> > +{
> > +   char *buf = NULL;
> > +   size_t buf_size;
> > +   int nodeoffset;
> > +   u64 value;
> > +   int range_len;
> > +   int ret;
> > +
> > +   /* duplicate dt blob */
> > +   buf_size = fdt_totalsize(initial_boot_params);
> > +   range_len = (__dt_root_addr_cells + __dt_root_size_cells) * sizeof(u32);
> 
> These two cells values are 0 here. Did you want
> arch_kexec_file_init() in patch 7 in this patch?
> 
> Ah, range_len isn't used, so, did you want the cells values and this range_len
> thing in in patch 7!?

Umm, this problem has long existed since my v1 :)
I might better re-think about patch order.

> 
> > +
> > +   if (initrd_load_addr)
> > +   buf_size += fdt_prop_len("linux,initrd-start", sizeof(u64))
> > +   + fdt_prop_len("linux,initrd-end", sizeof(u64));
> > +
> > +   if (cmdline)
> > +   buf_size += fdt_prop_len("bootargs", cmdline_len + 1);
> 
> I can't find where fdt_prop_len()  oh, patch 7. fdt_prop_len() doesn't 
> look
> like the sort of thing that should be created here, but I agree there isn't an
> existing API to do this.

Will take care of it.


> (This must be why powerpc guesses that the fdt won't be more than double in 
> size).
> 
> 
> > +   buf = vmalloc(buf_size);
> > +   if (!buf) {
> > +   ret = -ENOMEM;
> > +   goto out_err;
> > +   }
> > +
> > +   ret = fdt_open_into(initial_boot_params, buf, buf_size);
> > +   if (ret)
> > +   goto out_err;
> > +
> > +   nodeoffset = fdt_path_offset(buf, "/chosen");
> > +   if (nodeoffset < 0)
> > +   goto out_err;
> > +
> > +   /* add bootargs */
> > +   if (cmdline) {
> > +   ret = fdt_setprop(buf, nodeoffset, "bootargs",
> > +   cmdline, cmdline_len + 1);
> 
> fdt_setprop_string()?

OK

> 
> > +   if (ret)
> > +   goto out_err;
> > +   }
> > +
> > +   /* add initrd-* */
> > +   if (initrd_load_addr) {
> > +   value = cpu_to_fdt64(initrd_load_addr);
> > +   ret = fdt_setprop(buf, nodeoffset, "linux,initrd-start",
> > +   &value, sizeof(value));
> 
> sizeof(value) was assumed to be the same as sizeof(u64) earlier.
> fdt_setprop_u64()?

OK

> 
> > +   if (ret)
> > +   goto out_err;
> > +
> > +   value = cpu_to_fdt64(initrd_load_addr + initrd_len);
> > +   ret = fdt_setprop(buf, nodeoffset, "linux,initrd-end",
> > +   &value, sizeof(value));
> > +   if (ret)
> > +   goto out_err;
> > +   }
> > +
> > +   /* trim a buffer */
> > +   fdt_pack(buf);
> > +   *dtb_buf = buf;
> > +   *dtb_buf_len = fdt_to

Re: [PATCH v9 03/11] arm64: kexec_file: invoke the kernel without purgatory

2018-05-17 Thread AKASHI Takahiro
James,

On Tue, May 15, 2018 at 05:15:52PM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 15/05/18 05:45, AKASHI Takahiro wrote:
> > On Fri, May 11, 2018 at 06:03:49PM +0100, James Morse wrote:
> >> On 07/05/18 06:22, AKASHI Takahiro wrote:
> >>> On Tue, May 01, 2018 at 06:46:06PM +0100, James Morse wrote:
> >>>> On 25/04/18 07:26, AKASHI Takahiro wrote:
> >>>>> diff --git a/arch/arm64/kernel/machine_kexec.c 
> >>>>> b/arch/arm64/kernel/machine_kexec.c
> >>>>> index f76ea92dff91..f7dbba00be10 100644
> >>>>> --- a/arch/arm64/kernel/machine_kexec.c
> >>>>> +++ b/arch/arm64/kernel/machine_kexec.c
> >>>>> @@ -205,10 +205,17 @@ void machine_kexec(struct kimage *kimage)
> >>
> >>>>> cpu_soft_restart(kimage != kexec_crash_image,
> >>>>> -   reboot_code_buffer_phys, kimage->head, kimage->start, 
> >>>>> 0);
> >>>>> +   reboot_code_buffer_phys, kimage->head, kimage->start,
> >>>>> +#ifdef CONFIG_KEXEC_FILE
> >>>>> +   kimage->purgatory_info.purgatory_buf ?
> >>>>> +   0 : 
> >>>>> kimage->arch.dtb_mem);
> >>>>> +#else
> >>>>> +   0);
> >>>>> +#endif
> >>
> >>
> >>>> purgatory_buf seems to only be set in kexec_purgatory_setup_kbuf(), 
> >>>> called from
> >>>> kexec_load_purgatory(), which we don't use. How does this get a value?
> >>>>
> >>>> Would it be better to always use kimage->arch.dtb_mem, and ensure that 
> >>>> is 0 for
> >>>> regular kexec (as we can't know where the dtb is)? (image_arg may then 
> >>>> be a
> >>>> better name).
> >>>
> >>> The problem is arch.dtb_mem is currently defined only if 
> >>> CONFIG_KEXEC_FILE.
> >>
> >> I thought it was ARCH_HAS_KIMAGE_ARCH, which we can define all the time if
> >> that's what we want.
> >>
> >>
> >>> So I would like to
> >>> - merge this patch with patch#8
> >>> - change the condition
> >>> #ifdef CONFIG_KEXEC_FILE
> >>>   kimage->file_mode ? 
> >>> kimage->arch.dtb_mem : 0);

We don't need "kimage->file_mode ?" since arch.dtb_mem is 0 if !file_mode.

> >>> #else
> >>>   0);
> >>> #endif
> >>
> >> If we can avoid even this #ifdef by always having kimage->arch, I'd prefer 
> >> that.
> >> If we do that 'dtb_mem' would need some thing that indicates its for 
> >> kexec_file,
> >> as kexec has a DTB too, we just don't know where it is...
> > 
> > OK, but I want to have a minimum of kexec.arch always exist.
> 
> I'm curious, why? Its 32bytes that is allocated a maximum of twice.

I believe that I'm a stingy minimalist :)


> (my questions on what needs to go in there were because it looked like a third
> user was missing...)
> 
> 
> > How about this?
> >
> > | struct kimage_arch {
> > |   phys_addr_t dtb_mem;
> > | #ifdef CONFIG_KEXEC_FILE
> 
> #ifdef in structs just breeds more #ifdefs, as the code that accesses those
> members has to be behind the same set of conditions.
> 
> Given this, I prefer the #ifdefs around cpu_soft_restart() as it doesn't force
> us to add more #ifdefs later.

OK

> For either option without purgatory_info:
> Reviewed-by: James Morse 

Thanks,
-Takahiro AKASHI

> 
> Thanks,
> 
> James


Re: [PATCH v9 04/11] arm64: kexec_file: allocate memory walking through memblock list

2018-05-17 Thread AKASHI Takahiro
Baoquan,

On Fri, May 18, 2018 at 09:37:35AM +0800, Baoquan He wrote:
> On 05/17/18 at 07:04pm, James Morse wrote:
> > Hi Baoquan,
> > 
> > On 17/05/18 03:15, Baoquan He wrote:
> > > On 05/17/18 at 10:10am, Baoquan He wrote:
> > >> On 05/07/18 at 02:59pm, AKASHI Takahiro wrote:
> > >>> On Tue, May 01, 2018 at 06:46:09PM +0100, James Morse wrote:
> > >>>> On 25/04/18 07:26, AKASHI Takahiro wrote:
> > >>>>> We need to prevent firmware-reserved memory regions, particularly EFI
> > >>>>> memory map as well as ACPI tables, from being corrupted by loading
> > >>>>> kernel/initrd (or other kexec buffers). We also want to support memory
> > >>>>> allocation in top-down manner in addition to default bottom-up.
> > >>>>> So let's have arm64 specific arch_kexec_walk_mem() which will search
> > >>>>> for available memory ranges in usable memblock list,
> > >>>>> i.e. !NOMAP & !reserved, 
> > >>>>
> > >>>>> instead of system resource tree.
> > >>>>
> > >>>> Didn't we try to fix the system-resource-tree in order to fix 
> > >>>> regular-kexec to
> > >>>> be safe in the EFI-memory-map/ACPI-tables case?
> > >>>>
> > >>>> It would be good to avoid having two ways of doing this, and I would 
> > >>>> like to
> > >>>> avoid having extra arch code...
> > >>>
> > >>> I know what you mean.
> > >>> /proc/iomem or system resource is, in my opinion, not the best place to
> > >>> describe memory usage of kernel but rather to describe *physical* 
> > >>> hardware
> > >>> layout. As we are still discussing about "reserved" memory, I don't want
> > >>> to depend on it.
> > >>> Along with memblock list, we will have more accurate control over memory
> > >>> usage.
> > >>
> > >> In kexec-tools, we see any usable memory as candidate which can be used
> > > 
> > > Here I said 'any', it's not accurate. Those memory which need be passed
> > > to 2nd kernel for use need be excluded, just as we have done in
> > > kexec-tools.
> > > 
> > >> to load kexec kernel image/initrd etc. However kexec loading is a
> > >> preparation work, it just books those position for later kexec kernel
> > >> jumping after "kexec -e", that is why we need kexec_buf to remember
> > >> them and do the real content copy of kernel/initrd.
> > 
> > The problem we have on arm64 is /proc/iomem is being used for two things.
> > 1) Kexec's this is memory I can book for the new kernel.
> > 2) Kdump's this is memory I must describe for vmcore.
> > 
> > We get the memory map from UEFI via the EFI stub, and leave it in
> > memblock_reserved() memory. A new kexec kernel needs this to boot: it 
> > mustn't
> > overwrite it. The same goes for the ACPI tables, they could be reclaimed and
> > used as memory, but the new kexec kernel needs them to boot, they are
> > memblock_reserved() too.
> 
> Thanks for these details. Seems arm64 is different. In x86 64 memblock

Thanks to James from me, too.

> is used as bootmem allocator and will be released when buddy takes over.
> Mainly, using memblock may bring concern that kexec kernel
> will jump to a unfixed position. This creates an unexpected effect as
> KASLR is doing, namely kernel could be put at a random position. As we

I don't think that this would be a problem on arm64.

> know, kexec was invented for fast kernel dev testing by bypassing
> firmware reset, and has been taken to reboot those huge server with
> thousands of devices and large memory for business currently. This extra
> unpected KASLR effect may cause annoyance even though people have
> disabled KASLR explicitly for a specific testing purpose.
> 
> Besides, discarding the /proc/iomem scanning but taking memblock instead
> in kernel space works for kexec loading for the time being, the flaw of
> /proc/iomem still exists and cause problem for user space kexec-tools,
> as pointed out. Do we have a plan for that?

This was the difference between my and James' standpoint (at leas initially).
James didn't want to require userspace changes to fix the issue, but
the reality is that, without modifying it, we can't support kexec and kdump
perfectly as James explained in his email.

> > 
> &g

Re: [PATCH v9 06/11] arm64: kexec_file: allow for loading Image-format kernel

2018-05-14 Thread AKASHI Takahiro
James,

On Fri, May 11, 2018 at 06:07:06PM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 07/05/18 08:21, AKASHI Takahiro wrote:
> > On Tue, May 01, 2018 at 06:46:11PM +0100, James Morse wrote:
> >> On 25/04/18 07:26, AKASHI Takahiro wrote:
> >>> This patch provides kexec_file_ops for "Image"-format kernel. In this
> >>> implementation, a binary is always loaded with a fixed offset identified
> >>> in text_offset field of its header.
> 
> >>> diff --git a/arch/arm64/include/asm/kexec.h 
> >>> b/arch/arm64/include/asm/kexec.h
> >>> index e4de1223715f..3cba4161818a 100644
> >>> --- a/arch/arm64/include/asm/kexec.h
> >>> +++ b/arch/arm64/include/asm/kexec.h
> >>> @@ -102,6 +102,56 @@ struct kimage_arch {
> >>>   void *dtb_buf;
> >>>  };
> >>>  
> >>> +/**
> >>> + * struct arm64_image_header - arm64 kernel image header
> >>> + *
> >>> + * @pe_sig: Optional PE format 'MZ' signature

To be precise, this is NOT a PE signature but MS-DOS header's magic.
(There is another "PE" signature in PE COFF file header pointed to by
'pe_header'.)
I will correct its name.

> >>> + * @branch_code: Instruction to branch to stext
> >>> + * @text_offset: Image load offset, little endian
> >>> + * @image_size: Effective image size, little endian
> >>> + * @flags:
> >>> + *   Bit 0: Kernel endianness. 0=little endian, 1=big endian
> >>
> >> Page size? What about 'phys_base'?, (whatever that is...)
> >> Probably best to refer to Documentation/arm64/booting.txt here, its the
> >> authoritative source of what these fields mean.
> > 
> > While we don't care other bit fields for now, I will add the reference
> > to the Documentation file.
> 
> Thanks, I don't want to create a second, incomplete set of documentation!

I will leave a minimum of description of parameters here.

> 
> 
> >>> + u64 reserved[3];
> >>> + u8 magic[4];
> >>> + u32 pe_header;
> >>> +};
> >>
> >> I'm surprised we don't have a definition for this already, I guess its 
> >> always
> >> done in asm. We have kernel/image.h that holds some of this stuff, if we 
> >> are
> >> going to validate the flags, is it worth adding the code there, (and 
> >> moving it
> >> to include/asm)?
> > 
> > A comment at the beginning of this file says,
> > #ifndef LINKER_SCRIPT
> > #error This file should only be included in vmlinux.lds.S
> > #endif
> > Let me think about.
> 
> Ah, I missed that.
> 
> Having two definitions of something makes me nervous that they can become
> different... looks like that header belongs to the linker, and shouldn't be 
> used
> here then.

OK.

> 
> >> I guess you skip the MZ prefix as its not present for !EFI?

Correct, but MZ checking in probe function is just an informative message.

> > 
> > CONFIG_KEXEC_IMAGE_VERIFY_SIG depends on the fact that the file
> > format is PE (that is, EFI is enabled).
> 
> So if the signature checking is enabled, its already been checked.

The signature, either MZ or PE, in a file will be actually checked
in verify_pefile_signature().

> 
> >> Could we check branch_code is non-zero, and text-offset points within 
> >> image-size?
> > 
> > We could do it, but I don't think this check is very useful.
> > 
> >>
> >> We could check that this platform supports the page-size/endian config 
> >> that this
> >> Image was built with... We get a message from the EFI stub if the page-size
> >> can't be supported, it would be nice to do the same here (as we can).
> > 
> > There is no restriction on page-size or endianness for kexec.
> 
> No, but it won't boot if the hardware doesn't support it. The kernel will spin
> at a magic address that is, difficult, to debug without JTAG. The bug report
> will be "it didn't boot".

OK.
Added sanity checks for cpu features, endianness as well as page size.

> 
> > What will be the purpose of this check?
> 
> These values are in the header so that the bootloader can check them, then 
> print
> a meaningful error. Here, kexec_file_load() is playing the part of the 
> bootloader.
> 
> I'm assuming kexec_file_load() can only be used to kexec linux... unlike 
> regular
> kexec. Is this where I'm going wrong?
> 
> 
> >>> diff --git a/arch/arm64/kernel/

Re: [PATCH v9 03/11] arm64: kexec_file: invoke the kernel without purgatory

2018-05-14 Thread AKASHI Takahiro
James,

On Fri, May 11, 2018 at 06:03:49PM +0100, James Morse wrote:
> Hi Akashi,
> 
> On 07/05/18 06:22, AKASHI Takahiro wrote:
> > On Tue, May 01, 2018 at 06:46:06PM +0100, James Morse wrote:
> >> On 25/04/18 07:26, AKASHI Takahiro wrote:
> >>> diff --git a/arch/arm64/kernel/machine_kexec.c 
> >>> b/arch/arm64/kernel/machine_kexec.c
> >>> index f76ea92dff91..f7dbba00be10 100644
> >>> --- a/arch/arm64/kernel/machine_kexec.c
> >>> +++ b/arch/arm64/kernel/machine_kexec.c
> >>> @@ -205,10 +205,17 @@ void machine_kexec(struct kimage *kimage)
> 
> >>>   cpu_soft_restart(kimage != kexec_crash_image,
> >>> - reboot_code_buffer_phys, kimage->head, kimage->start, 0);
> >>> + reboot_code_buffer_phys, kimage->head, kimage->start,
> >>> +#ifdef CONFIG_KEXEC_FILE
> >>> + kimage->purgatory_info.purgatory_buf ?
> >>> + 0 : kimage->arch.dtb_mem);
> >>> +#else
> >>> + 0);
> >>> +#endif
> 
> 
> >> purgatory_buf seems to only be set in kexec_purgatory_setup_kbuf(), called 
> >> from
> >> kexec_load_purgatory(), which we don't use. How does this get a value?
> >>
> >> Would it be better to always use kimage->arch.dtb_mem, and ensure that is 
> >> 0 for
> >> regular kexec (as we can't know where the dtb is)? (image_arg may then be a
> >> better name).
> > 
> > The problem is arch.dtb_mem is currently defined only if CONFIG_KEXEC_FILE.
> 
> I thought it was ARCH_HAS_KIMAGE_ARCH, which we can define all the time if
> that's what we want.
> 
> 
> > So I would like to
> > - merge this patch with patch#8
> > - change the condition
> > #ifdef CONFIG_KEXEC_FILE
> > kimage->file_mode ? 
> > kimage->arch.dtb_mem : 0);
> > #else
> > 0);
> > #endif
> 
> If we can avoid even this #ifdef by always having kimage->arch, I'd prefer 
> that.
> If we do that 'dtb_mem' would need some thing that indicates its for 
> kexec_file,
> as kexec has a DTB too, we just don't know where it is...

OK, but I want to have a minimum of kexec.arch always exist.
How about this?

| #define ARCH_HAS_KIMAGE_ARCH
|
| struct kimage_arch {
|   phys_addr_t dtb_mem;
| #ifdef CONFIG_KEXEC_FILE
|   void *dtb_buf;
|   /* Core ELF header buffer */
|   void *elf_headers;
|   unsigned long elf_headers_sz;
|   unsigned long elf_load_addr;
| #endif

| void machine_kexec(struct kimage *kimage)
| {
|   ...
|   cpu_soft_restart(kimage != kexec_crash_image,
|   reboot_code_buffer_phys, kimage->head, kimage->start,
|   kimage->arch.dtb_mem);

Thanks
-Takahiro AKASHI

> 
> 
> Thanks,
> 
> James


Re: [PATCH v9 04/11] arm64: kexec_file: allocate memory walking through memblock list

2018-05-14 Thread AKASHI Takahiro
James,

On Mon, May 07, 2018 at 02:59:07PM +0900, AKASHI Takahiro wrote:
> James,
> 
> On Tue, May 01, 2018 at 06:46:09PM +0100, James Morse wrote:
> > Hi Akashi,
> > 
> > On 25/04/18 07:26, AKASHI Takahiro wrote:
> > > We need to prevent firmware-reserved memory regions, particularly EFI
> > > memory map as well as ACPI tables, from being corrupted by loading
> > > kernel/initrd (or other kexec buffers). We also want to support memory
> > > allocation in top-down manner in addition to default bottom-up.
> > > So let's have arm64 specific arch_kexec_walk_mem() which will search
> > > for available memory ranges in usable memblock list,
> > > i.e. !NOMAP & !reserved, 
> > 
> > > instead of system resource tree.
> > 
> > Didn't we try to fix the system-resource-tree in order to fix regular-kexec 
> > to
> > be safe in the EFI-memory-map/ACPI-tables case?
> > 
> > It would be good to avoid having two ways of doing this, and I would like to
> > avoid having extra arch code...
> 
> I know what you mean.
> /proc/iomem or system resource is, in my opinion, not the best place to
> describe memory usage of kernel but rather to describe *physical* hardware
> layout. As we are still discussing about "reserved" memory, I don't want
> to depend on it.
> Along with memblock list, we will have more accurate control over memory
> usage.

If you don't have further objection, I will take memblock approach
(with factoring out powerpc's arch_kexec_walk_mem()).

Thanks,
-Takahiro AKASHI


> > 
> > > diff --git a/arch/arm64/kernel/machine_kexec_file.c 
> > > b/arch/arm64/kernel/machine_kexec_file.c
> > > new file mode 100644
> > > index ..f9ebf54ca247
> > > --- /dev/null
> > > +++ b/arch/arm64/kernel/machine_kexec_file.c
> > > @@ -0,0 +1,57 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * kexec_file for arm64
> > > + *
> > > + * Copyright (C) 2018 Linaro Limited
> > > + * Author: AKASHI Takahiro 
> > > + *
> > 
> > > + * Most code is derived from arm64 port of kexec-tools
> > 
> > How does kexec-tools walk memblock?
> 
> Will remove this comment from this patch.
> Obviously, this comment is for the rest of the code which will be
> added to succeeding patches (patch #5 and #7).
> 
> 
> > 
> > > + */
> > > +
> > > +#define pr_fmt(fmt) "kexec_file: " fmt
> > > +
> > > +#include 
> > > +#include 
> > > +#include 
> > > +#include 
> > > +
> > > +int arch_kexec_walk_mem(struct kexec_buf *kbuf,
> > > + int (*func)(struct resource *, void *))
> > > +{
> > > + phys_addr_t start, end;
> > > + struct resource res;
> > > + u64 i;
> > > + int ret = 0;
> > > +
> > > + if (kbuf->image->type == KEXEC_TYPE_CRASH)
> > > + return func(&crashk_res, kbuf);
> > > +
> > > + if (kbuf->top_down)
> > > + for_each_mem_range_rev(i, &memblock.memory, &memblock.reserved,
> > > + NUMA_NO_NODE, MEMBLOCK_NONE,
> > > + &start, &end, NULL) {
> > 
> > for_each_free_mem_range_reverse() is a more readable version of this helper.
> 
> OK. I used to use my own limited list of reserved memory instead of
> memblock.reserved here to exclude verbose ranges.
> 
> 
> > > + if (!memblock_is_map_memory(start))
> > > + continue;
> > 
> > Passing MEMBLOCK_NONE means this walk will never find MEMBLOCK_NOMAP memory.
> 
> Sure, I confirmed it.
> 
> > 
> > > + res.start = start;
> > > + res.end = end;
> > > + ret = func(&res, kbuf);
> > > + if (ret)
> > > + break;
> > > + }
> > > + else
> > > + for_each_mem_range(i, &memblock.memory, &memblock.reserved,
> > > + NUMA_NO_NODE, MEMBLOCK_NONE,
> > > + &start, &end, NULL) {
> > 
> > for_each_free_mem_range()?
> 
> OK.
> 
> > > + if (!memblock_is_map_memory(start))
> > > + continue;
> > > +
> > > + res.start = start;
> > > + res.end = end;
> > > + ret = func(&res, kbuf);
> > > + if (ret)
> > > + break;
> > > + }
> > > +
> > > + return ret;
> > > +}
> > > 
> > 
> > With these changes, what we have is almost:
> > arch/powerpc/kernel/machine_kexec_file_64.c::arch_kexec_walk_mem() !
> > (the difference being powerpc doesn't yet support crash-kernels here)
> > 
> > If the argument is walking memblock gives a better answer than the stringy
> > walk_system_ram_res() thing, is there any mileage in moving this code into
> > kexec_file.c, and using it if !IS_ENABLED(CONFIG_ARCH_DISCARD_MEMBLOCK)?
> > 
> > This would save arm64/powerpc having near-identical implementations.
> > 32bit arm keeps memblock if it has kexec, so it may be useful there too if
> > kexec_file_load() support is added.
> 
> Thanks. I've forgot ppc.
> 
> -Takahiro AKASHI
> 
> 
> > 
> > Thanks,
> > 
> > James


  1   2   3   4   5   6   7   8   >