Re: [PATCH v2] PCI: ACPI: IA64: fix IO port generic range check

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Mar 10, 2016 at 07:42:36AM +0000, Lorenzo Pieralisi wrote:

[...]

> > > We can't do that, it may work on IA64 but the ioport_resource is a
> > > chunk of address space on IA64/ARM64 that has nothing to do with
> > > the physical address at which the root bridges decode IO space (which
> > > is what's contained in the resource).
> > 
> > I'm stumbling over "the physical address at which the root bridges
> > decode IO space (which is what's contained in the resource)".
> > 
> > x86 host bridges typically just forward CPU-generated I/O port
> > transactions to PCI with no address translation, so it sounds like
> > you're talking about ia64/ARM64 bridges that decode CPU MMIO space and
> > turn accesses into PCI I/O transactions.
> > 
> > If we start from a driver calling inb(), the driver supplies a Linux
> > ioport number "X".  On ia64 (and I assume ARM64 as well), inb()
> > performs an MMIO access to memory address "Y".  A host bridge consumes
> > that MMIO access and generates a corresponding PCI I/O transaction to
> > PCI ioport "Z".
> > 
> > It is indeed true that ioport_resource has nothing to do with memory
> > addresses like "Y".  But the driver (and this part of the ACPI
> > infrastructure) are dealing with ioport address "X", and that is
> > definitely in an IORESOURCE_IO struct resource.  The IORESOURCE_MEM_
> > struct resource that contains "Y" is internal to the host bridge
> > driver and invisible to the device driver that's using inb().
> 
> The problem is, that's the address like "Y" that are checked in
> acpi_dev_ioresource_flags() with current PCI initialization flow.
> 
> IO ports number "X" are created in (IA64) add_io_space() that is
> executed after acpi_pci_probe_root_resources() is called (see
> arch/ia64/pci/pci.c), that's the code that, IIUC, translates an
> IO resource containing a CPU physical address (which is the address
> that is ioremapped) to an IO resource containing a port number *and*
> a corresponding MEM resource.
> 
> The check that causes failures (>=0x10003) is carried out
> on the "raw" IO resource parsed from ACPI, not the one crafted
> in add_io_space().
> 
> The resource checked in acpi_dev_ioresource_flags() is created from
> ACPI IO descriptor and does contain CPU physical MMIO addresses,
> comparing it to a port number is bound to fail, they do NOT represent
> the same thing, happy be corrected.
> 
> That's the reason why currently IA64 IO space is not working, and
> this patch fixes it, please correct me if I am wrong.
> 
> I will write back next week with the commits sequence and logic that
> led to the current failure, sorry for not being able to respond
> more promptly and in a comprehensive way I need sometime to write up
> my understanding of the problem and commit logs, I will do that
> next week.

I had a further look and went through commit history and I think
my explanation above is correct, current code for IA64 PCI IO space
is wrong IMO and the failures started with:

commit 3772aea7d6f3 ("ia64/PCI/ACPI: Use common ACPI resource parsing
interface for host bridge")

because that's the commit that added IA64 PCI code to use
acpi_dev_get_resources(), let me add to that.

For the records, and for the same reason, let's imagine we can fix the
(>=0x10003) check in:

acpi_dev_ioresource_flags()

the code in acpi_pci_probe_root_resources() that checks the PCI IO
resources (ie acpi_pci_root_validate_resources()) is wrong, in that it
validates the PCI IO resources obtained from ACPI IO descriptors against
ioport_resource, and that's not correct, they do not represent the
same thing.

Code in acpi_dev_get_resources() walks the device (PCI host bridge in
this case) resources (ie _CRS) with acpi_dev_process_resource().

On IA64 IO space is memory mapped, therefore the CPU physical address
at which the PCI host bridge maps the IO space has to come from ACPI
IO descriptors.

IIUC, those descriptors are parsed through:

acpi_dev_resource_address_space()
acpi_dev_resource_ext_address_space()

which in turn call:

acpi_decode_space()

where the resource window is actually created, in particular the
acpi_address64_attribute value contains (on IA64, I verified with
ACPI spec working group through actual ACPI tables):

attr->minimum = PCI IO port min value
attr->translation_offset = offset to add to attr->minimum to obtain the
                           CPU physical address at which the PCI IO
			   bridge decodes IO space. Translation offset,
			   according to the ACPI specification has to
			   be used when resources on primary and
			   secondary sides of the PCI bridge are
			   different (IIUC secondary bus represents PCI
			   IO ports, primary bus CPU physical addresses
			   mapping IO ports in CPU physical address
			   space). This is the physical address that is
			   remapped in IA64 new_space(), to map the
			   bridge CPU physical address into the virtual
			   address space, and it has always been so, even
			   before 3772aea7d6f3.

Now, the resource window, in acpi_decode_space() is created as:

res->start = attr->minimum + attr->translation_offset;
res->end = attr->maximum + attr->translation_offset;

and that's the resource we have in acpi_dev_ioresource_flags(), if we
are comparing it against ioport_resource that's not correct since as I
already mentioned, they represent *different* things.

There is something we can do, which is, checking translation_type
in acpi_dev_ioresource_flags(), if it is == TypeTranslation (which
basically means that the IO space is MMIO) the >=10003 can be skipped,
but that's hackish (also because I am not sure IA64 platforms set
translation_type consistently in ACPI tables).

Even if we do that, call to acpi_pci_root_validate_resources() for
IO space is wrong on IA64, we are comparing an IO resource against
ioport_resource there, but the Linux IO port space for the host
bridge is created in IA64 pci_acpi_root_prepare_resources() with
the call to add_io_space() which happens *after* the sequence above
is executed.

On IA64:

pci_acpi_root_prepare_resources()
 -> acpi_pci_probe_root_resources()
    -> acpi_dev_get_resources()
    -> acpi_pci_root_validate_resources()
 -> add_io_space() # this is where the Linux IO port space for the bridge is
                     created and that's when we can validate the IO
		     resource against ioport_resource

I have no experience/knowledge of IA64 systems so I may be totally wrong,
I just want to understand.

Comments welcome, Hanjun proved my understanding by testing on IA64 and
current mainline just does not work (see commit log for failure messages),
feedback from IA64 people is really needed here, we have to get this fixed
please (and through that fix, getting it to work on ARM64 too).

Thanks,
Lorenzo
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux