diff mbox

[PATCHv4,2/7] driver/core: Populate IOMMU'able devices in order

Message ID 1384158718-4756-3-git-send-email-hdoyu@nvidia.com (mailing list archive)
State New, archived
Headers show

Commit Message

Hiroshi DOYU Nov. 11, 2013, 8:31 a.m. UTC
An "IOMMU device" on the bus is poplulated first, "IOMMU'able devices"
are done later.

With CONFIG_OF_IOMMU, "#stream-id-cells" DT binding would be used to
identify whether a device is IOMMU'able or not. If a device is
IOMMU'able, we'll defer to populate that device till an iommu device
is populated. Once an iommu device is populated, "dev->bus->iommu_ops"
is set in the bus. Then, those defered IOMMU'able devices are
populated and configured as IOMMU'abled with help of the already
populated iommu device via iommu_ops->add_device().

Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
Update:
This is newly added, and the successor of the following RFC:
  [RFC][PATCHv3+ 1/2] driver/core: Add of_iommu_attach()
  http://lists.linuxfoundation.org/pipermail/iommu/2013-November/006914.html
---
 drivers/base/dd.c        |  5 +++++
 drivers/iommu/of_iommu.c | 33 +++++++++++++++++++++++++++++++++
 include/linux/of_iommu.h |  7 +++++++
 3 files changed, 45 insertions(+)

Comments

Will Deacon Nov. 11, 2013, 11:39 a.m. UTC | #1
On Mon, Nov 11, 2013 at 08:31:53AM +0000, Hiroshi Doyu wrote:
> An "IOMMU device" on the bus is poplulated first, "IOMMU'able devices"
> are done later.
> 
> With CONFIG_OF_IOMMU, "#stream-id-cells" DT binding would be used to
> identify whether a device is IOMMU'able or not. If a device is
> IOMMU'able, we'll defer to populate that device till an iommu device
> is populated. Once an iommu device is populated, "dev->bus->iommu_ops"
> is set in the bus. Then, those defered IOMMU'able devices are
> populated and configured as IOMMU'abled with help of the already
> populated iommu device via iommu_ops->add_device().
> 
> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
> ---
> Update:
> This is newly added, and the successor of the following RFC:
>   [RFC][PATCHv3+ 1/2] driver/core: Add of_iommu_attach()
>   http://lists.linuxfoundation.org/pipermail/iommu/2013-November/006914.html

This generally looks like the right idea to me, but it would be good to have
the input from a DT maintainer on the use of "#stream-id-cells" as an indicator
that a device is behind an IOMMU. (aside: I think "iommuable" is a horrible
word!).

What happens if you do the deferring at the bus level? E.g. defer all device
probes on a bus, until the IOMMU is probed for that bus. That might fit
better with future work, where we will almost certainly need to expose more
of the bus topology to Linux. Of course, I can see that falling down for
monolithic virtual buses like the platform bus.

Will
Stephen Warren Nov. 12, 2013, 11:30 p.m. UTC | #2
On 11/11/2013 04:39 AM, Will Deacon wrote:
> On Mon, Nov 11, 2013 at 08:31:53AM +0000, Hiroshi Doyu wrote:
>> An "IOMMU device" on the bus is poplulated first, "IOMMU'able devices"
>> are done later.
>>
>> With CONFIG_OF_IOMMU, "#stream-id-cells" DT binding would be used to
>> identify whether a device is IOMMU'able or not. If a device is
>> IOMMU'able, we'll defer to populate that device till an iommu device
>> is populated. Once an iommu device is populated, "dev->bus->iommu_ops"
>> is set in the bus. Then, those defered IOMMU'able devices are
>> populated and configured as IOMMU'abled with help of the already
>> populated iommu device via iommu_ops->add_device().
>>
>> Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
>> ---
>> Update:
>> This is newly added, and the successor of the following RFC:
>>   [RFC][PATCHv3+ 1/2] driver/core: Add of_iommu_attach()
>>   http://lists.linuxfoundation.org/pipermail/iommu/2013-November/006914.html
> 
> This generally looks like the right idea to me, but it would be good to have
> the input from a DT maintainer on the use of "#stream-id-cells" as an indicator
> that a device is behind an IOMMU. (aside: I think "iommuable" is a horrible
> word!).
> 
> What happens if you do the deferring at the bus level? E.g. defer all device
> probes on a bus, until the IOMMU is probed for that bus. That might fit
> better with future work, where we will almost certainly need to expose more
> of the bus topology to Linux. Of course, I can see that falling down for
> monolithic virtual buses like the platform bus.

I don't think it's correct to think about "the IOMMU for the bus".

There could easily be multiple different IOMMU slave-sides attached to a
bus, and hence you'd need to defer probing until "all the IOMMs for the
bus" to be available.

Equally, I assume that dev->bus->iommu_ops rather assumes that bus
masters always master transactions onto the same bus that their control
registers are slaves upon. That also doesn't seem like a reasonable
assumption.

As such, I think an approach where each device waits for any IOMMUs that
affect it (wherever/whatever and however many they may be) is better
than one where we try to explicitly manage the probe order of devices
based on their slave registers' location.
Stephen Warren Nov. 12, 2013, 11:34 p.m. UTC | #3
On 11/11/2013 01:31 AM, Hiroshi Doyu wrote:
> An "IOMMU device" on the bus is poplulated first, "IOMMU'able devices"
> are done later.
> 
> With CONFIG_OF_IOMMU, "#stream-id-cells" DT binding would be used to
> identify whether a device is IOMMU'able or not. If a device is
> IOMMU'able, we'll defer to populate that device till an iommu device
> is populated. Once an iommu device is populated, "dev->bus->iommu_ops"
> is set in the bus. Then, those defered IOMMU'able devices are
> populated and configured as IOMMU'abled with help of the already
> populated iommu device via iommu_ops->add_device().

This looks fairly neat and clean.

I'm still worried about using #stream-id-cells in DT nodes though. While
I do understand that the *Linux* device model currently only allows each
struct device to be affected by a single IOMMU, I worry that encoding
that same restriction into DT is a mistake. I'd far rather see a
property like:

SMMU:
    smmu: smmu@xxxxxx {
        #smmu-cells = <1>;
    }

Affected device:
    smmus = <&smmu 1>;
    (perhaps with smmu-names too)

That would allow the DT to represent basically arbitrary HW configurations.

The implementation of this patch would then be almost as trivial; you'd
just need to walk the smmus property to find each phandle in turn, just
like any other phandle+specifier property, and validate that the SMMU
driver was already probe()d for each.
Hiroshi DOYU Nov. 13, 2013, 7:23 a.m. UTC | #4
On Wed, 13 Nov 2013 00:34:20 +0100
Stephen Warren <swarren@wwwdotorg.org> wrote:

> On 11/11/2013 01:31 AM, Hiroshi Doyu wrote:
> > An "IOMMU device" on the bus is poplulated first, "IOMMU'able devices"
> > are done later.
> > 
> > With CONFIG_OF_IOMMU, "#stream-id-cells" DT binding would be used to
> > identify whether a device is IOMMU'able or not. If a device is
> > IOMMU'able, we'll defer to populate that device till an iommu device
> > is populated. Once an iommu device is populated, "dev->bus->iommu_ops"
> > is set in the bus. Then, those defered IOMMU'able devices are
> > populated and configured as IOMMU'abled with help of the already
> > populated iommu device via iommu_ops->add_device().
> 
> This looks fairly neat and clean.
> 
> I'm still worried about using #stream-id-cells in DT nodes though. While
> I do understand that the *Linux* device model currently only allows each
> struct device to be affected by a single IOMMU, I worry that encoding
> that same restriction into DT is a mistake. I'd far rather see a
> property like:
> 
> SMMU:
>     smmu: smmu@xxxxxx {
>         #smmu-cells = <1>;
>     }
> 
> Affected device:
>     smmus = <&smmu 1>;
>     (perhaps with smmu-names too)
> 
> That would allow the DT to represent basically arbitrary HW configurations.

True, and also can solve multi IOMMU problem as well.

> The implementation of this patch would then be almost as trivial; you'd
> just need to walk the smmus property to find each phandle in turn, just
> like any other phandle+specifier property, and validate that the SMMU
> driver was already probe()d for each.

This seems to be almost same as the previous v3 DT bindings, and if we
introduce 64 bitmap newly, this DT bindings would be something like
below:

   smmu: iommu@xxxxxx {
       #smmu-cells = <2>;
       ......
   };

   host1x {
           compatible = "nvidia,tegra30-host1x", "simple-bus";
           nvidia,memory-clients = <&smmu 0x??????? 0x???????>;
           ....
           gr3d {
                   compatible = "nvidia,tegra30-gr3d";
                   nvidia,memory-clients = <&smmu 0x??????? 0x???????>;
           }

If a device is attached to multiple IOMMU H/Ws,

           gr3d {
                   compatible = "nvidia,tegra30-gr3d";
                   nvidia,memory-clients = <&smmu 0x??????? 0x??????? &gart 0x???????>;
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Then, the problem is the binding "name" and its "scope". This original
patch works with "#stream-id-cells" in driver core because I assumed
that "#stream-id-cells" can indicate globally that a device can be an
IOMMU master.

We may be able to have some kind of callback function which checks
"#stream-id-cells" *in* SMMU driver, but at least this function needs to
be registered in the bus at very early stage, iommu_ops->is_iommu_master().
But this cannot be done with bus->iommu_ops since bus->iommu_ops is set
after IOMMU is populated. A kind of Chikin or the egg problem.

Having a global bindings which indicates a device's IOMMU
master'ability is quite convenient. For example, "iommu" and
"#iommu-cells" without refering any local data. Then the above
DT would be:

   smmu: iommu@xxxxxx {
       #iommu-cells = <2>;
       ^^^^^^^^^^^^^^^^^^
   };

   host1x {
           compatible = "nvidia,tegra30-host1x", "simple-bus";
           iommu = <&smmu 0x??????? 0x???????>;
	   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
           gr3d {
                   compatible = "nvidia,tegra30-gr3d";
                   iommu = <&smmu 0x??????? 0x???????>;
           }

What do you think to have a global IOMMU DT bindings?
Will Deacon Nov. 13, 2013, 2:38 p.m. UTC | #5
On Tue, Nov 12, 2013 at 11:34:20PM +0000, Stephen Warren wrote:
> On 11/11/2013 01:31 AM, Hiroshi Doyu wrote:
> > An "IOMMU device" on the bus is poplulated first, "IOMMU'able devices"
> > are done later.
> > 
> > With CONFIG_OF_IOMMU, "#stream-id-cells" DT binding would be used to
> > identify whether a device is IOMMU'able or not. If a device is
> > IOMMU'able, we'll defer to populate that device till an iommu device
> > is populated. Once an iommu device is populated, "dev->bus->iommu_ops"
> > is set in the bus. Then, those defered IOMMU'able devices are
> > populated and configured as IOMMU'abled with help of the already
> > populated iommu device via iommu_ops->add_device().
> 
> This looks fairly neat and clean.
> 
> I'm still worried about using #stream-id-cells in DT nodes though. While
> I do understand that the *Linux* device model currently only allows each
> struct device to be affected by a single IOMMU, I worry that encoding
> that same restriction into DT is a mistake. I'd far rather see a
> property like:
> 
> SMMU:
>     smmu: smmu@xxxxxx {
>         #smmu-cells = <1>;
>     }
> 
> Affected device:
>     smmus = <&smmu 1>;
>     (perhaps with smmu-names too)
> 
> That would allow the DT to represent basically arbitrary HW configurations.
> 
> The implementation of this patch would then be almost as trivial; you'd
> just need to walk the smmus property to find each phandle in turn, just
> like any other phandle+specifier property, and validate that the SMMU
> driver was already probe()d for each.

There are a few problems with that:

  1.) It assumes all devices sharing an SMMU have the same number of
      "smmu cells"

  2.) It moves SMMU-specific data out to the device, which makes it
      impossible to describe more complicated topologies where IDs can be
      remapped/remastered, potentially by multiple SMMUs and/or bus bridges.

When writing the binding for the ARM SMMU driver, I originally started with
something similar to what you're suggesting, but was later forced down a
different route when I realised what sort of systems were being built.

We will have similar problems for PCIe RIDs and GIC DIDs (I spoke about this
at the ARM mini-summit). They are not fixed across the system: they
originate from a device, but can change as they traverse the system
topology.

Will
Hiroshi DOYU Nov. 13, 2013, 4:06 p.m. UTC | #6
Will Deacon <will.deacon@arm.com> wrote @ Wed, 13 Nov 2013 15:38:04 +0100:

> On Tue, Nov 12, 2013 at 11:34:20PM +0000, Stephen Warren wrote:
> > On 11/11/2013 01:31 AM, Hiroshi Doyu wrote:
> > > An "IOMMU device" on the bus is poplulated first, "IOMMU'able devices"
> > > are done later.
> > > 
> > > With CONFIG_OF_IOMMU, "#stream-id-cells" DT binding would be used to
> > > identify whether a device is IOMMU'able or not. If a device is
> > > IOMMU'able, we'll defer to populate that device till an iommu device
> > > is populated. Once an iommu device is populated, "dev->bus->iommu_ops"
> > > is set in the bus. Then, those defered IOMMU'able devices are
> > > populated and configured as IOMMU'abled with help of the already
> > > populated iommu device via iommu_ops->add_device().
> > 
> > This looks fairly neat and clean.
> > 
> > I'm still worried about using #stream-id-cells in DT nodes though. While
> > I do understand that the *Linux* device model currently only allows each
> > struct device to be affected by a single IOMMU, I worry that encoding
> > that same restriction into DT is a mistake. I'd far rather see a
> > property like:
> > 
> > SMMU:
> >     smmu: smmu@xxxxxx {
> >         #smmu-cells = <1>;
> >     }
> > 
> > Affected device:
> >     smmus = <&smmu 1>;
> >     (perhaps with smmu-names too)
> > 
> > That would allow the DT to represent basically arbitrary HW configurations.
> > 
> > The implementation of this patch would then be almost as trivial; you'd
> > just need to walk the smmus property to find each phandle in turn, just
> > like any other phandle+specifier property, and validate that the SMMU
> > driver was already probe()d for each.
> 
> There are a few problems with that:
> 
>   1.) It assumes all devices sharing an SMMU have the same number of
>       "smmu cells"

This can be solved with introducing the fixed size of bitmap. The size
of bitmap can be fixed even per SoC. In tegra we used 64(2 cells)
which I expect at most.

>   2.) It moves SMMU-specific data out to the device, which makes it
>       impossible to describe more complicated topologies where IDs can be
>       remapped/remastered, potentially by multiple SMMUs and/or bus bridges.
> 
> When writing the binding for the ARM SMMU driver, I originally started with
> something similar to what you're suggesting, but was later forced down a
> different route when I realised what sort of systems were being built.
> 
> We will have similar problems for PCIe RIDs and GIC DIDs (I spoke about this
> at the ARM mini-summit). They are not fixed across the system: they
> originate from a device, but can change as they traverse the system
> topology.

Is there any chance to overwrite SMMU driver specific params during
setting up topologies?
Will Deacon Nov. 13, 2013, 5:31 p.m. UTC | #7
On Wed, Nov 13, 2013 at 04:06:10PM +0000, Hiroshi Doyu wrote:
> Will Deacon <will.deacon@arm.com> wrote @ Wed, 13 Nov 2013 15:38:04 +0100:
> 
> > On Tue, Nov 12, 2013 at 11:34:20PM +0000, Stephen Warren wrote:
> > > SMMU:
> > >     smmu: smmu@xxxxxx {
> > >         #smmu-cells = <1>;
> > >     }
> > > 
> > > Affected device:
> > >     smmus = <&smmu 1>;
> > >     (perhaps with smmu-names too)
> > > 
> > > That would allow the DT to represent basically arbitrary HW configurations.
> > > 
> > > The implementation of this patch would then be almost as trivial; you'd
> > > just need to walk the smmus property to find each phandle in turn, just
> > > like any other phandle+specifier property, and validate that the SMMU
> > > driver was already probe()d for each.
> > 
> > There are a few problems with that:
> > 
> >   1.) It assumes all devices sharing an SMMU have the same number of
> >       "smmu cells"
> 
> This can be solved with introducing the fixed size of bitmap. The size
> of bitmap can be fixed even per SoC. In tegra we used 64(2 cells)
> which I expect at most.

That really doesn't sound like a good idea where you have bridges (like a
PCIe host controller) which could have a significant chunk of StreamID
space. You'd also need to pad everything out with some dummy IDs for parsing
purposes. Yuck!

> >   2.) It moves SMMU-specific data out to the device, which makes it
> >       impossible to describe more complicated topologies where IDs can be
> >       remapped/remastered, potentially by multiple SMMUs and/or bus bridges.
> > 
> > When writing the binding for the ARM SMMU driver, I originally started with
> > something similar to what you're suggesting, but was later forced down a
> > different route when I realised what sort of systems were being built.
> > 
> > We will have similar problems for PCIe RIDs and GIC DIDs (I spoke about this
> > at the ARM mini-summit). They are not fixed across the system: they
> > originate from a device, but can change as they traverse the system
> > topology.
> 
> Is there any chance to overwrite SMMU driver specific params during
> setting up topologies?

Not sure I understand what you're getting at here. Could you elaborate
please?

Will
Stephen Warren Nov. 13, 2013, 5:45 p.m. UTC | #8
On 11/13/2013 07:38 AM, Will Deacon wrote:
> On Tue, Nov 12, 2013 at 11:34:20PM +0000, Stephen Warren wrote:
>> On 11/11/2013 01:31 AM, Hiroshi Doyu wrote:
>>> An "IOMMU device" on the bus is poplulated first, "IOMMU'able devices"
>>> are done later.
>>>
>>> With CONFIG_OF_IOMMU, "#stream-id-cells" DT binding would be used to
>>> identify whether a device is IOMMU'able or not. If a device is
>>> IOMMU'able, we'll defer to populate that device till an iommu device
>>> is populated. Once an iommu device is populated, "dev->bus->iommu_ops"
>>> is set in the bus. Then, those defered IOMMU'able devices are
>>> populated and configured as IOMMU'abled with help of the already
>>> populated iommu device via iommu_ops->add_device().
>>
>> This looks fairly neat and clean.
>>
>> I'm still worried about using #stream-id-cells in DT nodes though. While
>> I do understand that the *Linux* device model currently only allows each
>> struct device to be affected by a single IOMMU, I worry that encoding
>> that same restriction into DT is a mistake. I'd far rather see a
>> property like:
>>
>> SMMU:
>>     smmu: smmu@xxxxxx {
>>         #smmu-cells = <1>;
>>     }
>>
>> Affected device:
>>     smmus = <&smmu 1>;
>>     (perhaps with smmu-names too)
>>
>> That would allow the DT to represent basically arbitrary HW configurations.
>>
>> The implementation of this patch would then be almost as trivial; you'd
>> just need to walk the smmus property to find each phandle in turn, just
>> like any other phandle+specifier property, and validate that the SMMU
>> driver was already probe()d for each.
> 
> There are a few problems with that:
> 
>   1.) It assumes all devices sharing an SMMU have the same number of
>       "smmu cells"

