diff mbox

[PATCHv3,10/19] iommu/tegra: smmu: Get "nvidia,swgroups" from DT

Message ID 1382092020-13170-11-git-send-email-hdoyu@nvidia.com
State Superseded, archived
Headers show

Commit Message

Hiroshi Doyu Oct. 18, 2013, 10:26 a.m. UTC
This provides the info about which H/W Accelerators are supported on
Tegra SoC. This info is passed from DT. This is necessary to have the
unified SMMU driver among Tegra SoCs. Instead of using platform data,
DT passes "nvidia,swgroups" now. DT is mandatory in Tegra.

Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
 .../bindings/iommu/nvidia,tegra30-smmu.txt         |  6 +++++
 drivers/iommu/tegra-smmu.c                         | 31 ++++++++++------------
 2 files changed, 20 insertions(+), 17 deletions(-)

Comments

Grant Likely Oct. 24, 2013, 8:58 a.m. UTC | #1
On Fri, 18 Oct 2013 13:26:51 +0300, Hiroshi Doyu <hdoyu@nvidia.com> wrote:
> This provides the info about which H/W Accelerators are supported on
> Tegra SoC. This info is passed from DT. This is necessary to have the
> unified SMMU driver among Tegra SoCs. Instead of using platform data,
> DT passes "nvidia,swgroups" now. DT is mandatory in Tegra.
> 
> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
> ---
> @@ -1200,6 +1193,9 @@ static int tegra_smmu_probe(struct platform_device *pdev)
>  	if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
>  		return -ENODEV;
>  
> +	if (of_property_read_u64(dev->of_node, "nvidia,swgroups", &swgroups))
> +		return -ENODEV;
> +

Best practice: A new property has been created here. If the property
isn't present, then it should default to the previous meaning instead of
outright failing. (or make a strong argument that no one is using this
yet and therefore is not breakage).


--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Warren Oct. 30, 2013, 10:22 p.m. UTC | #2
On 10/24/2013 02:58 AM, Grant Likely wrote:
> On Fri, 18 Oct 2013 13:26:51 +0300, Hiroshi Doyu <hdoyu@nvidia.com> wrote:
>> This provides the info about which H/W Accelerators are supported on
>> Tegra SoC. This info is passed from DT. This is necessary to have the
>> unified SMMU driver among Tegra SoCs. Instead of using platform data,
>> DT passes "nvidia,swgroups" now. DT is mandatory in Tegra.
>>
>> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
>> ---
>> @@ -1200,6 +1193,9 @@ static int tegra_smmu_probe(struct platform_device *pdev)
>>  	if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
>>  		return -ENODEV;
>>  
>> +	if (of_property_read_u64(dev->of_node, "nvidia,swgroups", &swgroups))
>> +		return -ENODEV;
>> +
> 
> Best practice: A new property has been created here. If the property
> isn't present, then it should default to the previous meaning instead of
> outright failing. (or make a strong argument that no one is using this
> yet and therefore is not breakage).

We definitely don't have anyone using this binding yet upstream, and
even the reg properties in the DT were wrong for the device, so it
couldn't possibly have worked:-(
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Warren Oct. 30, 2013, 10:33 p.m. UTC | #3
On 10/18/2013 04:26 AM, Hiroshi Doyu wrote:
> This provides the info about which H/W Accelerators are supported on
> Tegra SoC. This info is passed from DT. This is necessary to have the
> unified SMMU driver among Tegra SoCs. Instead of using platform data,
> DT passes "nvidia,swgroups" now. DT is mandatory in Tegra.

> diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> index 89fb543..6a844b3 100644
> --- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> +++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> @@ -8,6 +8,11 @@ Required properties:
>  - nvidia,#asids : # of ASIDs
>  - dma-window : IOVA start address and length.
>  - nvidia,ahb : phandle to the ahb bus connected to SMMU.
> +- nvidia,swgroups: A bitmap of supported HardWare Accelerators(HWA).
> +  Each bit represents one swgroup. The assignments may be found in header
> +  file <dt-bindings/memory/tegra-swgroup.h>. Its max is 64. 2 cells

That file doesn't exist at this point in the series. I think you should
create a patch up-front that adds that header, and modifies the binding
document, all in one go, and separate from any driver code changes.
Separate DT/driver patches were IIRC agreed to be preferablte at the
recent ARM workshop.

