Re: [RFC 1/2] iommu: arm-smmu: Handoff SMR registers and context banks

2019-06-13 Thread Bjorn Andersson
On Thu 13 Jun 04:23 PDT 2019, Robin Murphy wrote:

> On 05/06/2019 22:08, Bjorn Andersson wrote:
> > Boot splash screen or EFI framebuffer requires the display hardware to
> > operate while the Linux iommu driver probes. Therefore, we cannot simply
> > wipe out the SMR register settings programmed by the bootloader.
> > 
> > Detect which SMR registers are in use during probe, and which context
> > banks they are associated with. Reserve these context banks for the
> > first Linux device whose stream-id matches the SMR register.
> > 
> > Any existing page-tables will be discarded.
> 
> That doesn't seem particularly useful :/
> 

In my case all valid CBs have TTBR0 and TTBR1 as 0, so I don't have a
page table. So all I need is a matching stream to keep the display
hardware satisfied.

Is this perhaps the thing that's mentioned as "S2CR bypass" mode?

> Either way, if firmware did set up a translation context, is there any
> guarantee that its pagetables haven't already been stomped on by Linux (e.g.
> via memtest)?
> 

The only way I can think of is if the bootloader would allocate these in
a chunk of memory which it removes from the memory ranges communicated
to the kernel.

In order to support this I believe we would need some logic that
remap the existing page tables and clone them into new ones, and then
update the CBs to match the existing configuration.

But as I said, this is beyond our current needs.

> > Heavily based on downstream implementation by Patrick Daly
> > .
> > 
> > Signed-off-by: Bjorn Andersson 
> > ---
> >   drivers/iommu/arm-smmu-regs.h |  2 +
> >   drivers/iommu/arm-smmu.c  | 80 ---
> >   2 files changed, 77 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h
> > index e9132a926761..8c1fd84032a2 100644
> > --- a/drivers/iommu/arm-smmu-regs.h
> > +++ b/drivers/iommu/arm-smmu-regs.h
> > @@ -105,7 +105,9 @@
> >   #define ARM_SMMU_GR0_SMR(n)   (0x800 + ((n) << 2))
> >   #define SMR_VALID (1 << 31)
> >   #define SMR_MASK_SHIFT16
> > +#define SMR_MASK_MASK  0x7fff
> >   #define SMR_ID_SHIFT  0
> > +#define SMR_ID_MASK0x
> 
> The SMR ID and MASK fields are either both 15 bits or both 16 bits,
> depending on EXIDS. This mix-and-match is plain wrong either way.
> 

Okay, I will read up some more on how these pieces works.

> >   #define ARM_SMMU_GR0_S2CR(n)  (0xc00 + ((n) << 2))
> >   #define S2CR_CBNDX_SHIFT  0
> > diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> > index 5e54cc0a28b3..c8629a656b42 100644
> > --- a/drivers/iommu/arm-smmu.c
> > +++ b/drivers/iommu/arm-smmu.c
> > @@ -135,6 +135,7 @@ struct arm_smmu_s2cr {
> > enum arm_smmu_s2cr_type type;
> > enum arm_smmu_s2cr_privcfg  privcfg;
> > u8  cbndx;
> > +   boolhandoff;
> >   };
> >   #define s2cr_init_val (struct arm_smmu_s2cr){ 
> > \
> > @@ -399,9 +400,22 @@ static int arm_smmu_register_legacy_master(struct 
> > device *dev,
> > return err;
> >   }
> > -static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
> > +static int __arm_smmu_alloc_cb(struct arm_smmu_device *smmu, int start,
> > +  struct device *dev)
> >   {
> > +   struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
> > +   unsigned long *map = smmu->context_map;
> > +   int end = smmu->num_context_banks;
> > +   int cbndx;
> > int idx;
> > +   int i;
> > +
> > +   for_each_cfg_sme(fwspec, i, idx) {
> > +   if (smmu->s2crs[idx].handoff) {
> > +   cbndx = smmu->s2crs[idx].cbndx;
> > +   goto found_handoff;
> > +   }
> > +   }
> > do {
> > idx = find_next_zero_bit(map, end, start);
> > @@ -410,6 +424,17 @@ static int __arm_smmu_alloc_bitmap(unsigned long *map, 
> > int start, int end)
> > } while (test_and_set_bit(idx, map));
> > return idx;
> > +
> > +found_handoff:
> > +   for (i = 0; i < smmu->num_mapping_groups; i++) {
> > +   if (smmu->s2crs[i].cbndx == cbndx) {
> > +   smmu->s2crs[i].cbndx = 0;
> > +   smmu->s2crs[i].handoff = false;
> > +   smmu->s2crs[i].count--;
> > +   }
> > +   }
> > +
> > +   return cbndx;
> >   }
> >   static void __arm_smmu_free_bitmap(unsigned long *map, int idx)
> > @@ -759,7 +784,8 @@ static void arm_smmu_write_context_bank(struct 
> > arm_smmu_device *smmu, int idx)
> >   }
> >   static int arm_smmu_init_domain_context(struct iommu_domain *domain,
> > -   struct arm_smmu_device *smmu)
> > +   struct arm_smmu_device *smmu,
> > +   struct device *dev)
> >   {
> > int irq, start, ret = 0;
> > 

Re: [RFC 1/2] iommu: arm-smmu: Handoff SMR registers and context banks

2019-06-13 Thread Robin Murphy

On 05/06/2019 22:08, Bjorn Andersson wrote:

Boot splash screen or EFI framebuffer requires the display hardware to
operate while the Linux iommu driver probes. Therefore, we cannot simply
wipe out the SMR register settings programmed by the bootloader.

Detect which SMR registers are in use during probe, and which context
banks they are associated with. Reserve these context banks for the
first Linux device whose stream-id matches the SMR register.

Any existing page-tables will be discarded.


That doesn't seem particularly useful :/

Either way, if firmware did set up a translation context, is there any 
guarantee that its pagetables haven't already been stomped on by Linux 
(e.g. via memtest)?



Heavily based on downstream implementation by Patrick Daly
.

Signed-off-by: Bjorn Andersson 
---
  drivers/iommu/arm-smmu-regs.h |  2 +
  drivers/iommu/arm-smmu.c  | 80 ---
  2 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h
index e9132a926761..8c1fd84032a2 100644
--- a/drivers/iommu/arm-smmu-regs.h
+++ b/drivers/iommu/arm-smmu-regs.h
@@ -105,7 +105,9 @@
  #define ARM_SMMU_GR0_SMR(n)   (0x800 + ((n) << 2))
  #define SMR_VALID (1 << 31)
  #define SMR_MASK_SHIFT16
+#define SMR_MASK_MASK  0x7fff
  #define SMR_ID_SHIFT  0
+#define SMR_ID_MASK0x


The SMR ID and MASK fields are either both 15 bits or both 16 bits, 
depending on EXIDS. This mix-and-match is plain wrong either way.



  #define ARM_SMMU_GR0_S2CR(n)  (0xc00 + ((n) << 2))
  #define S2CR_CBNDX_SHIFT  0
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 5e54cc0a28b3..c8629a656b42 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -135,6 +135,7 @@ struct arm_smmu_s2cr {
enum arm_smmu_s2cr_type type;
enum arm_smmu_s2cr_privcfg  privcfg;
u8  cbndx;
+   boolhandoff;
  };
  
  #define s2cr_init_val (struct arm_smmu_s2cr){\

@@ -399,9 +400,22 @@ static int arm_smmu_register_legacy_master(struct device 
*dev,
return err;
  }
  
-static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)