The SMMU HW defines how many cells are required to represent the client
stream IDs. So, this isn't a problem.

Are you thinking of cases where an SMMU client issues transactions with
multiple different stream IDs? That is supported by having multiple
entries in the smmus property.

(Assuming that #smmu-cells in the SMMU is <1>)

HW that issues with 1 stream ID:

	smmus = <&smmu 123>;

HW that issues with 2 stream IDs:

	smmus = <&smmu 123 &smmu 345>;

>   2.) It moves SMMU-specific data out to the device, which makes it

Yes, but I think it's really SMMU-client-specific data not
SMMU-specific. The SMMU doesn't dictate the stream IDs that "clients"
include with their transactions; the "client" HW dictates that.

>       impossible to describe more complicated topologies where IDs can be
>       remapped/remastered, potentially by multiple SMMUs and/or bus bridges.

I don't think so.

The SMMU "clients" can indicate what stream IDs they use to issue
transactions.

The SMMU DT node or driver itself can still include a table that
describes how it re-writes those stream IDs when forwarding transactions
to the next step. I don't believe there's any requirement that the SMMU
list all its clients and this mapping table in the same property. So,
the SMMU could easily have:

(entries are this SMMU's #stream-id-cells, assumed to be 1 here, then
the next SMMU's #stream-id-cells, assumed to be 2 here)

	smmu-stream-id-translations =
		<123 1 987>,
		<345 0 765>;

> When writing the binding for the ARM SMMU driver, I originally started with
> something similar to what you're suggesting, but was later forced down a
> different route when I realised what sort of systems were being built.
> 
> We will have similar problems for PCIe RIDs and GIC DIDs (I spoke about this
> at the ARM mini-summit). They are not fixed across the system: they
> originate from a device, but can change as they traverse the system
> topology.
Stephen Warren Nov. 13, 2013, 5:49 p.m. UTC | #9
On 11/13/2013 12:23 AM, Hiroshi Doyu wrote:
> On Wed, 13 Nov 2013 00:34:20 +0100
> Stephen Warren <swarren@wwwdotorg.org> wrote:
> 
>> On 11/11/2013 01:31 AM, Hiroshi Doyu wrote:
>>> An "IOMMU device" on the bus is poplulated first, "IOMMU'able devices"
>>> are done later.
>>>
>>> With CONFIG_OF_IOMMU, "#stream-id-cells" DT binding would be used to
>>> identify whether a device is IOMMU'able or not. If a device is
>>> IOMMU'able, we'll defer to populate that device till an iommu device
>>> is populated. Once an iommu device is populated, "dev->bus->iommu_ops"
>>> is set in the bus. Then, those defered IOMMU'able devices are
>>> populated and configured as IOMMU'abled with help of the already
>>> populated iommu device via iommu_ops->add_device().
>>
>> This looks fairly neat and clean.
>>
>> I'm still worried about using #stream-id-cells in DT nodes though. While
>> I do understand that the *Linux* device model currently only allows each
>> struct device to be affected by a single IOMMU, I worry that encoding
>> that same restriction into DT is a mistake. I'd far rather see a
>> property like:
>>
>> SMMU:
>>     smmu: smmu@xxxxxx {
>>         #smmu-cells = <1>;
>>     }
>>
>> Affected device:
>>     smmus = <&smmu 1>;
>>     (perhaps with smmu-names too)
>>
>> That would allow the DT to represent basically arbitrary HW configurations.
> 
> True, and also can solve multi IOMMU problem as well.
> 
>> The implementation of this patch would then be almost as trivial; you'd
>> just need to walk the smmus property to find each phandle in turn, just
>> like any other phandle+specifier property, and validate that the SMMU
>> driver was already probe()d for each.
> 
> This seems to be almost same as the previous v3 DT bindings, and if we
> introduce 64 bitmap newly, this DT bindings would be something like
> below:
> 
>    smmu: iommu@xxxxxx {
>        #smmu-cells = <2>;
>        ......
>    };
> 
>    host1x {
>            compatible = "nvidia,tegra30-host1x", "simple-bus";
>            nvidia,memory-clients = <&smmu 0x??????? 0x???????>;
>            ....
>            gr3d {
>                    compatible = "nvidia,tegra30-gr3d";
>                    nvidia,memory-clients = <&smmu 0x??????? 0x???????>;
>            }
> 
> If a device is attached to multiple IOMMU H/Ws,
> 
>            gr3d {
>                    compatible = "nvidia,tegra30-gr3d";
>                    nvidia,memory-clients = <&smmu 0x??????? 0x??????? &gart 0x???????>;
>                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> Then, the problem is the binding "name" and its "scope". This original
> patch works with "#stream-id-cells" in driver core because I assumed
> that "#stream-id-cells" can indicate globally that a device can be an
> IOMMU master.

For example, the pinctrl bindings have the same issue, since they're
interpreted "globally", and by (code called from) the generic device
probing code.

We simply decided that the properties "pinctrl-names" and "pinctrl-n"
(n=0...) were globally defined by the pinctrl subsystem, and hence could
be parsed in any node.

We could do the same with "smmus" and "smmu-names" in this case.

> We may be able to have some kind of callback function which checks
> "#stream-id-cells" *in* SMMU driver, but at least this function needs to
> be registered in the bus at very early stage, iommu_ops->is_iommu_master().
> But this cannot be done with bus->iommu_ops since bus->iommu_ops is set
> after IOMMU is populated. A kind of Chikin or the egg problem.

I think this is simply the normal deferred probe.

When device X attempts to probe, the core SMMU code (called from the
core device probing code) iterates over the smmus property. If any of
the phandles listed there don't have a registered SMMU driver, then
defer probe of device X. Eventually, the SMMU driver will appear, and
the driver core will attempt to re-probe device X, and all the SMMUs
have devices probed already, and everything will work.
Stephen Warren Nov. 13, 2013, 5:53 p.m. UTC | #10
On 11/13/2013 10:31 AM, Will Deacon wrote:
> On Wed, Nov 13, 2013 at 04:06:10PM +0000, Hiroshi Doyu wrote:
>> Will Deacon <will.deacon@arm.com> wrote @ Wed, 13 Nov 2013 15:38:04 +0100:
>>
>>> On Tue, Nov 12, 2013 at 11:34:20PM +0000, Stephen Warren wrote:
>>>> SMMU:
>>>>     smmu: smmu@xxxxxx {
>>>>         #smmu-cells = <1>;
>>>>     }
>>>>
>>>> Affected device:
>>>>     smmus = <&smmu 1>;
>>>>     (perhaps with smmu-names too)
>>>>
>>>> That would allow the DT to represent basically arbitrary HW configurations.
>>>>
>>>> The implementation of this patch would then be almost as trivial; you'd
>>>> just need to walk the smmus property to find each phandle in turn, just
>>>> like any other phandle+specifier property, and validate that the SMMU
>>>> driver was already probe()d for each.
>>>
>>> There are a few problems with that:
>>>
>>>   1.) It assumes all devices sharing an SMMU have the same number of
>>>       "smmu cells"
>>
>> This can be solved with introducing the fixed size of bitmap. The size
>> of bitmap can be fixed even per SoC. In tegra we used 64(2 cells)
>> which I expect at most.
> 
> That really doesn't sound like a good idea where you have bridges (like a
> PCIe host controller) which could have a significant chunk of StreamID
> space. You'd also need to pad everything out with some dummy IDs for parsing
> purposes. Yuck!

Can't you solve this by having the SMMU include a stream ID mapping
table. In the case of stream IDs having a large "address" space, then
just define the mapping table syntax to allow easy specification of
ranges using start/length, start/end, or value/mask pairs. Similar to
ranges or PCI's interrupt-map{,-mask}.
Will Deacon Nov. 14, 2013, 4:16 p.m. UTC | #11
On Wed, Nov 13, 2013 at 05:53:36PM +0000, Stephen Warren wrote:
> On 11/13/2013 10:31 AM, Will Deacon wrote:
> > On Wed, Nov 13, 2013 at 04:06:10PM +0000, Hiroshi Doyu wrote:
> >> This can be solved with introducing the fixed size of bitmap. The size
> >> of bitmap can be fixed even per SoC. In tegra we used 64(2 cells)
> >> which I expect at most.
> > 
> > That really doesn't sound like a good idea where you have bridges (like a
> > PCIe host controller) which could have a significant chunk of StreamID
> > space. You'd also need to pad everything out with some dummy IDs for parsing
> > purposes. Yuck!
> 
> Can't you solve this by having the SMMU include a stream ID mapping
> table. In the case of stream IDs having a large "address" space, then
> just define the mapping table syntax to allow easy specification of
> ranges using start/length, start/end, or value/mask pairs. Similar to
> ranges or PCI's interrupt-map{,-mask}.

