diff mbox

[V4,4/7] ARM64, ACPI, PCI: I/O Remapping Table (IORT) initial support.

Message ID 1459759975-24097-5-git-send-email-tn@semihalf.com (mailing list archive)
State New, archived
Headers show

Commit Message

Tomasz Nowicki April 4, 2016, 8:52 a.m. UTC
IORT shows representation of IO topology for ARM based systems.
It describes how various components are connected together on
parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.

Initial support allows to:
- register ITS MSI chip along with ITS translation ID and domain token
- deregister ITS MSI chip based on ITS translation ID
- find registered domain token based on ITS translation ID
- map MSI RID based on PCI device and requester ID
- find domain token based on PCI device and requester ID

To: Rafael J. Wysocki <rjw@rjwysocki.net>
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
---
 drivers/acpi/Kconfig    |   3 +
 drivers/acpi/Makefile   |   1 +
 drivers/acpi/iort.c     | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/irqchip/Kconfig |   1 +
 include/linux/iort.h    |  31 +++++
 5 files changed, 371 insertions(+)
 create mode 100644 drivers/acpi/iort.c
 create mode 100644 include/linux/iort.h

Comments

Marc Zyngier April 13, 2016, 3:23 p.m. UTC | #1
On 04/04/16 09:52, Tomasz Nowicki wrote:
> IORT shows representation of IO topology for ARM based systems.
> It describes how various components are connected together on
> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
> 
> Initial support allows to:
> - register ITS MSI chip along with ITS translation ID and domain token
> - deregister ITS MSI chip based on ITS translation ID
> - find registered domain token based on ITS translation ID
> - map MSI RID based on PCI device and requester ID
> - find domain token based on PCI device and requester ID
> 
> To: Rafael J. Wysocki <rjw@rjwysocki.net>
> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
> ---
>  drivers/acpi/Kconfig    |   3 +
>  drivers/acpi/Makefile   |   1 +
>  drivers/acpi/iort.c     | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/irqchip/Kconfig |   1 +
>  include/linux/iort.h    |  31 +++++
>  5 files changed, 371 insertions(+)
>  create mode 100644 drivers/acpi/iort.c
>  create mode 100644 include/linux/iort.h
> 

[...]