+static int __arm_smmu_alloc_cb(struct arm_smmu_device *smmu, int start,
+  struct device *dev)
  {
+   struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+   unsigned long *map = smmu->context_map;
+   int end = smmu->num_context_banks;
+   int cbndx;
int idx;
+   int i;
+
+   for_each_cfg_sme(fwspec, i, idx) {
+   if (smmu->s2crs[idx].handoff) {
+   cbndx = smmu->s2crs[idx].cbndx;
+   goto found_handoff;
+   }
+   }
  
  	do {

idx = find_next_zero_bit(map, end, start);
@@ -410,6 +424,17 @@ static int __arm_smmu_alloc_bitmap(unsigned long *map, int 
start, int end)
} while (test_and_set_bit(idx, map));
  
  	return idx;

+
+found_handoff:
+   for (i = 0; i < smmu->num_mapping_groups; i++) {
+   if (smmu->s2crs[i].cbndx == cbndx) {
+   smmu->s2crs[i].cbndx = 0;
+   smmu->s2crs[i].handoff = false;
+   smmu->s2crs[i].count--;
+   }
+   }
+
+   return cbndx;
  }
  
  static void __arm_smmu_free_bitmap(unsigned long *map, int idx)

@@ -759,7 +784,8 @@ static void arm_smmu_write_context_bank(struct 
arm_smmu_device *smmu, int idx)
  }
  
  static int arm_smmu_init_domain_context(struct iommu_domain *domain,

-   struct arm_smmu_device *smmu)
+   struct arm_smmu_device *smmu,
+   struct device *dev)
  {
int irq, start, ret = 0;
unsigned long ias, oas;
@@ -873,8 +899,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain 
*domain,
ret = -EINVAL;
goto out_unlock;
}
-   ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
- smmu->num_context_banks);
+   ret = __arm_smmu_alloc_cb(smmu, start, dev);
if (ret < 0)
goto out_unlock;
  
@@ -1264,7 +1289,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)

return ret;
  
  	/* Ensure that the domain is finalised */

-   ret = arm_smmu_init_domain_context(domain, smmu);
+   ret = arm_smmu_init_domain_context(domain, smmu, dev);
if (ret < 0)
goto rpm_put;
  
@@ -1798,6 +1823,49 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)

writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
  }
  