> +  are required. This unique ID info can be used to calculate
> +  MC_SMMU_<SWGROUP name>_ASID_0 offset and HOTRESET bit.

I'm afraid I still don't quite understand what a swgroup is.

IIUC, the HW works like this based on comments in a previous patch:

Each bus-master attached to the MMU passes a "memory client ID" along
with the transaction. Some devices can generate transactions with
different "memory client IDs". There is a mapping inside the SMMU from
"memory client ID" to "address space ID". (I don't know what form that
mapping takes; can you point out where it's set up?). Each "address
space ID" has its own set of page tables. Is "swgroup" simply another
name for "memory client ID"? If so, it'd be good to use just one term
consistently.

Assuming "swgroup" is "memory client ID", why can't the driver just
create a list/... of known swgroups at runtime, based on the swgroup
values that each device uses, which would presumably be either
hard-coded in the client device's driver, or represented in the DT smmu
property's "iommu specifier" value.

> @@ -380,12 +383,10 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
>  	if (!on)
>  		map = smmu_client_hwgrp(c);
>  
> -	for_each_set_bit(i, &map, HWGRP_COUNT) {
> +	for_each_set_bit(i, bitmap, sizeof(map) * BITS_PER_BYTE) {
>  		offs = HWGRP_ASID_REG(i);
>  		val = smmu_read(smmu, offs);
>  		if (on) {
> -			if (WARN_ON(val & mask))
> -				goto err_hw_busy;
>  			val |= mask;
>  		} else {
>  			WARN_ON((val & mask) == mask);
> @@ -396,15 +397,6 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
>  	FLUSH_SMMU_REGS(smmu);
>  	c->hwgrp = map;
>  	return 0;
> -
> -err_hw_busy:
> -	for_each_set_bit(i, &map, HWGRP_COUNT) {
> -		offs = HWGRP_ASID_REG(i);
> -		val = smmu_read(smmu, offs);
> -		val &= ~mask;
> -		smmu_write(smmu, val, offs);
> -	}
> -	return -EBUSY;
>  }

I must admit to having zero idea what that part of the patch is doing
semantically. Some form of explanation in the commit description would
be useful.
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hiroshi Doyu Oct. 31, 2013, 8:17 a.m. UTC | #4
Stephen Warren <swarren@wwwdotorg.org> wrote @ Wed, 30 Oct 2013 23:33:32 +0100:

> > +  are required. This unique ID info can be used to calculate
> > +  MC_SMMU_<SWGROUP name>_ASID_0 offset and HOTRESET bit.
> 
> I'm afraid I still don't quite understand what a swgroup is.
> 
> IIUC, the HW works like this based on comments in a previous patch:
> 
> Each bus-master attached to the MMU passes a "memory client ID" along
> with the transaction. Some devices can generate transactions with
> different "memory client IDs". There is a mapping inside the SMMU from
> "memory client ID" to "address space ID". (I don't know what form that
> mapping takes; can you point out where it's set up?). Each "address
> space ID" has its own set of page tables.

Right.
"memory client ID" is used to find out MC_SMMU_<swgroup>_ASID_0
register. This register is used to associate <swgroup> to address
space(AS). <swgroup> == H/W. <swgroup> can be attached to any AS.

> Is "swgroup" simply another name for "memory client ID"? If so, it'd
> be good to use just one term consistently.

I used the name "memory client ID" because this ID can be used to find
out HOTRESET bit in MC_CLIENT_HOTRESET_*_0 registers in addition to
find the MC_SMMU_<swgroup>_ASID_0 offset. But maybe it's easy to use
the consistent name as "swgroup". If laster HOTRESET wants automatic
calculation they could borrow/redefine the same ID list, just
replacing the prefix. What do you think?

> Assuming "swgroup" is "memory client ID",

Yes

> why can't the driver just
> create a list/... of known swgroups at runtime, based on the swgroup
> values that each device uses, which would presumably be either
> hard-coded in the client device's driver, or represented in the DT smmu
> property's "iommu specifier" value.

Why we have "nvidia,swgroups" is just to avoid a device node having a
wrong "nvidia,memory-clients" which is not supported by that Tegra
SoC, which could crash kernel eventually. This info may be residual
since we define both "nvidia,swgroups" and "nvidia,memory-clients" at
once in DT. I'll remove "nvidia,swgroups" in SMMU node.
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Rutland Oct. 31, 2013, 5:15 p.m. UTC | #5
On Fri, Oct 18, 2013 at 11:26:51AM +0100, Hiroshi Doyu wrote:
> This provides the info about which H/W Accelerators are supported on
> Tegra SoC. This info is passed from DT. This is necessary to have the
> unified SMMU driver among Tegra SoCs. Instead of using platform data,
> DT passes "nvidia,swgroups" now. DT is mandatory in Tegra.
> 
> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
> ---
>  .../bindings/iommu/nvidia,tegra30-smmu.txt         |  6 +++++
>  drivers/iommu/tegra-smmu.c                         | 31 ++++++++++------------
>  2 files changed, 20 insertions(+), 17 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> index 89fb543..6a844b3 100644
> --- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> +++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> @@ -8,6 +8,11 @@ Required properties:
>  - nvidia,#asids : # of ASIDs
>  - dma-window : IOVA start address and length.
>  - nvidia,ahb : phandle to the ahb bus connected to SMMU.
> +- nvidia,swgroups: A bitmap of supported HardWare Accelerators(HWA).
> +  Each bit represents one swgroup. The assignments may be found in header
> +  file <dt-bindings/memory/tegra-swgroup.h>. Its max is 64. 2 cells
> +  are required. This unique ID info can be used to calculate
> +  MC_SMMU_<SWGROUP name>_ASID_0 offset and HOTRESET bit.

I'd prefer that you pointed out the type of the property explicitly at the
beginning of the description. It's difficult to spot it in the middle, and
while the current description defines that the property is two cells, it
doesn't point out that they are expected to form a (big endian) u64 (rather
than an array of two u32s).

While we don't yet have a formal set of rules for consistent binding
documentation, defining the explicitly is one of the requirements I'd like to
push for in new bindings. Placing this at the start of the description makes it
far easier to skim a binding document and perform basic sanity checks of the
binding itself, dts using the binding, and kernel code parsing it.

Cheers,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Rutland Oct. 31, 2013, 5:31 p.m. UTC | #6
On Wed, Oct 30, 2013 at 10:33:32PM +0000, Stephen Warren wrote:
> On 10/18/2013 04:26 AM, Hiroshi Doyu wrote:
> > This provides the info about which H/W Accelerators are supported on
> > Tegra SoC. This info is passed from DT. This is necessary to have the
> > unified SMMU driver among Tegra SoCs. Instead of using platform data,
> > DT passes "nvidia,swgroups" now. DT is mandatory in Tegra.
> 
> > diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> > index 89fb543..6a844b3 100644
> > --- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> > +++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
> > @@ -8,6 +8,11 @@ Required properties:
> >  - nvidia,#asids : # of ASIDs
> >  - dma-window : IOVA start address and length.
> >  - nvidia,ahb : phandle to the ahb bus connected to SMMU.
> > +- nvidia,swgroups: A bitmap of supported HardWare Accelerators(HWA).
> > +  Each bit represents one swgroup. The assignments may be found in header
> > +  file <dt-bindings/memory/tegra-swgroup.h>. Its max is 64. 2 cells
> 
> That file doesn't exist at this point in the series. I think you should
> create a patch up-front that adds that header, and modifies the binding
> document, all in one go, and separate from any driver code changes.
> Separate DT/driver patches were IIRC agreed to be preferablte at the
> recent ARM workshop.

That certainly matches what I recall from the ARM minisummit.

> 
> > +  are required. This unique ID info can be used to calculate
> > +  MC_SMMU_<SWGROUP name>_ASID_0 offset and HOTRESET bit.
> 
> I'm afraid I still don't quite understand what a swgroup is.
> 
> IIUC, the HW works like this based on comments in a previous patch:
> 
> Each bus-master attached to the MMU passes a "memory client ID" along
> with the transaction. Some devices can generate transactions with
> different "memory client IDs". There is a mapping inside the SMMU from
> "memory client ID" to "address space ID". (I don't know what form that
> mapping takes; can you point out where it's set up?). Each "address
> space ID" has its own set of page tables. Is "swgroup" simply another
> name for "memory client ID"? If so, it'd be good to use just one term
> consistently.

The ARM SMMU refers to these as "stream IDs", as that's the architected name
that appears in all the hardware documentation. If "swgroup" is the term used
in the hardware documentation I think it makes sense to stick with it, as long
as there's a description in the binding document that points out what an
"swgroup" is. If there's a common term that both binding documents could refer
to to define what stream-id/swgroup are, that would be nice.

There are a few other differences in approach with the current ARM SMMU binding:
Documentation/devicetree/bindings/iommu/arm,smmu.txt

We should probably begin to look for commonality such that the next iommu
device that gets a binding is closer to a generic iommu class binding.

> 
> Assuming "swgroup" is "memory client ID", why can't the driver just
> create a list/... of known swgroups at runtime, based on the swgroup
> values that each device uses, which would presumably be either
> hard-coded in the client device's driver, or represented in the DT smmu
> property's "iommu specifier" value.

Assuming that the swgroup values of IP block instances are static, that sounds
like the ARM SMMU binding approach. Are the IDs static, or can they be assigned
at runtime?

Thanks,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Will Deacon Oct. 31, 2013, 6 p.m. UTC | #7
On Thu, Oct 31, 2013 at 05:31:33PM +0000, Mark Rutland wrote:
> On Wed, Oct 30, 2013 at 10:33:32PM +0000, Stephen Warren wrote:
> > I'm afraid I still don't quite understand what a swgroup is.
> > 
> > IIUC, the HW works like this based on comments in a previous patch:
> > 
> > Each bus-master attached to the MMU passes a "memory client ID" along
> > with the transaction. Some devices can generate transactions with
> > different "memory client IDs". There is a mapping inside the SMMU from
> > "memory client ID" to "address space ID". (I don't know what form that
> > mapping takes; can you point out where it's set up?). Each "address
> > space ID" has its own set of page tables. Is "swgroup" simply another
> > name for "memory client ID"? If so, it'd be good to use just one term
> > consistently.
> 
> The ARM SMMU refers to these as "stream IDs", as that's the architected name
> that appears in all the hardware documentation. If "swgroup" is the term used
> in the hardware documentation I think it makes sense to stick with it, as long
> as there's a description in the binding document that points out what an
> "swgroup" is. If there's a common term that both binding documents could refer
> to to define what stream-id/swgroup are, that would be nice.

Sounds like:

  stream id == memory client id   (part of the binding)
  context id == address space id  (internal to the driver)

> There are a few other differences in approach with the current ARM SMMU binding:
> Documentation/devicetree/bindings/iommu/arm,smmu.txt
> 
> We should probably begin to look for commonality such that the next iommu
> device that gets a binding is closer to a generic iommu class binding.
> 
> > 
> > Assuming "swgroup" is "memory client ID", why can't the driver just
> > create a list/... of known swgroups at runtime, based on the swgroup
> > values that each device uses, which would presumably be either
> > hard-coded in the client device's driver, or represented in the DT smmu
> > property's "iommu specifier" value.
> 
> Assuming that the swgroup values of IP block instances are static, that sounds
> like the ARM SMMU binding approach. Are the IDs static, or can they be assigned
> at runtime?

The only valid case I can think of for dynamic IDs is for hotpluggable
devices sitting being a form of host controller (e.g. PCIe). In that case,
the host controller should handle the ID assignment, which must remain
static for the lifetime of a device.

Will
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hiroshi Doyu Nov. 1, 2013, 7:27 a.m. UTC | #8
Mark Rutland <mark.rutland@arm.com> wrote @ Thu, 31 Oct 2013 18:31:33 +0100:

> > Assuming "swgroup" is "memory client ID", why can't the driver just
> > create a list/... of known swgroups at runtime, based on the swgroup
> > values that each device uses, which would presumably be either
> > hard-coded in the client device's driver, or represented in the DT smmu
> > property's "iommu specifier" value.
> 
> Assuming that the swgroup values of IP block instances are static, that sounds
> like the ARM SMMU binding approach. Are the IDs static, or can they be assigned
> at runtime?

It's static.

But swgroup ID isn't documented in TRM. ID is basically calculated from register offset.

<swgroup ID> = (MC_SMMU_<swgroup name>_ASID_0 - MC_SMMU_<the 1st swgroup name>_ASID_0) / 4

Or 

MC_SMMU_<swgroup name>_ASID_0 = 4 * <swgroup ID> + MC_SMMU_<the 1st swgroup name>_ASID_0)
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hiroshi Doyu Nov. 1, 2013, 7:41 a.m. UTC | #9
> > The ARM SMMU refers to these as "stream IDs", as that's the architected name
> > that appears in all the hardware documentation. If "swgroup" is the term used
> > in the hardware documentation I think it makes sense to stick with it, as long
> > as there's a description in the binding document that points out what an
> > "swgroup" is. If there's a common term that both binding documents could refer
> > to to define what stream-id/swgroup are, that would be nice.
>
> Sounds like:
>
>   stream id == memory client id   (part of the binding)
>   context id == address space id  (internal to the driver)

Good explanation. This would be helpful when I read ARM SMMU TRM;)

> > There are a few other differences in approach with the current ARM SMMU binding:
> > Documentation/devicetree/bindings/iommu/arm,smmu.txt
> >
> > We should probably begin to look for commonality such that the next iommu
> > device that gets a binding is closer to a generic iommu class binding.

I think that now I got the "mmu-masters".

- mmu-masters   : A list of phandles to device nodes representing bus
		  masters for which the SMMU can provide a translation
		  and their corresponding StreamIDs (see example below).
		  Each device node linked from this list must have a
		  "#stream-id-cells" property, indicating the number of
		  StreamIDs associated with it.

If I apply this to Tegra, this would be:

	host1x {
            #swgroup-id-cells = <1>;

               gr3d {
                   #swgroup-id-cells = <2>;
               };

	};

	smmu: iommu {
		compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
		reg = <0x70019010 0x02c>,
		      <0x700191f0 0x010>,
		      <0x70019228 0x074>;
		.......
		mmu-masters = <&host1x TEGRA_SWGROUP_HC>,
			      <&mpe TEGRA_SWGROUP_MPE>,
			      ..........
			      <&gr3d TEGRA_SWGROUP_NV TEGRA_SWGROUP_NV2>;
	};

From consistency POV, this may look better. Also if "stream-id-cells",
"mmu-masters" is defined as IOMMU standard tag, it would be more
easier. Otherwise, I may need to stick to "swgroup-id-cells".

> > > Assuming "swgroup" is "memory client ID", why can't the driver just
> > > create a list/... of known swgroups at runtime, based on the swgroup
> > > values that each device uses, which would presumably be either
> > > hard-coded in the client device's driver, or represented in the DT smmu
> > > property's "iommu specifier" value.
> >
> > Assuming that the swgroup values of IP block instances are static, that sounds
> > like the ARM SMMU binding approach. Are the IDs static, or can they be assigned
> > at runtime?
>
> The only valid case I can think of for dynamic IDs is for hotpluggable
> devices sitting being a form of host controller (e.g. PCIe). In that case,
> the host controller should handle the ID assignment, which must remain
> static for the lifetime of a device.

In Tegra PCIe clients belong to one swgroup statically.
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Warren Nov. 1, 2013, 4:54 p.m. UTC | #10
On 10/31/2013 02:17 AM, Hiroshi Doyu wrote:
> Stephen Warren <swarren@wwwdotorg.org> wrote @ Wed, 30 Oct 2013 23:33:32 +0100:
...
> Right.
> "memory client ID" is used to find out MC_SMMU_<swgroup>_ASID_0
> register. This register is used to associate <swgroup> to address
> space(AS). <swgroup> == H/W. <swgroup> can be attached to any AS.
> 
>> Is "swgroup" simply another name for "memory client ID"? If so, it'd
>> be good to use just one term consistently.
> 
> I used the name "memory client ID" because this ID can be used to find
> out HOTRESET bit in MC_CLIENT_HOTRESET_*_0 registers in addition to
> find the MC_SMMU_<swgroup>_ASID_0 offset. But maybe it's easy to use
> the consistent name as "swgroup". If laster HOTRESET wants automatic
> calculation they could borrow/redefine the same ID list, just
> replacing the prefix. What do you think?
> 
>> Assuming "swgroup" is "memory client ID",
> 
> Yes

I took a look at the TRM, and it does look like there's a distinction
between client IDs and swgroups. The basic idea is that each swgroup
encompasses n (n >= 1) memory client IDs. So, we do have to use both terms.

See for example the tables in section 20.11.1.12 and 20.11.1.15 of
Tegra4 (Tegra114) TRM v01 that describe (some?) client ID -> swgroup
mappings. Section 20.3.4 states that whenever a translation error
occurs, both the module ID (I assume swgroup) and client ID will be
recorded, although the interrupt registers don't appear to be
documented, so I can't check this:-(

However, the bits in the HOTRESET register appear mostly align with
swgroup IDs rather client IDs, so I think some of your explanation above
is innaccurate.

I do want to point out that the HOTRESET bits don't 100% match the
swgroup IDs though, so the driver needs to be careful, and perhaps
contain some kind of mapping table between the two numbering spaces. In
particular, on Tegra114, swgroups and ASID registers appear in order
PPCS, <gap>, SATA, whereas there's no gap between the HOTRESET bits for
PPCS and SATA, assuming the TRM is correct.
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hiroshi Doyu Nov. 4, 2013, 6:59 a.m. UTC | #11
Stephen Warren <swarren@wwwdotorg.org> wrote @ Fri, 1 Nov 2013 17:54:37 +0100:

> On 10/31/2013 02:17 AM, Hiroshi Doyu wrote:
> > Stephen Warren <swarren@wwwdotorg.org> wrote @ Wed, 30 Oct 2013 23:33:32 +0100:
> ...
> > Right.
> > "memory client ID" is used to find out MC_SMMU_<swgroup>_ASID_0
> > register. This register is used to associate <swgroup> to address
> > space(AS). <swgroup> == H/W. <swgroup> can be attached to any AS.
> > 
> >> Is "swgroup" simply another name for "memory client ID"? If so, it'd
> >> be good to use just one term consistently.
> > 
> > I used the name "memory client ID" because this ID can be used to find
> > out HOTRESET bit in MC_CLIENT_HOTRESET_*_0 registers in addition to
> > find the MC_SMMU_<swgroup>_ASID_0 offset. But maybe it's easy to use
> > the consistent name as "swgroup". If laster HOTRESET wants automatic
> > calculation they could borrow/redefine the same ID list, just
> > replacing the prefix. What do you think?
> > 
> >> Assuming "swgroup" is "memory client ID",
> > 
> > Yes
> 
> I took a look at the TRM, and it does look like there's a distinction
> between client IDs and swgroups. The basic idea is that each swgroup
> encompasses n (n >= 1) memory client IDs. So, we do have to use both terms.

Well, I considred that memory-client's' ~= 'a' swgroup, and the term
"swgroup" isn't used in HOTREST, where actually each bit represents
a "swgroup".

> However, the bits in the HOTRESET register appear mostly align with
> swgroup IDs rather client IDs, so I think some of your explanation above
> is innaccurate.
> 
> I do want to point out that the HOTRESET bits don't 100% match the
> swgroup IDs though, so the driver needs to be careful, and perhaps
> contain some kind of mapping table between the two numbering spaces. In
> particular, on Tegra114, swgroups and ASID registers appear in order
> PPCS, <gap>, SATA, whereas there's no gap between the HOTRESET bits for
> PPCS and SATA, assuming the TRM is correct.

In our downstream, basically I provided to two conversion tables, one
for "MC_SMMU_<swgroup ID>_ASID_0" and the other for "HOTRESET"
bit. That table converts ID to them respectively. I think that this is
acceptable.
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
index 89fb543..6a844b3 100644
--- a/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
@@ -8,6 +8,11 @@  Required properties:
 - nvidia,#asids : # of ASIDs
 - dma-window : IOVA start address and length.
 - nvidia,ahb : phandle to the ahb bus connected to SMMU.
+- nvidia,swgroups: A bitmap of supported HardWare Accelerators(HWA).
+  Each bit represents one swgroup. The assignments may be found in header
+  file <dt-bindings/memory/tegra-swgroup.h>. Its max is 64. 2 cells
+  are required. This unique ID info can be used to calculate
+  MC_SMMU_<SWGROUP name>_ASID_0 offset and HOTRESET bit.
 
 Example:
 	smmu {
@@ -17,5 +22,6 @@  Example:
 		       0x7000f228 0x05c>;
 		nvidia,#asids = <4>;		/* # of ASIDs */
 		dma-window = <0 0x40000000>;	/* IOVA start & length */
+		nvidia,swgroups = <0x00000000 0x000779ff>;
 		nvidia,ahb = <&ahb>;
 	};
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 4dcdd6c..22951e6 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -247,7 +247,7 @@  struct smmu_client {
 	struct device		*dev;
 	struct list_head	list;
 	struct smmu_as		*as;
-	u32			hwgrp;
+	u64			hwgrp;
 };
 
 /*
@@ -289,6 +289,8 @@  struct smmu_device {
 	struct device	*dev;
 	struct page *avp_vector_page;	/* dummy page shared by all AS's */
 
+	u64 swgroups;			/* swgroup ID bitmap */
+
 	/*
 	 * Register image savers for suspend/resume
 	 */
@@ -364,15 +366,16 @@  static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
  */
 #define FLUSH_SMMU_REGS(smmu)	smmu_read(smmu, SMMU_CONFIG)
 
-#define smmu_client_hwgrp(c) (u32)((c)->dev->platform_data)
+#define smmu_client_hwgrp(c)	(c->as->smmu->swgroups)
 
 static int __smmu_client_set_hwgrp(struct smmu_client *c,
-				   unsigned long map, int on)
+				   u64 map, int on)
 {
 	int i;
 	struct smmu_as *as = c->as;
 	u32 val, offs, mask = SMMU_ASID_ENABLE(as->asid);
 	struct smmu_device *smmu = as->smmu;
+	unsigned long *bitmap = (unsigned long *)&map;
 
 	WARN_ON(!on && map);
 	if (on && !map)
@@ -380,12 +383,10 @@  static int __smmu_client_set_hwgrp(struct smmu_client *c,
 	if (!on)
 		map = smmu_client_hwgrp(c);
 
-	for_each_set_bit(i, &map, HWGRP_COUNT) {
+	for_each_set_bit(i, bitmap, sizeof(map) * BITS_PER_BYTE) {
 		offs = HWGRP_ASID_REG(i);
 		val = smmu_read(smmu, offs);
 		if (on) {
-			if (WARN_ON(val & mask))
-				goto err_hw_busy;
 			val |= mask;
 		} else {
 			WARN_ON((val & mask) == mask);
@@ -396,15 +397,6 @@  static int __smmu_client_set_hwgrp(struct smmu_client *c,
 	FLUSH_SMMU_REGS(smmu);
 	c->hwgrp = map;
 	return 0;
-
-err_hw_busy:
-	for_each_set_bit(i, &map, HWGRP_COUNT) {
-		offs = HWGRP_ASID_REG(i);
-		val = smmu_read(smmu, offs);
-		val &= ~mask;
-		smmu_write(smmu, val, offs);
-	}
-	return -EBUSY;
 }
 
 static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
@@ -776,7 +768,7 @@  static int smmu_iommu_attach_dev(struct iommu_domain *domain,
 	struct smmu_as *as = domain->priv;
 	struct smmu_device *smmu = as->smmu;
 	struct smmu_client *client, *c;
-	u32 map;
+	u64 map;
 	int err;
 
 	client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL);
@@ -784,7 +776,7 @@  static int smmu_iommu_attach_dev(struct iommu_domain *domain,
 		return -ENOMEM;
 	client->dev = dev;
 	client->as = as;
-	map = (unsigned long)dev->platform_data;
+	map = smmu->swgroups;
 	if (!map)
 		return -EINVAL;
 
@@ -1191,6 +1183,7 @@  static int tegra_smmu_probe(struct platform_device *pdev)
 	int i, asids, err = 0;
 	dma_addr_t uninitialized_var(base);
 	size_t bytes, uninitialized_var(size);
+	u64 swgroups;
 
 	if (smmu_handle)
 		return -EIO;
@@ -1200,6 +1193,9 @@  static int tegra_smmu_probe(struct platform_device *pdev)
 	if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
 		return -ENODEV;
 
+	if (of_property_read_u64(dev->of_node, "nvidia,swgroups", &swgroups))
+		return -ENODEV;
+
 	bytes = sizeof(*smmu) + asids * (sizeof(*smmu->as) +
 					 sizeof(struct dma_iommu_mapping *));
 	smmu = devm_kzalloc(dev, bytes, GFP_KERNEL);
@@ -1246,6 +1242,7 @@  static int tegra_smmu_probe(struct platform_device *pdev)
 	smmu->num_as = asids;
 	smmu->iovmm_base = base;
 	smmu->page_count = size;
+	smmu->swgroups = swgroups;
 
 	smmu->translation_enable_0 = ~0;
 	smmu->translation_enable_1 = ~0;