That may work for windows, but the mapping from input stream IDs to output
IDs can be arbitrary (I *really* hope people stick to windows for requester
IDs though).

Will
diff mbox

Patch

diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 35fa368..6e892d4 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -25,6 +25,7 @@ 
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
 #include <linux/pinctrl/devinfo.h>
+#include <linux/of_iommu.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -273,6 +274,10 @@  static int really_probe(struct device *dev, struct device_driver *drv)
 
 	dev->driver = drv;
 
+	ret = of_iommu_attach(dev);
+	if (ret)
+		goto probe_failed;
+
 	/* If using pinctrl, bind pins now before probing */
 	ret = pinctrl_bind_pins(dev);
 	if (ret)
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index ee249bc..335bf6a 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -20,6 +20,8 @@ 
 #include <linux/export.h>
 #include <linux/limits.h>
 #include <linux/of.h>
+#include <linux/device.h>
+#include <linux/iommu.h>
 
 /**
  * of_get_dma_window - Parse *dma-window property and returns 0 if found.
@@ -88,3 +90,34 @@  int of_get_dma_window(struct device_node *dn, const char *prefix, int index,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(of_get_dma_window);
+
+static bool of_is_iommuable(struct device *dev)
+{
+	size_t bytes;
+	const __be32 *prop;
+	const char *propname = "#stream-id-cells";
+
+	prop = of_get_property(dev->of_node, propname, &bytes);
+	if (!prop || !bytes)
+		return false;
+
+	pr_debug("%s=%d %s\n", propname, bytes, dev_name(dev));
+	return true;
+}
+
+int of_iommu_attach(struct device *dev)
+{
+	struct iommu_ops *ops;
+
+	if (!of_is_iommuable(dev))
+		return 0;
+
+	ops = dev->bus->iommu_ops;
+	if (!ops)
+		return -EPROBE_DEFER;
+
+	if (ops->add_device)
+		return ops->add_device(dev);
+
+	return 0;
+}
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index 51a560f..3457489 100644
--- a/include/linux/of_iommu.h
+++ b/include/linux/of_iommu.h
@@ -7,6 +7,8 @@  extern int of_get_dma_window(struct device_node *dn, const char *prefix,
 			     int index, unsigned long *busno, dma_addr_t *addr,
 			     size_t *size);
 
+extern int of_iommu_attach(struct device *dev);
+
 #else
 
 static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
@@ -16,6 +18,11 @@  static inline int of_get_dma_window(struct device_node *dn, const char *prefix,
 	return -EINVAL;
 }
 
+static inline int of_iommu_attach(struct device *dev)
+{
+	return 0;
+}
+
 #endif	/* CONFIG_OF_IOMMU */
 
 #endif /* __OF_IOMMU_H */