+static void arm_smmu_read_smr_state(struct arm_smmu_device 

Re: [RFC 1/2] iommu: arm-smmu: Handoff SMR registers and context banks

2019-06-12 Thread Jeffrey Hugo

On 6/12/2019 12:42 PM, Bjorn Andersson wrote:

On Wed 12 Jun 11:07 PDT 2019, Jeffrey Hugo wrote:


On Wed, Jun 5, 2019 at 3:09 PM Bjorn Andersson
 wrote:


Boot splash screen or EFI framebuffer requires the display hardware to
operate while the Linux iommu driver probes. Therefore, we cannot simply
wipe out the SMR register settings programmed by the bootloader.

Detect which SMR registers are in use during probe, and which context
banks they are associated with. Reserve these context banks for the
first Linux device whose stream-id matches the SMR register.

Any existing page-tables will be discarded.

Heavily based on downstream implementation by Patrick Daly
.

Signed-off-by: Bjorn Andersson 


Reviewed-by: Jeffrey Hugo 

This is very similar to the hacked up version I did, and I'm glad to see it
cleaned up and posted.

This is important work, and I want to see it move forward, however it doesn't
completely address everything, IMO.  Fixing the remaining issues certainly
can be follow on work, but I don't know if they would end up affecting this
implementation.

So, with this series, we've gone from a crash on msm8998/sdm845, to causing
context faults.  This is because while we are now not nuking the config, we
are preventing the bootloader installed translations from working.  Essentially
the display already has a mapping (technically passthrough) that is likely being
used by EFIFB.  The instant the SMMU inits, that mapping becomes invalid,
and the display is going to generate context faults.  While not fatal,
this provides
a bad user experience as there are nasty messages, and EFIFB stops working.

The situation does get resolved once the display driver inits and takes over the
HW and SMMU mappings, so we are not stuck with it, but it would be nice to
have that addressed as well, ie have EFIFB working up until the Linux display
driver takes over.



But do you see this even though you don't enable the mdss driver?


The only way I can see that happening is if the SMMU leaves the context bank
alone, with M == 0, and the iommu framework defines a domain attribute or
some other mechanism to allow the driver to flip the M bit in the context bank
after installing the necessary handover translations.



 From what I can tell this implementation leaves the framebuffer mapping
in working condition until the attach_dev of the display driver, at
which time we do get context faults until the display driver is done
initializing things.

So we're reducing the problem to a question of how to seamlessly carry
over the mapping during the attach.


Actually, you are correct.  Without mdss this won't occur.  The window 
is from the creation of the default domain for the mdss device, to the 
point that the display is fully init'd (and EFIFB is shut down).




Regards,
Bjorn


---
  drivers/iommu/arm-smmu-regs.h |  2 +
  drivers/iommu/arm-smmu.c  | 80 ---
  2 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h
index e9132a926761..8c1fd84032a2 100644
--- a/drivers/iommu/arm-smmu-regs.h
+++ b/drivers/iommu/arm-smmu-regs.h
@@ -105,7 +105,9 @@
  #define ARM_SMMU_GR0_SMR(n)(0x800 + ((n) << 2))
  #define SMR_VALID  (1 << 31)
  #define SMR_MASK_SHIFT 16
+#define SMR_MASK_MASK  0x7fff
  #define SMR_ID_SHIFT   0
+#define SMR_ID_MASK0x

  #define ARM_SMMU_GR0_S2CR(n)   (0xc00 + ((n) << 2))
  #define S2CR_CBNDX_SHIFT   0
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 5e54cc0a28b3..c8629a656b42 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -135,6 +135,7 @@ struct arm_smmu_s2cr {
 enum arm_smmu_s2cr_type type;
 enum arm_smmu_s2cr_privcfg  privcfg;
 u8  cbndx;
+   boolhandoff;
  };

  #define s2cr_init_val (struct arm_smmu_s2cr){  \
@@ -399,9 +400,22 @@ static int arm_smmu_register_legacy_master(struct device 
*dev,
 return err;
  }

-static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
+static int __arm_smmu_alloc_cb(struct arm_smmu_device *smmu, int start,
+  struct device *dev)
  {
+   struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+   unsigned long *map = smmu->context_map;
+   int end = smmu->num_context_banks;
+   int cbndx;
 int idx;
+   int i;
+
+   for_each_cfg_sme(fwspec, i, idx) {
+   if (smmu->s2crs[idx].handoff) {
+   cbndx = smmu->s2crs[idx].cbndx;
+   goto found_handoff;
+   }
+   }

 do {
 idx = find_next_zero_bit(map, end, start);
@@ -410,6 +424,17 @@ static int __arm_smmu_alloc_bitmap(unsigned long *map, int 
start, int end)
 

Re: [RFC 1/2] iommu: arm-smmu: Handoff SMR registers and context banks

2019-06-12 Thread Bjorn Andersson
On Wed 12 Jun 11:07 PDT 2019, Jeffrey Hugo wrote:

> On Wed, Jun 5, 2019 at 3:09 PM Bjorn Andersson
>  wrote:
> >
> > Boot splash screen or EFI framebuffer requires the display hardware to
> > operate while the Linux iommu driver probes. Therefore, we cannot simply
> > wipe out the SMR register settings programmed by the bootloader.
> >
> > Detect which SMR registers are in use during probe, and which context
> > banks they are associated with. Reserve these context banks for the
> > first Linux device whose stream-id matches the SMR register.
> >
> > Any existing page-tables will be discarded.
> >
> > Heavily based on downstream implementation by Patrick Daly
> > .
> >
> > Signed-off-by: Bjorn Andersson 
> 
> Reviewed-by: Jeffrey Hugo 
> 
> This is very similar to the hacked up version I did, and I'm glad to see it
> cleaned up and posted.
> 
> This is important work, and I want to see it move forward, however it doesn't
> completely address everything, IMO.  Fixing the remaining issues certainly
> can be follow on work, but I don't know if they would end up affecting this
> implementation.
> 
> So, with this series, we've gone from a crash on msm8998/sdm845, to causing
> context faults.  This is because while we are now not nuking the config, we
> are preventing the bootloader installed translations from working.  
> Essentially
> the display already has a mapping (technically passthrough) that is likely 
> being
> used by EFIFB.  The instant the SMMU inits, that mapping becomes invalid,
> and the display is going to generate context faults.  While not fatal,
> this provides
> a bad user experience as there are nasty messages, and EFIFB stops working.
> 
> The situation does get resolved once the display driver inits and takes over 
> the
> HW and SMMU mappings, so we are not stuck with it, but it would be nice to
> have that addressed as well, ie have EFIFB working up until the Linux display
> driver takes over.
> 

But do you see this even though you don't enable the mdss driver?

> The only way I can see that happening is if the SMMU leaves the context bank
> alone, with M == 0, and the iommu framework defines a domain attribute or
> some other mechanism to allow the driver to flip the M bit in the context bank
> after installing the necessary handover translations.
> 

>From what I can tell this implementation leaves the framebuffer mapping
in working condition until the attach_dev of the display driver, at
which time we do get context faults until the display driver is done
initializing things.

So we're reducing the problem to a question of how to seamlessly carry
over the mapping during the attach.

Regards,
Bjorn

> > ---
> >  drivers/iommu/arm-smmu-regs.h |  2 +
> >  drivers/iommu/arm-smmu.c  | 80 ---
> >  2 files changed, 77 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h
> > index e9132a926761..8c1fd84032a2 100644
> > --- a/drivers/iommu/arm-smmu-regs.h
> > +++ b/drivers/iommu/arm-smmu-regs.h
> > @@ -105,7 +105,9 @@
> >  #define ARM_SMMU_GR0_SMR(n)(0x800 + ((n) << 2))
> >  #define SMR_VALID  (1 << 31)
> >  #define SMR_MASK_SHIFT 16
> > +#define SMR_MASK_MASK  0x7fff
> >  #define SMR_ID_SHIFT   0
> > +#define SMR_ID_MASK0x
> >
> >  #define ARM_SMMU_GR0_S2CR(n)   (0xc00 + ((n) << 2))
> >  #define S2CR_CBNDX_SHIFT   0
> > diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> > index 5e54cc0a28b3..c8629a656b42 100644
> > --- a/drivers/iommu/arm-smmu.c
> > +++ b/drivers/iommu/arm-smmu.c
> > @@ -135,6 +135,7 @@ struct arm_smmu_s2cr {
> > enum arm_smmu_s2cr_type type;
> > enum arm_smmu_s2cr_privcfg  privcfg;
> > u8  cbndx;
> > +   boolhandoff;
> >  };
> >
> >  #define s2cr_init_val (struct arm_smmu_s2cr){  \
> > @@ -399,9 +400,22 @@ static int arm_smmu_register_legacy_master(struct 
> > device *dev,
> > return err;
> >  }
> >
> > -static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
> > +static int __arm_smmu_alloc_cb(struct arm_smmu_device *smmu, int start,
> > +  struct device *dev)
> >  {
> > +   struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
> > +   unsigned long *map = smmu->context_map;
> > +   int end = smmu->num_context_banks;
> > +   int cbndx;
> > int idx;
> > +   int i;
> > +
> > +   for_each_cfg_sme(fwspec, i, idx) {
> > +   if (smmu->s2crs[idx].handoff) {
> > +   cbndx = smmu->s2crs[idx].cbndx;
> > +   goto found_handoff;
> > +   }
> > +   }
> >
> > do {
> > idx = find_next_zero_bit(map, end, start);
> > @@ -410,6 +424,17 @@ static int 

Re: [RFC 1/2] iommu: arm-smmu: Handoff SMR registers and context banks

2019-06-12 Thread Jeffrey Hugo
On Wed, Jun 5, 2019 at 3:09 PM Bjorn Andersson
 wrote:
>
> Boot splash screen or EFI framebuffer requires the display hardware to
> operate while the Linux iommu driver probes. Therefore, we cannot simply
> wipe out the SMR register settings programmed by the bootloader.
>
> Detect which SMR registers are in use during probe, and which context
> banks they are associated with. Reserve these context banks for the
> first Linux device whose stream-id matches the SMR register.
>
> Any existing page-tables will be discarded.
>
> Heavily based on downstream implementation by Patrick Daly
> .
>
> Signed-off-by: Bjorn Andersson 

Reviewed-by: Jeffrey Hugo 

This is very similar to the hacked up version I did, and I'm glad to see it
cleaned up and posted.

This is important work, and I want to see it move forward, however it doesn't
completely address everything, IMO.  Fixing the remaining issues certainly
can be follow on work, but I don't know if they would end up affecting this
implementation.

So, with this series, we've gone from a crash on msm8998/sdm845, to causing
context faults.  This is because while we are now not nuking the config, we
are preventing the bootloader installed translations from working.  Essentially
the display already has a mapping (technically passthrough) that is likely being
used by EFIFB.  The instant the SMMU inits, that mapping becomes invalid,
and the display is going to generate context faults.  While not fatal,
this provides
a bad user experience as there are nasty messages, and EFIFB stops working.

The situation does get resolved once the display driver inits and takes over the
HW and SMMU mappings, so we are not stuck with it, but it would be nice to
have that addressed as well, ie have EFIFB working up until the Linux display
driver takes over.

The only way I can see that happening is if the SMMU leaves the context bank
alone, with M == 0, and the iommu framework defines a domain attribute or
some other mechanism to allow the driver to flip the M bit in the context bank
after installing the necessary handover translations.

> ---
>  drivers/iommu/arm-smmu-regs.h |  2 +
>  drivers/iommu/arm-smmu.c  | 80 ---
>  2 files changed, 77 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h
> index e9132a926761..8c1fd84032a2 100644
> --- a/drivers/iommu/arm-smmu-regs.h
> +++ b/drivers/iommu/arm-smmu-regs.h
> @@ -105,7 +105,9 @@
>  #define ARM_SMMU_GR0_SMR(n)(0x800 + ((n) << 2))
>  #define SMR_VALID  (1 << 31)
>  #define SMR_MASK_SHIFT 16
> +#define SMR_MASK_MASK  0x7fff
>  #define SMR_ID_SHIFT   0
> +#define SMR_ID_MASK0x
>
>  #define ARM_SMMU_GR0_S2CR(n)   (0xc00 + ((n) << 2))
>  #define S2CR_CBNDX_SHIFT   0
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index 5e54cc0a28b3..c8629a656b42 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -135,6 +135,7 @@ struct arm_smmu_s2cr {
> enum arm_smmu_s2cr_type type;
> enum arm_smmu_s2cr_privcfg  privcfg;
> u8  cbndx;
> +   boolhandoff;
>  };
>
>  #define s2cr_init_val (struct arm_smmu_s2cr){  \
> @@ -399,9 +400,22 @@ static int arm_smmu_register_legacy_master(struct device 
> *dev,
> return err;
>  }
>
> -static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
> +static int __arm_smmu_alloc_cb(struct arm_smmu_device *smmu, int start,
> +  struct device *dev)
>  {
> +   struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
> +   unsigned long *map = smmu->context_map;
> +   int end = smmu->num_context_banks;
> +   int cbndx;
> int idx;
> +   int i;
> +
> +   for_each_cfg_sme(fwspec, i, idx) {
> +   if (smmu->s2crs[idx].handoff) {
> +   cbndx = smmu->s2crs[idx].cbndx;
> +   goto found_handoff;
> +   }
> +   }
>
> do {
> idx = find_next_zero_bit(map, end, start);
> @@ -410,6 +424,17 @@ static int __arm_smmu_alloc_bitmap(unsigned long *map, 
> int start, int end)
> } while (test_and_set_bit(idx, map));
>
> return idx;
> +
> +found_handoff:
> +   for (i = 0; i < smmu->num_mapping_groups; i++) {
> +   if (smmu->s2crs[i].cbndx == cbndx) {
> +   smmu->s2crs[i].cbndx = 0;
> +   smmu->s2crs[i].handoff = false;
> +   smmu->s2crs[i].count--;
> +   }
> +   }
> +
> +   return cbndx;
>  }
>
>  static void __arm_smmu_free_bitmap(unsigned long *map, int idx)
> @@ -759,7 +784,8 @@ static void arm_smmu_write_context_bank(struct 
> arm_smmu_device *smmu, int idx)
>  }
>
>  static int