> +static acpi_status
> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
> +{
> +	struct acpi_iort_root_complex *pci_rc;
> +	struct device *dev = context;
> +	struct pci_bus *bus;
> +
> +	switch (node->type) {
> +	case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
> +		bus = to_pci_bus(dev);
> +		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
> +
> +		/*
> +		 * It is assumed that PCI segment numbers maps one-to-one
> +		 * with root complexes. Each segment number can represent only
> +		 * one root complex.
> +		 */
> +		if (pci_rc->pci_segment_number == pci_domain_nr(bus))
> +			return AE_OK;

What guarantees that this is ever valid? As far as I know, pci_domain_nr
is completely arbitrary, and depends both on the probe order and the
phase of the moon. If you want this to be reliable, you need to allocate
the domain number from pci_segment_number.

I must be missing something. Care to shed some light on this?

Thanks,

	M.
Tomasz Nowicki April 13, 2016, 3:36 p.m. UTC | #2
On 13.04.2016 17:23, Marc Zyngier wrote:
> On 04/04/16 09:52, Tomasz Nowicki wrote:
>> IORT shows representation of IO topology for ARM based systems.
>> It describes how various components are connected together on
>> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>>
>> Initial support allows to:
>> - register ITS MSI chip along with ITS translation ID and domain token
>> - deregister ITS MSI chip based on ITS translation ID
>> - find registered domain token based on ITS translation ID
>> - map MSI RID based on PCI device and requester ID
>> - find domain token based on PCI device and requester ID
>>
>> To: Rafael J. Wysocki <rjw@rjwysocki.net>
>> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
>> ---
>>   drivers/acpi/Kconfig    |   3 +
>>   drivers/acpi/Makefile   |   1 +
>>   drivers/acpi/iort.c     | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   drivers/irqchip/Kconfig |   1 +
>>   include/linux/iort.h    |  31 +++++
>>   5 files changed, 371 insertions(+)
>>   create mode 100644 drivers/acpi/iort.c
>>   create mode 100644 include/linux/iort.h
>>
>
> [...]
>
>> +static acpi_status
>> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
>> +{
>> +	struct acpi_iort_root_complex *pci_rc;
>> +	struct device *dev = context;
>> +	struct pci_bus *bus;
>> +
>> +	switch (node->type) {
>> +	case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
>> +		bus = to_pci_bus(dev);
>> +		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>> +
>> +		/*
>> +		 * It is assumed that PCI segment numbers maps one-to-one
>> +		 * with root complexes. Each segment number can represent only
>> +		 * one root complex.
>> +		 */
>> +		if (pci_rc->pci_segment_number == pci_domain_nr(bus))
>> +			return AE_OK;
>
> What guarantees that this is ever valid? As far as I know, pci_domain_nr
> is completely arbitrary, and depends both on the probe order and the
> phase of the moon. If you want this to be reliable, you need to allocate
> the domain number from pci_segment_number.
>
> I must be missing something. Care to shed some light on this?
>
Sure. Please see:
http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
3.1.1.5 PCI root complex node
PCI Segment number -> The PCI segment number, as in MCFG and as
returned by _SEG in the namespace.

So IORT spec states that pci_segment_number corresponds to the segment 
number from MCFG table and _SEG method. Here is my patch which makes 
sure pci_domain_nr(bus) is set properly:
https://lkml.org/lkml/2016/2/16/418

Tomasz
Marc Zyngier April 13, 2016, 3:52 p.m. UTC | #3
On 13/04/16 16:36, Tomasz Nowicki wrote:
> On 13.04.2016 17:23, Marc Zyngier wrote:
>> On 04/04/16 09:52, Tomasz Nowicki wrote:
>>> IORT shows representation of IO topology for ARM based systems.
>>> It describes how various components are connected together on
>>> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>>>
>>> Initial support allows to:
>>> - register ITS MSI chip along with ITS translation ID and domain token
>>> - deregister ITS MSI chip based on ITS translation ID
>>> - find registered domain token based on ITS translation ID
>>> - map MSI RID based on PCI device and requester ID
>>> - find domain token based on PCI device and requester ID
>>>
>>> To: Rafael J. Wysocki <rjw@rjwysocki.net>
>>> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
>>> ---
>>>   drivers/acpi/Kconfig    |   3 +
>>>   drivers/acpi/Makefile   |   1 +
>>>   drivers/acpi/iort.c     | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>   drivers/irqchip/Kconfig |   1 +
>>>   include/linux/iort.h    |  31 +++++
>>>   5 files changed, 371 insertions(+)
>>>   create mode 100644 drivers/acpi/iort.c
>>>   create mode 100644 include/linux/iort.h
>>>
>>
>> [...]
>>
>>> +static acpi_status
>>> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
>>> +{
>>> +	struct acpi_iort_root_complex *pci_rc;
>>> +	struct device *dev = context;
>>> +	struct pci_bus *bus;
>>> +
>>> +	switch (node->type) {
>>> +	case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
>>> +		bus = to_pci_bus(dev);
>>> +		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>> +
>>> +		/*
>>> +		 * It is assumed that PCI segment numbers maps one-to-one
>>> +		 * with root complexes. Each segment number can represent only
>>> +		 * one root complex.
>>> +		 */
>>> +		if (pci_rc->pci_segment_number == pci_domain_nr(bus))
>>> +			return AE_OK;
>>
>> What guarantees that this is ever valid? As far as I know, pci_domain_nr
>> is completely arbitrary, and depends both on the probe order and the
>> phase of the moon. If you want this to be reliable, you need to allocate
>> the domain number from pci_segment_number.
>>
>> I must be missing something. Care to shed some light on this?
>>
> Sure. Please see:
> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
> 3.1.1.5 PCI root complex node
> PCI Segment number -> The PCI segment number, as in MCFG and as
> returned by _SEG in the namespace.
> 
> So IORT spec states that pci_segment_number corresponds to the segment 
> number from MCFG table and _SEG method. Here is my patch which makes 
> sure pci_domain_nr(bus) is set properly:
> https://lkml.org/lkml/2016/2/16/418

Lovely. So this series is actually dependent on the PCI one. I guess we
need to solve that one first, because IORT seems pretty pointless if we
don't have PCI support. What's the plan?

	M.
Sinan Kaya April 13, 2016, 9:18 p.m. UTC | #4
On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>> > Sure. Please see:
>> > http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>> > 3.1.1.5 PCI root complex node
>> > PCI Segment number -> The PCI segment number, as in MCFG and as
>> > returned by _SEG in the namespace.
>> > 
>> > So IORT spec states that pci_segment_number corresponds to the segment 
>> > number from MCFG table and _SEG method. Here is my patch which makes 
>> > sure pci_domain_nr(bus) is set properly:
>> > https://lkml.org/lkml/2016/2/16/418
> Lovely. So this series is actually dependent on the PCI one. I guess we
> need to solve that one first, because IORT seems pretty pointless if we
> don't have PCI support. What's the plan?

Would it be OK to split the PCI specific section of the patch and continue
review? PCI is a user of the IORT table. Not the other way around. 

We shouldn't need a two way dependency.
Tomasz Nowicki April 14, 2016, 7:20 a.m. UTC | #5
On 13.04.2016 23:18, Sinan Kaya wrote:
> On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>>>> Sure. Please see:
>>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>>> 3.1.1.5 PCI root complex node
>>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>>> returned by _SEG in the namespace.
>>>>
>>>> So IORT spec states that pci_segment_number corresponds to the segment
>>>> number from MCFG table and _SEG method. Here is my patch which makes
>>>> sure pci_domain_nr(bus) is set properly:
>>>> https://lkml.org/lkml/2016/2/16/418
>> Lovely. So this series is actually dependent on the PCI one. I guess we
>> need to solve that one first, because IORT seems pretty pointless if we
>> don't have PCI support. What's the plan?
>
> Would it be OK to split the PCI specific section of the patch and continue
> review? PCI is a user of the IORT table. Not the other way around.

I need to disagree. What would be the use case for patches w/o "PCI part" ?

Tomasz
Marc Zyngier April 14, 2016, 7:36 a.m. UTC | #6
On 14/04/16 08:20, Tomasz Nowicki wrote:
> On 13.04.2016 23:18, Sinan Kaya wrote:
>> On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>>>>> Sure. Please see:
>>>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>>>> 3.1.1.5 PCI root complex node
>>>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>>>> returned by _SEG in the namespace.
>>>>>
>>>>> So IORT spec states that pci_segment_number corresponds to the segment
>>>>> number from MCFG table and _SEG method. Here is my patch which makes
>>>>> sure pci_domain_nr(bus) is set properly:
>>>>> https://lkml.org/lkml/2016/2/16/418
>>> Lovely. So this series is actually dependent on the PCI one. I guess we
>>> need to solve that one first, because IORT seems pretty pointless if we
>>> don't have PCI support. What's the plan?
>>
>> Would it be OK to split the PCI specific section of the patch and continue
>> review? PCI is a user of the IORT table. Not the other way around.
> 
> I need to disagree. What would be the use case for patches w/o "PCI part" ?

Quite. PCI (as a subsystem) doesn't need IORT at all, thank you very
much. GIC (implementing MSI) and SMMU (implementing DMA) do, by virtue
of RID/SID/DID being translated all over the place.

So by the look of it, the dependency chain is GIC+SMMU->IORT->PCI.

The GIC changes here are pretty mechanical, and not that interesting.
The stuff that needs sorting quickly is PCI, because all this work is
pointless if we don't have it.

At the risk of sounding like a stuck record: What's the plan?

Thanks,

	M.
Tomasz Nowicki April 14, 2016, 7:39 a.m. UTC | #7
On 13.04.2016 17:52, Marc Zyngier wrote:
> On 13/04/16 16:36, Tomasz Nowicki wrote:
>> On 13.04.2016 17:23, Marc Zyngier wrote:
>>> On 04/04/16 09:52, Tomasz Nowicki wrote:
>>>> IORT shows representation of IO topology for ARM based systems.
>>>> It describes how various components are connected together on
>>>> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>>>>
>>>> Initial support allows to:
>>>> - register ITS MSI chip along with ITS translation ID and domain token
>>>> - deregister ITS MSI chip based on ITS translation ID
>>>> - find registered domain token based on ITS translation ID
>>>> - map MSI RID based on PCI device and requester ID
>>>> - find domain token based on PCI device and requester ID
>>>>
>>>> To: Rafael J. Wysocki <rjw@rjwysocki.net>
>>>> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
>>>> ---
>>>>    drivers/acpi/Kconfig    |   3 +
>>>>    drivers/acpi/Makefile   |   1 +
>>>>    drivers/acpi/iort.c     | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>    drivers/irqchip/Kconfig |   1 +
>>>>    include/linux/iort.h    |  31 +++++
>>>>    5 files changed, 371 insertions(+)
>>>>    create mode 100644 drivers/acpi/iort.c
>>>>    create mode 100644 include/linux/iort.h
>>>>
>>>
>>> [...]
>>>
>>>> +static acpi_status
>>>> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
>>>> +{
>>>> +	struct acpi_iort_root_complex *pci_rc;
>>>> +	struct device *dev = context;
>>>> +	struct pci_bus *bus;
>>>> +
>>>> +	switch (node->type) {
>>>> +	case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
>>>> +		bus = to_pci_bus(dev);
>>>> +		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>>> +
>>>> +		/*
>>>> +		 * It is assumed that PCI segment numbers maps one-to-one
>>>> +		 * with root complexes. Each segment number can represent only
>>>> +		 * one root complex.
>>>> +		 */
>>>> +		if (pci_rc->pci_segment_number == pci_domain_nr(bus))
>>>> +			return AE_OK;
>>>
>>> What guarantees that this is ever valid? As far as I know, pci_domain_nr
>>> is completely arbitrary, and depends both on the probe order and the
>>> phase of the moon. If you want this to be reliable, you need to allocate
>>> the domain number from pci_segment_number.
>>>
>>> I must be missing something. Care to shed some light on this?
>>>
>> Sure. Please see:
>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>> 3.1.1.5 PCI root complex node
>> PCI Segment number -> The PCI segment number, as in MCFG and as
>> returned by _SEG in the namespace.
>>
>> So IORT spec states that pci_segment_number corresponds to the segment
>> number from MCFG table and _SEG method. Here is my patch which makes
>> sure pci_domain_nr(bus) is set properly:
>> https://lkml.org/lkml/2016/2/16/418
>
> Lovely. So this series is actually dependent on the PCI one. I guess we
> need to solve that one first, because IORT seems pretty pointless if we
> don't have PCI support. What's the plan?
>

The plan is to make this series ready for being merged. Once we get PCI 
series upstream, we can just retest ITS final series and pull it in, if 
you agree. PCI domain assignment is settled so it will not be the reason 
for fundamental changes here. What do you think?

Tomasz
Marc Zyngier April 14, 2016, 7:46 a.m. UTC | #8
On 14/04/16 08:39, Tomasz Nowicki wrote:
> On 13.04.2016 17:52, Marc Zyngier wrote:
>> On 13/04/16 16:36, Tomasz Nowicki wrote:
>>> On 13.04.2016 17:23, Marc Zyngier wrote:
>>>> On 04/04/16 09:52, Tomasz Nowicki wrote:
>>>>> IORT shows representation of IO topology for ARM based systems.
>>>>> It describes how various components are connected together on
>>>>> parent-child basis e.g. PCI RC -> SMMU -> ITS. Also see IORT spec.
>>>>>
>>>>> Initial support allows to:
>>>>> - register ITS MSI chip along with ITS translation ID and domain token
>>>>> - deregister ITS MSI chip based on ITS translation ID
>>>>> - find registered domain token based on ITS translation ID
>>>>> - map MSI RID based on PCI device and requester ID
>>>>> - find domain token based on PCI device and requester ID
>>>>>
>>>>> To: Rafael J. Wysocki <rjw@rjwysocki.net>
>>>>> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
>>>>> ---
>>>>>    drivers/acpi/Kconfig    |   3 +
>>>>>    drivers/acpi/Makefile   |   1 +
>>>>>    drivers/acpi/iort.c     | 335 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>    drivers/irqchip/Kconfig |   1 +
>>>>>    include/linux/iort.h    |  31 +++++
>>>>>    5 files changed, 371 insertions(+)
>>>>>    create mode 100644 drivers/acpi/iort.c
>>>>>    create mode 100644 include/linux/iort.h
>>>>>
>>>>
>>>> [...]
>>>>
>>>>> +static acpi_status
>>>>> +iort_find_dev_callback(struct acpi_iort_node *node, void *context)
>>>>> +{
>>>>> +	struct acpi_iort_root_complex *pci_rc;
>>>>> +	struct device *dev = context;
>>>>> +	struct pci_bus *bus;
>>>>> +
>>>>> +	switch (node->type) {
>>>>> +	case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
>>>>> +		bus = to_pci_bus(dev);
>>>>> +		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
>>>>> +
>>>>> +		/*
>>>>> +		 * It is assumed that PCI segment numbers maps one-to-one
>>>>> +		 * with root complexes. Each segment number can represent only
>>>>> +		 * one root complex.
>>>>> +		 */
>>>>> +		if (pci_rc->pci_segment_number == pci_domain_nr(bus))
>>>>> +			return AE_OK;
>>>>
>>>> What guarantees that this is ever valid? As far as I know, pci_domain_nr
>>>> is completely arbitrary, and depends both on the probe order and the
>>>> phase of the moon. If you want this to be reliable, you need to allocate
>>>> the domain number from pci_segment_number.
>>>>
>>>> I must be missing something. Care to shed some light on this?
>>>>
>>> Sure. Please see:
>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>> 3.1.1.5 PCI root complex node
>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>> returned by _SEG in the namespace.
>>>
>>> So IORT spec states that pci_segment_number corresponds to the segment
>>> number from MCFG table and _SEG method. Here is my patch which makes
>>> sure pci_domain_nr(bus) is set properly:
>>> https://lkml.org/lkml/2016/2/16/418
>>
>> Lovely. So this series is actually dependent on the PCI one. I guess we
>> need to solve that one first, because IORT seems pretty pointless if we
>> don't have PCI support. What's the plan?
>>
> 
> The plan is to make this series ready for being merged. Once we get PCI 
> series upstream, we can just retest ITS final series and pull it in, if 
> you agree. PCI domain assignment is settled so it will not be the reason 
> for fundamental changes here. What do you think?

As long as you are making progress on the PCI front, and that we
establish that PCI must go in first, I'm OK with that.

Thanks,

	M.
Sinan Kaya April 14, 2016, 11:37 a.m. UTC | #9
On 2016-04-14 03:36, Marc Zyngier wrote:
> On 14/04/16 08:20, Tomasz Nowicki wrote:
>> On 13.04.2016 23:18, Sinan Kaya wrote:
>>> On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>>>>>> Sure. Please see:
>>>>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>>>>> 3.1.1.5 PCI root complex node
>>>>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>>>>> returned by _SEG in the namespace.
>>>>>> 
>>>>>> So IORT spec states that pci_segment_number corresponds to the 
>>>>>> segment
>>>>>> number from MCFG table and _SEG method. Here is my patch which 
>>>>>> makes
>>>>>> sure pci_domain_nr(bus) is set properly:
>>>>>> https://lkml.org/lkml/2016/2/16/418
>>>> Lovely. So this series is actually dependent on the PCI one. I guess 
>>>> we
>>>> need to solve that one first, because IORT seems pretty pointless if 
>>>> we
>>>> don't have PCI support. What's the plan?
>>> 
>>> Would it be OK to split the PCI specific section of the patch and 
>>> continue
>>> review? PCI is a user of the IORT table. Not the other way around.
>> 
>> I need to disagree. What would be the use case for patches w/o "PCI 
>> part" ?
> 
> Quite. PCI (as a subsystem) doesn't need IORT at all, thank you very
> much. GIC (implementing MSI) and SMMU (implementing DMA) do, by virtue
> of RID/SID/DID being translated all over the place.
> 
> So by the look of it, the dependency chain is GIC+SMMU->IORT->PCI.
> 
> The GIC changes here are pretty mechanical, and not that interesting.
> The stuff that needs sorting quickly is PCI, because all this work is
> pointless if we don't have it.
> 
> At the risk of sounding like a stuck record: What's the plan?
> 
> Thanks,
> 
> 	M.

My answer is based on the spec definition. The spec defines named 
components for other peripherals that are behind iommu and can 
potentially implement msi.

You could have used a basic device like platform sata to take care of 
basic iort and smmu support.

You can then come back and implement PCIe support.
Marc Zyngier April 14, 2016, 11:48 a.m. UTC | #10
On 14/04/16 12:37, okaya@codeaurora.org wrote:
> On 2016-04-14 03:36, Marc Zyngier wrote:
>> On 14/04/16 08:20, Tomasz Nowicki wrote:
>>> On 13.04.2016 23:18, Sinan Kaya wrote:
>>>> On 4/13/2016 11:52 AM, Marc Zyngier wrote:
>>>>>>> Sure. Please see:
>>>>>>> http://infocenter.arm.com/help/topic/com.arm.doc.den0049a/DEN0049A_IO_Remapping_Table.pdf
>>>>>>> 3.1.1.5 PCI root complex node
>>>>>>> PCI Segment number -> The PCI segment number, as in MCFG and as
>>>>>>> returned by _SEG in the namespace.
>>>>>>>
>>>>>>> So IORT spec states that pci_segment_number corresponds to the 
>>>>>>> segment
>>>>>>> number from MCFG table and _SEG method. Here is my patch which 
>>>>>>> makes
>>>>>>> sure pci_domain_nr(bus) is set properly:
>>>>>>> https://lkml.org/lkml/2016/2/16/418
>>>>> Lovely. So this series is actually dependent on the PCI one. I guess 
>>>>> we
>>>>> need to solve that one first, because IORT seems pretty pointless if 
>>>>> we
>>>>> don't have PCI support. What's the plan?
>>>>
>>>> Would it be OK to split the PCI specific section of the patch and 
>>>> continue
>>>> review? PCI is a user of the IORT table. Not the other way around.
>>>
>>> I need to disagree. What would be the use case for patches w/o "PCI 
>>> part" ?
>>
>> Quite. PCI (as a subsystem) doesn't need IORT at all, thank you very
>> much. GIC (implementing MSI) and SMMU (implementing DMA) do, by virtue
>> of RID/SID/DID being translated all over the place.
>>
>> So by the look of it, the dependency chain is GIC+SMMU->IORT->PCI.
>>
>> The GIC changes here are pretty mechanical, and not that interesting.
>> The stuff that needs sorting quickly is PCI, because all this work is
>> pointless if we don't have it.
>>
>> At the risk of sounding like a stuck record: What's the plan?
>>
>> Thanks,
>>
>> 	M.
> 
> My answer is based on the spec definition. The spec defines named 
> components for other peripherals that are behind iommu and can 
> potentially implement msi.
> 
> You could have used a basic device like platform sata to take care of 
> basic iort and smmu support.
> 
> You can then come back and implement PCIe support.

I could. You could do it too. Thankfully, the dependency is dictated by
whoever is writing the code.

Thanks,

	M.
diff mbox

Patch

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee..183ffa3 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -57,6 +57,9 @@  config ACPI_SYSTEM_POWER_STATES_SUPPORT
 config ACPI_CCA_REQUIRED
 	bool
 
+config IORT_TABLE
+	bool
+
 config ACPI_DEBUGGER
 	bool "AML debugger interface"
 	select ACPI_DEBUG
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index cb648a4..7ea903d 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -80,6 +80,7 @@  obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
 obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
 obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o
+obj-$(CONFIG_IORT_TABLE) 	+= iort.o
 
 # processor has its own "processor." module_param namespace
 processor-y			:= processor_driver.o
diff --git a/drivers/acpi/iort.c b/drivers/acpi/iort.c
new file mode 100644
index 0000000..3119683
--- /dev/null
+++ b/drivers/acpi/iort.c
@@ -0,0 +1,335 @@ 
+/*
+ * Copyright (C) 2016, Semihalf
+ *	Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * This file implements early detection/parsing of I/O mapping
+ * reported to OS through firmware via I/O Remapping Table (IORT)
+ * IORT document number: ARM DEN 0049A
+ */
+
+#define pr_fmt(fmt)	"ACPI: IORT: " fmt
+
+#include <linux/export.h>
+#include <linux/iort.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+struct iort_its_msi_chip {
+	struct list_head	list;
+	struct fwnode_handle	*fw_node;
+	u32			translation_id;
+};
+
+typedef acpi_status (*iort_find_node_callback)
+	(struct acpi_iort_node *node, void *context);
+
+/* Root pointer to the mapped IORT table */
+static struct acpi_table_header *iort_table;
+
+static LIST_HEAD(iort_msi_chip_list);
+
+/**
+ * iort_register_domain_token() - register domain token and related ITS ID
+ * 				  to the list from where we can get it back
+ * 				  later on.
+ * @translation_id: ITS ID
+ * @token: domain token
+ *
+ * Returns: 0 on success, -ENOMEM if not memory when allocating list element.
+ */
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
+{
+	struct iort_its_msi_chip *its_msi_chip;
+
+	its_msi_chip = kzalloc(sizeof(*its_msi_chip), GFP_KERNEL);
+	if (!its_msi_chip)
+		return -ENOMEM;
+
+	its_msi_chip->fw_node = fw_node;
+	its_msi_chip->translation_id = trans_id;
+
+	list_add(&its_msi_chip->list, &iort_msi_chip_list);
+	return 0;
+}
+
+/**
+ * iort_unregister_domain_token() - unregister domain token based on ITS ID.
+ * @translation_id: ITS ID
+ *
+ * Returns: none.
+ */
+void iort_deregister_domain_token(int trans_id)
+{
+	struct iort_its_msi_chip *its_msi_chip, *t;
+
+	list_for_each_entry_safe(its_msi_chip, t, &iort_msi_chip_list, list) {
+		if (its_msi_chip->translation_id == trans_id) {
+			list_del(&its_msi_chip->list);
+			kfree(its_msi_chip);
+			break;
+		}
+	}
+}
+
+/**
+ * iort_find_its_domain_token() - find domain token based on given ITS ID.
+ * @translation_id: ITS ID
+ *
+ * Returns: domain token when find on the list, NULL otherwise.
+ */
+struct fwnode_handle *iort_its_find_domain_token(int trans_id)
+{
+	struct iort_its_msi_chip *its_msi_chip;
+
+	list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
+		if (its_msi_chip->translation_id == trans_id)
+			return its_msi_chip->fw_node;
+	}
+
+	return NULL;
+}
+
+static struct acpi_iort_node *
+iort_scan_node(enum acpi_iort_node_type type,
+	       iort_find_node_callback callback, void *context)
+{
+	struct acpi_iort_node *iort_node, *iort_end;
+	struct acpi_table_iort *iort;
+	int i;
+
+	if (!iort_table)
+		return NULL;
+
+	/*
+	 * iort_table and iort both point to the start of IORT table, but
+	 * have different struct types
+	 */
+	iort = (struct acpi_table_iort *)iort_table;
+
+	/* Get the first IORT node */
+	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
+				 iort->node_offset);
+	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				iort_table->length);
+
+	for (i = 0; i < iort->node_count; i++) {
+		if (iort_node >= iort_end) {
+			pr_err("iort node pointer overflows, bad table\n");
+			return NULL;
+		}
+
+		if (iort_node->type == type) {
+			if (ACPI_SUCCESS(callback(iort_node, context)))
+				return iort_node;
+		}
+
+		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
+					 iort_node->length);
+	}
+
+	return NULL;
+}
+
+static acpi_status
+iort_find_dev_callback(struct acpi_iort_node *node, void *context)
+{
+	struct acpi_iort_root_complex *pci_rc;
+	struct device *dev = context;
+	struct pci_bus *bus;
+
+	switch (node->type) {
+	case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
+		bus = to_pci_bus(dev);
+		pci_rc = (struct acpi_iort_root_complex *)node->node_data;
+
+		/*
+		 * It is assumed that PCI segment numbers maps one-to-one
+		 * with root complexes. Each segment number can represent only
+		 * one root complex.
+		 */
+		if (pci_rc->pci_segment_number == pci_domain_nr(bus))
+			return AE_OK;
+
+		break;
+	}
+
+	return AE_NOT_FOUND;
+}
+
+static struct acpi_iort_node *
+iort_dev_map_rid(struct acpi_iort_node *node, u32 rid_in,
+			    u32 *rid_out)
+{
+
+	if (!node)
+		goto out;
+
+	/* Go upstream */
+	while (node->type != ACPI_IORT_NODE_ITS_GROUP) {
+		struct acpi_iort_id_mapping *id;
+		int i, found = 0;
+
+		/* Exit when no mapping array */
+		if (!node->mapping_offset || !node->mapping_count)
+			return NULL;
+
+		id = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
+				  node->mapping_offset);
+
+		for (i = 0, found = 0; i < node->mapping_count; i++, id++) {
+			/*
+			 * Single mapping is not translation rule,
+			 * lets move on for this case
+			 */
+			if (id->flags & ACPI_IORT_ID_SINGLE_MAPPING)
+				continue;
+
+			if (rid_in < id->input_base ||
+			    (rid_in > id->input_base + id->id_count))
+				continue;
+
+			rid_in = id->output_base + (rid_in - id->input_base);
+			found = 1;
+			break;
+		}
+
+		if (!found)
+			return NULL;
+
+		/* Firmware bug! */
+		if (!id->output_reference) {
+			pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
+			       node, node->type);
+			return NULL;
+		}
+
+		node = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
+				    id->output_reference);
+	}
+
+out:
+	if (rid_out)
+		*rid_out = rid_in;
+	return node;
+}
+
+static struct acpi_iort_node *
+iort_its_find_node_and_map_rid(struct pci_dev *pdev, u32 req_id, u32 *dev_id)
+{
+	struct pci_bus *pbus = pdev->bus;
+	struct acpi_iort_node *node;
+
+	/* Find a PCI root bus */
+	while (!pci_is_root_bus(pbus))
+		pbus = pbus->parent;
+
+
+	node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
+			      iort_find_dev_callback, &pbus->dev);
+	if (!node) {
+		dev_err(&pdev->dev, "can't find related IORT node\n");
+		return NULL;
+	}
+
+	return iort_dev_map_rid(node, req_id, dev_id);
+}
+
+/**
+ * iort_pci_domain_get_msi_rid() - find MSI RID based on PCI device ID
+ * @pdev: The PCI device
+ * @req_id: The PCI device requester ID
+ *
+ * Returns: MSI RID on success, requester ID otherwise
+ */
+u32 iort_pci_get_msi_rid(struct pci_dev *pdev, u32 req_id)
+{
+	u32 dev_id;
+
+	if (!iort_its_find_node_and_map_rid(pdev, req_id, &dev_id))
+		return req_id;
+
+	return dev_id;
+}
+
+/**
+ * iort_pci_find_its_id() - find the ITS identifier based on specified device.
+ * @pdev: The PCI device
+ * @idx: Index of the ITS identifier list
+ * @its_id: ITS identifier
+ *
+ * Returns: 0 on success, appropriate error value otherwise
+ */
+static int
+iort_pci_find_its_id(struct pci_dev *pdev, u32 req_id, unsigned int idx,
+		     int *its_id)
+{
+	struct acpi_iort_its_group *its;
+	struct acpi_iort_node *node;
+
+	node = iort_its_find_node_and_map_rid(pdev, req_id, NULL);
+	if (!node)
+		return -ENXIO;
+
+	/* Move to ITS specific data */
+	its = (struct acpi_iort_its_group *)node->node_data;
+	if (idx > its->its_count) {
+		dev_err(&pdev->dev, "requested ITS ID index [%d] is greater than available[%d]\n",
+			idx, its->its_count);
+		return -ENXIO;
+	}
+
+	*its_id = its->identifiers[idx];
+	return 0;
+}
+
+/**
+ * iort_pci_get_msi_domain_handle() - find registered domain token related to
+ *                                    PCI device
+ * @pdev:    The PCI device
+ * @req_id:  The PCI device requester ID
+ *
+ * Returns: domain token on success, NULL otherwise
+ */
+struct fwnode_handle *
+iort_pci_get_domain(struct pci_dev *pdev, u32 req_id)
+{
+	static struct fwnode_handle *domain_handle;
+	int its_id;
+
+	if (iort_pci_find_its_id(pdev, req_id, 0, &its_id))
+		return NULL;
+
+	domain_handle = iort_its_find_domain_token(its_id);
+	if (!domain_handle)
+		return NULL;
+
+	return domain_handle;
+}
+
+static int __init iort_table_detect(void)
+{
+	acpi_status status;
+
+	if (acpi_disabled)
+		return -ENODEV;
+
+	status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
+	if (ACPI_FAILURE(status)) {
+		const char *msg = acpi_format_exception(status);
+		pr_err("Failed to get table, %s\n", msg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+arch_initcall(iort_table_detect);
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index fb50911..8410999 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -31,6 +31,7 @@  config ARM_GIC_V3
 config ARM_GIC_V3_ITS
 	bool
 	select PCI_MSI_IRQ_DOMAIN
+	select IORT_TABLE if ACPI
 
 config HISILICON_IRQ_MBIGEN
 	bool "Support mbigen interrupt controller"
diff --git a/include/linux/iort.h b/include/linux/iort.h
new file mode 100644
index 0000000..7441941
--- /dev/null
+++ b/include/linux/iort.h
@@ -0,0 +1,31 @@ 
+/*
+ * Copyright (C) 2016, Semihalf
+ *	Author: Tomasz Nowicki <tn@semihalf.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __IORT_H__
+#define __IORT_H__
+
+#include <linux/acpi.h>
+
+struct fwnode_handle;
+int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node);
+void iort_deregister_domain_token(int trans_id);
+struct fwnode_handle *iort_its_find_domain_token(int trans_id);
+u32 iort_pci_get_msi_rid(struct pci_dev *pdev, u32 req_id);
+struct fwnode_handle *iort_pci_get_domain(struct pci_dev *pdev, u32 req_id);
+
+#endif /* __IORT_H__ */