diff mbox

[v7,3/3] arm64: Add architecture support for PCI

Message ID 1394811258-1500-4-git-send-email-Liviu.Dudau@arm.com
State New
Headers show

Commit Message

Liviu Dudau March 14, 2014, 3:34 p.m. UTC
Use the generic host bridge functions to provide support for
PCI Express on arm64. There is no support for ISA memory.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Tested-by: Tanmay Inamdar <tinamdar@apm.com>
---
 arch/arm64/Kconfig            |  19 +++-
 arch/arm64/include/asm/Kbuild |   1 +
 arch/arm64/include/asm/io.h   |   3 +-
 arch/arm64/include/asm/pci.h  |  51 ++++++++++
 arch/arm64/kernel/Makefile    |   1 +
 arch/arm64/kernel/pci.c       | 173 ++++++++++++++++++++++++++++++++
 6 files changed, 246 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm64/include/asm/pci.h
 create mode 100644 arch/arm64/kernel/pci.c

Comments

Catalin Marinas March 14, 2014, 5:14 p.m. UTC | #1
On Fri, Mar 14, 2014 at 03:34:18PM +0000, Liviu Dudau wrote:
> --- /dev/null
> +++ b/arch/arm64/kernel/pci.c
[...]
> +int pci_register_io_range(phys_addr_t address, resource_size_t size)
[...]
> +unsigned long pci_address_to_pio(phys_addr_t address)
[...]
> +void pcibios_fixup_bus(struct pci_bus *bus)
[ actually most of this file ]

Maybe it was raised before already but can we have __weak generic
definitions of these functions? They don't seem to be arm64 specific in
any way.
Liviu Dudau March 14, 2014, 6:05 p.m. UTC | #2
On Fri, Mar 14, 2014 at 05:38:08PM +0000, Arnd Bergmann wrote:
> On Friday 14 March 2014, Catalin Marinas wrote:
> > On Fri, Mar 14, 2014 at 03:34:18PM +0000, Liviu Dudau wrote:
> > > --- /dev/null
> > > +++ b/arch/arm64/kernel/pci.c
> > [...]
> > > +int pci_register_io_range(phys_addr_t address, resource_size_t size)
> > [...]
> > > +unsigned long pci_address_to_pio(phys_addr_t address)
> > [...]
> > > +void pcibios_fixup_bus(struct pci_bus *bus)
> > [ actually most of this file ]
> > 
> > Maybe it was raised before already but can we have __weak generic
> > definitions of these functions? They don't seem to be arm64 specific in
> > any way.
> > 
> 
> I would definitely prefer that.
> 
> 	Arnd
> 

I haven't seen any reaction from Bjorn on this, so I threaded carefully on that
subject. I'm new to this so I don't know how to handle this.

To my mind, and looking at the way every architecture has been setup, the pcibios_*
function are intended to be provided by the architecture. No matter how much wishful
thinking we are going to put in here, it will not change the fact that the non-arm64
specific version of pcibios_fixup_bus() that I wrote is not shared by anyone else
and it will remain "for arm64 use only" regardless to where it is placed until the
next architecture comes into the kernel. And even then its adoption is questionable.
If we are looking for simple and common implementations of this function, maybe we
should look at why microblaze and powerpc versions, that are identical, are not being
made the default __weak implementation.

As for the other two functions, I've no special attachment to where they are present
and I'm happy to move them into drivers/pci on the condition that the patchset doesn't
double in size. The reason why I'm weary of touching other architectures in a significant
way is the current lack of engineering bandwidth and way of testing all the architectures.
My low friction approach has been to introduce them in arm64 and then slowly move them
into core (and yes, I know about good intentions and the road to hell.)

Catalin, if you are happy to ask for ACKs from all arch maintainers that might get
affected by our custom version of pci_address_to_pio() before you can pull PCI support
for arm64 then I can propose a new patchset.

Best regards,
Liviu
Arnd Bergmann March 14, 2014, 7:10 p.m. UTC | #3
On Friday 14 March 2014, Liviu Dudau wrote:
> > 
> 
> I haven't seen any reaction from Bjorn on this, so I threaded carefully on that
> subject. I'm new to this so I don't know how to handle this.
> 
> To my mind, and looking at the way every architecture has been setup, the pcibios_*
> function are intended to be provided by the architecture.

That is definitely correct.

> No matter how much wishful
> thinking we are going to put in here, it will not change the fact that the non-arm64
> specific version of pcibios_fixup_bus() that I wrote is not shared by anyone else
> and it will remain "for arm64 use only" regardless to where it is placed until the
> next architecture comes into the kernel. And even then its adoption is questionable.

Agreed as well.

> If we are looking for simple and common implementations of this function, maybe we
> should look at why microblaze and powerpc versions, that are identical, are not being
> made the default __weak implementation.

Microblaze could most likely just be moved over to your version. The only
reason it is shared with the powerpc implementation is that they were
anticipating the code to become shared again and that it was known to
be working with flattened device tree.

> As for the other two functions, I've no special attachment to where they are present
> and I'm happy to move them into drivers/pci on the condition that the patchset doesn't
> double in size. The reason why I'm weary of touching other architectures in a significant
> way is the current lack of engineering bandwidth and way of testing all the architectures.
> My low friction approach has been to introduce them in arm64 and then slowly move them
> into core (and yes, I know about good intentions and the road to hell.)

I think everyone working on PCI is fed up with having arch-specific implementations
of all these, and Bjorn has been very supportive of generic infrastructure in the
past. Even just adding a generic infrastructure in a common place that is used
only by one architecture in my mind would be a significant improvement.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Rob Herring March 17, 2014, 4:05 p.m. UTC | #4
On Fri, Mar 14, 2014 at 10:34 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> Use the generic host bridge functions to provide support for
> PCI Express on arm64. There is no support for ISA memory.
>
> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> Tested-by: Tanmay Inamdar <tinamdar@apm.com>
> ---
>  arch/arm64/Kconfig            |  19 +++-
>  arch/arm64/include/asm/Kbuild |   1 +
>  arch/arm64/include/asm/io.h   |   3 +-
>  arch/arm64/include/asm/pci.h  |  51 ++++++++++
>  arch/arm64/kernel/Makefile    |   1 +
>  arch/arm64/kernel/pci.c       | 173 ++++++++++++++++++++++++++++++++
>  6 files changed, 246 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm64/include/asm/pci.h
>  create mode 100644 arch/arm64/kernel/pci.c

[snip]

> +#endif
> +
> +extern unsigned long pci_ioremap_io(const struct resource *res, phys_addr_t phys_addr);

Can we at least align the function definition across architectures if
not the implementation.


> +int pci_register_io_range(phys_addr_t address, resource_size_t size)
> +{
> +       struct ioresource *res;
> +       resource_size_t allocated_size = 0;
> +
> +       /* find if the range has not been already allocated */
> +       list_for_each_entry(res, &io_list, list) {
> +               if (address >= res->start &&
> +                       address + size <= res->start + size)
> +                       return 0;
> +               allocated_size += res->size;
> +       }
> +
> +       /* range not already registered, check for space */
> +       if (allocated_size + size > IO_SPACE_LIMIT)

I believe this needs to be "allocated_size + size - 1".

> +               return -E2BIG;
> +
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Liviu Dudau March 17, 2014, 4:22 p.m. UTC | #5
On Mon, Mar 17, 2014 at 04:05:38PM +0000, Rob Herring wrote:
> On Fri, Mar 14, 2014 at 10:34 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> > Use the generic host bridge functions to provide support for
> > PCI Express on arm64. There is no support for ISA memory.
> >
> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> > Tested-by: Tanmay Inamdar <tinamdar@apm.com>
> > ---
> >  arch/arm64/Kconfig            |  19 +++-
> >  arch/arm64/include/asm/Kbuild |   1 +
> >  arch/arm64/include/asm/io.h   |   3 +-
> >  arch/arm64/include/asm/pci.h  |  51 ++++++++++
> >  arch/arm64/kernel/Makefile    |   1 +
> >  arch/arm64/kernel/pci.c       | 173 ++++++++++++++++++++++++++++++++
> >  6 files changed, 246 insertions(+), 2 deletions(-)
> >  create mode 100644 arch/arm64/include/asm/pci.h
> >  create mode 100644 arch/arm64/kernel/pci.c
> 
> [snip]
> 
> > +#endif
> > +
> > +extern unsigned long pci_ioremap_io(const struct resource *res, phys_addr_t phys_addr);
> 
> Can we at least align the function definition across architectures if
> not the implementation.

The choice of names is unfortunate. We are trying to follow the spirit of the
arch/arm function, not the implementation, and for RFC that served the purpose.

I'll come up with a better name as I don't intend to share the implementation
with arch/arm here.

Best regards,
Liviu

> 
> 
> > +int pci_register_io_range(phys_addr_t address, resource_size_t size)
> > +{
> > +       struct ioresource *res;
> > +       resource_size_t allocated_size = 0;
> > +
> > +       /* find if the range has not been already allocated */
> > +       list_for_each_entry(res, &io_list, list) {
> > +               if (address >= res->start &&
> > +                       address + size <= res->start + size)
> > +                       return 0;
> > +               allocated_size += res->size;
> > +       }
> > +
> > +       /* range not already registered, check for space */
> > +       if (allocated_size + size > IO_SPACE_LIMIT)
> 
> I believe this needs to be "allocated_size + size - 1".
> 
> > +               return -E2BIG;
> > +
>
Catalin Marinas March 17, 2014, 5:38 p.m. UTC | #6
On Fri, Mar 14, 2014 at 06:05:27PM +0000, Liviu Dudau wrote:
> On Fri, Mar 14, 2014 at 05:38:08PM +0000, Arnd Bergmann wrote:
> > On Friday 14 March 2014, Catalin Marinas wrote:
> > > On Fri, Mar 14, 2014 at 03:34:18PM +0000, Liviu Dudau wrote:
> > > > --- /dev/null
> > > > +++ b/arch/arm64/kernel/pci.c
> > > [...]
> > > > +int pci_register_io_range(phys_addr_t address, resource_size_t size)
> > > [...]
> > > > +unsigned long pci_address_to_pio(phys_addr_t address)
> > > [...]
> > > > +void pcibios_fixup_bus(struct pci_bus *bus)
> > > [ actually most of this file ]
> > > 
> > > Maybe it was raised before already but can we have __weak generic
> > > definitions of these functions? They don't seem to be arm64 specific in
> > > any way.
[...]
> Catalin, if you are happy to ask for ACKs from all arch maintainers that might get
> affected by our custom version of pci_address_to_pio() before you can pull PCI support
> for arm64 then I can propose a new patchset.

You don't need to change the other architectures, that's the point of a
__weak definition, it will be automatically overridden. If you want, you
can even place a GENERIC_PCI or whatever config option that is only
selected by arm64 for the time being.
Liviu Dudau March 17, 2014, 6:05 p.m. UTC | #7
On Mon, Mar 17, 2014 at 05:38:21PM +0000, Catalin Marinas wrote:
> On Fri, Mar 14, 2014 at 06:05:27PM +0000, Liviu Dudau wrote:
> > On Fri, Mar 14, 2014 at 05:38:08PM +0000, Arnd Bergmann wrote:
> > > On Friday 14 March 2014, Catalin Marinas wrote:
> > > > On Fri, Mar 14, 2014 at 03:34:18PM +0000, Liviu Dudau wrote:
> > > > > --- /dev/null
> > > > > +++ b/arch/arm64/kernel/pci.c
> > > > [...]
> > > > > +int pci_register_io_range(phys_addr_t address, resource_size_t size)
> > > > [...]
> > > > > +unsigned long pci_address_to_pio(phys_addr_t address)
> > > > [...]
> > > > > +void pcibios_fixup_bus(struct pci_bus *bus)
> > > > [ actually most of this file ]
> > > > 
> > > > Maybe it was raised before already but can we have __weak generic
> > > > definitions of these functions? They don't seem to be arm64 specific in
> > > > any way.
> [...]
> > Catalin, if you are happy to ask for ACKs from all arch maintainers that might get
> > affected by our custom version of pci_address_to_pio() before you can pull PCI support
> > for arm64 then I can propose a new patchset.
> 
> You don't need to change the other architectures, that's the point of a
> __weak definition, it will be automatically overridden. If you want, you
> can even place a GENERIC_PCI or whatever config option that is only
> selected by arm64 for the time being.

pci_address_to_pio() is alread __weak. My patch was adding the arm64 version of it. Adding
an #ifdef GENERIC_PCI to the __weak implementation is not just a temporary solution.
We would still have to keep some sort of #ifdef around in the function as x86
will never pickup our version. Regardless, the list of people that would need to ACK that
change will increase, right?

Best regards,
Liviu

> 
> -- 
> Catalin
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Catalin Marinas March 19, 2014, 1:56 p.m. UTC | #8
On Mon, Mar 17, 2014 at 06:05:25PM +0000, Liviu Dudau wrote:
> On Mon, Mar 17, 2014 at 05:38:21PM +0000, Catalin Marinas wrote:
> > On Fri, Mar 14, 2014 at 06:05:27PM +0000, Liviu Dudau wrote:
> > > On Fri, Mar 14, 2014 at 05:38:08PM +0000, Arnd Bergmann wrote:
> > > > On Friday 14 March 2014, Catalin Marinas wrote:
> > > > > On Fri, Mar 14, 2014 at 03:34:18PM +0000, Liviu Dudau wrote:
> > > > > > --- /dev/null
> > > > > > +++ b/arch/arm64/kernel/pci.c
> > > > > [...]
> > > > > > +int pci_register_io_range(phys_addr_t address, resource_size_t size)
> > > > > [...]
> > > > > > +unsigned long pci_address_to_pio(phys_addr_t address)
> > > > > [...]
> > > > > > +void pcibios_fixup_bus(struct pci_bus *bus)
> > > > > [ actually most of this file ]
> > > > > 
> > > > > Maybe it was raised before already but can we have __weak generic
> > > > > definitions of these functions? They don't seem to be arm64 specific in
> > > > > any way.
> > [...]
> > > Catalin, if you are happy to ask for ACKs from all arch maintainers that might get
> > > affected by our custom version of pci_address_to_pio() before you can pull PCI support
> > > for arm64 then I can propose a new patchset.
> > 
> > You don't need to change the other architectures, that's the point of a
> > __weak definition, it will be automatically overridden. If you want, you
> > can even place a GENERIC_PCI or whatever config option that is only
> > selected by arm64 for the time being.
> 
> pci_address_to_pio() is alread __weak. My patch was adding the arm64 version of it. Adding
> an #ifdef GENERIC_PCI to the __weak implementation is not just a temporary solution.

Ah, I start to understand what you mean, pci_address_to_pio() is already
defined as __weak in drivers/of/address.c. So the reason we redefine it
on arm64 is that it uses the io_list resources which are populated by
pci_register_io_range(). Do you see any other architecture using a
similar logic (that could be shared)?

Any other functions in this file that could be shared (and are not
__weak already)?
Liviu Dudau March 19, 2014, 5:21 p.m. UTC | #9
On Wed, Mar 19, 2014 at 01:56:19PM +0000, Catalin Marinas wrote:
> On Mon, Mar 17, 2014 at 06:05:25PM +0000, Liviu Dudau wrote:
> > On Mon, Mar 17, 2014 at 05:38:21PM +0000, Catalin Marinas wrote:
> > > On Fri, Mar 14, 2014 at 06:05:27PM +0000, Liviu Dudau wrote:
> > > > On Fri, Mar 14, 2014 at 05:38:08PM +0000, Arnd Bergmann wrote:
> > > > > On Friday 14 March 2014, Catalin Marinas wrote:
> > > > > > On Fri, Mar 14, 2014 at 03:34:18PM +0000, Liviu Dudau wrote:
> > > > > > > --- /dev/null
> > > > > > > +++ b/arch/arm64/kernel/pci.c
> > > > > > [...]
> > > > > > > +int pci_register_io_range(phys_addr_t address, resource_size_t size)
> > > > > > [...]
> > > > > > > +unsigned long pci_address_to_pio(phys_addr_t address)
> > > > > > [...]
> > > > > > > +void pcibios_fixup_bus(struct pci_bus *bus)
> > > > > > [ actually most of this file ]
> > > > > > 
> > > > > > Maybe it was raised before already but can we have __weak generic
> > > > > > definitions of these functions? They don't seem to be arm64 specific in
> > > > > > any way.
> > > [...]
> > > > Catalin, if you are happy to ask for ACKs from all arch maintainers that might get
> > > > affected by our custom version of pci_address_to_pio() before you can pull PCI support
> > > > for arm64 then I can propose a new patchset.
> > > 
> > > You don't need to change the other architectures, that's the point of a
> > > __weak definition, it will be automatically overridden. If you want, you
> > > can even place a GENERIC_PCI or whatever config option that is only
> > > selected by arm64 for the time being.
> > 
> > pci_address_to_pio() is alread __weak. My patch was adding the arm64 version of it. Adding
> > an #ifdef GENERIC_PCI to the __weak implementation is not just a temporary solution.
> 
> Ah, I start to understand what you mean, pci_address_to_pio() is already
> defined as __weak in drivers/of/address.c. So the reason we redefine it
> on arm64 is that it uses the io_list resources which are populated by
> pci_register_io_range(). Do you see any other architecture using a
> similar logic (that could be shared)?

All architectures that memory map the PCI IO range should be supported by my version of
pci_address_to_pio(). But that still leaves the x86 and those architectures that have
separate IO space or map it 1:1 into CPU address space to carry a different version (which
the current "generic" weak version catters for).

> 
> Any other functions in this file that could be shared (and are not
> __weak already)?

A version of the pci_register_io_range() that uses part of pci_ioremap_io() (the calculation
of io_offset part).

My ultimate point is that no matter how long we argue about the shape of the functions that
I've added into arch/arm64/kernel/pci.c I don't think we can get away without having that
file, or at least not in the first phase if we want speedy integration into mainline.

Best regards,
Liviu

> 
> -- 
> Catalin
Rob Herring March 19, 2014, 5:53 p.m. UTC | #10
On Wed, Mar 19, 2014 at 12:21 PM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> On Wed, Mar 19, 2014 at 01:56:19PM +0000, Catalin Marinas wrote:
>> On Mon, Mar 17, 2014 at 06:05:25PM +0000, Liviu Dudau wrote:
>> > On Mon, Mar 17, 2014 at 05:38:21PM +0000, Catalin Marinas wrote:
>> > > On Fri, Mar 14, 2014 at 06:05:27PM +0000, Liviu Dudau wrote:
>> > > > On Fri, Mar 14, 2014 at 05:38:08PM +0000, Arnd Bergmann wrote:
>> > > > > On Friday 14 March 2014, Catalin Marinas wrote:
>> > > > > > On Fri, Mar 14, 2014 at 03:34:18PM +0000, Liviu Dudau wrote:
>> > > > > > > --- /dev/null
>> > > > > > > +++ b/arch/arm64/kernel/pci.c
>> > > > > > [...]
>> > > > > > > +int pci_register_io_range(phys_addr_t address, resource_size_t size)
>> > > > > > [...]
>> > > > > > > +unsigned long pci_address_to_pio(phys_addr_t address)
>> > > > > > [...]
>> > > > > > > +void pcibios_fixup_bus(struct pci_bus *bus)
>> > > > > > [ actually most of this file ]
>> > > > > >
>> > > > > > Maybe it was raised before already but can we have __weak generic
>> > > > > > definitions of these functions? They don't seem to be arm64 specific in
>> > > > > > any way.
>> > > [...]
>> > > > Catalin, if you are happy to ask for ACKs from all arch maintainers that might get
>> > > > affected by our custom version of pci_address_to_pio() before you can pull PCI support
>> > > > for arm64 then I can propose a new patchset.
>> > >
>> > > You don't need to change the other architectures, that's the point of a
>> > > __weak definition, it will be automatically overridden. If you want, you
>> > > can even place a GENERIC_PCI or whatever config option that is only
>> > > selected by arm64 for the time being.
>> >
>> > pci_address_to_pio() is alread __weak. My patch was adding the arm64 version of it. Adding
>> > an #ifdef GENERIC_PCI to the __weak implementation is not just a temporary solution.
>>
>> Ah, I start to understand what you mean, pci_address_to_pio() is already
>> defined as __weak in drivers/of/address.c. So the reason we redefine it
>> on arm64 is that it uses the io_list resources which are populated by
>> pci_register_io_range(). Do you see any other architecture using a
>> similar logic (that could be shared)?
>
> All architectures that memory map the PCI IO range should be supported by my version of
> pci_address_to_pio(). But that still leaves the x86 and those architectures that have
> separate IO space or map it 1:1 into CPU address space to carry a different version (which
> the current "generic" weak version catters for).
>
>>
>> Any other functions in this file that could be shared (and are not
>> __weak already)?
>
> A version of the pci_register_io_range() that uses part of pci_ioremap_io() (the calculation
> of io_offset part).
>
> My ultimate point is that no matter how long we argue about the shape of the functions that
> I've added into arch/arm64/kernel/pci.c I don't think we can get away without having that
> file, or at least not in the first phase if we want speedy integration into mainline.

"Speedy integration into mainline" is another way to say "leave it for
others to deal with and clean up later."

I've successfully used the preceeding series on ARM converting the
Versatile PCI support to use it. The main part of the process was just
copying this arm64 code to arm which tells me the code is in the wrong
place. There are still some differences in pcibios_fixup_bus, and it
is not clear to me whether the arm version should be doing all the
things the arm64 version does and vice-versa. Certainly that should be
sorted out. The other issues I see is pci_ioremap_io still has to be
called by the driver and is not aligned at least for the prototype as
I pointed out. Seems all these issues could be fixed with a simple
CONFIG_ARCH_HAS_MMIO_IOSPACE kconfig option.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Arnd Bergmann March 19, 2014, 6:36 p.m. UTC | #11
On Wednesday 19 March 2014 12:53:11 Rob Herring wrote:
> I've successfully used the preceeding series on ARM converting the
> Versatile PCI support to use it. The main part of the process was just
> copying this arm64 code to arm which tells me the code is in the wrong
> place. There are still some differences in pcibios_fixup_bus, and it
> is not clear to me whether the arm version should be doing all the
> things the arm64 version does and vice-versa. Certainly that should be
> sorted out. The other issues I see is pci_ioremap_io still has to be
> called by the driver and is not aligned at least for the prototype as
> I pointed out. Seems all these issues could be fixed with a simple
> CONFIG_ARCH_HAS_MMIO_IOSPACE kconfig option.

I don't even think we need a CONFIG option: Any architecture that wants
to provide pci_ioremap_io (or whatever we end up calling the new version)
needs to pass the virtual base address to the common code, and the
easiest way to do that is using a macro  (e.g. PCI_IO_VIRT_BASE).

What I think we should end up with is a generic implementation like

/* 
 * architectures with special needs may provide their own version,
 * but most should be able to use this one.
 */
unsigned long __weak pci_ioremap_iospace(struct resource *bus, unsigned long cpu)
{
#ifdef PCI_IO_VIRT_BASE
	/* find free space, ioremap the bus address, return the offset */
	...
#endif

	/* this architecture doesn't have memory mapped I/O space,
	   so this function should never be called */
	WARN_ON(1);
	return -ENODEV;
}

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Arnd Bergmann March 19, 2014, 6:37 p.m. UTC | #12
On Wednesday 19 March 2014 17:21:41 Liviu Dudau wrote:
> 
> My ultimate point is that no matter how long we argue about the shape of the functions that
> I've added into arch/arm64/kernel/pci.c I don't think we can get away without having that
> file, or at least not in the first phase if we want speedy integration into mainline.

Let me simplify the discussion here:

NAK to adding yet another architecture specific implementation.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Liviu Dudau March 20, 2014, 9:46 a.m. UTC | #13
On Wed, Mar 19, 2014 at 06:37:51PM +0000, Arnd Bergmann wrote:
> On Wednesday 19 March 2014 17:21:41 Liviu Dudau wrote:
> > 
> > My ultimate point is that no matter how long we argue about the shape of the functions that
> > I've added into arch/arm64/kernel/pci.c I don't think we can get away without having that
> > file, or at least not in the first phase if we want speedy integration into mainline.
> 
> Let me simplify the discussion here:
> 
> NAK to adding yet another architecture specific implementation.

So what would be your approach for handling pci_address_to_pio() in a non-arch specific way?

unsigned long __weak pci_address_to_pio(phys_addr_t address)
{
#ifdef ARCH_HAS_IOSPACE
	if (address > IO_SPACE_LIMIT)
		return (unsigned long)-1;

	return (unsigned long) address;
#else
	struct ioresource *res;

	list_for_each_entry(res, &io_list, list) {
		if (address >= res->start &&
			address < res->start + res->size) {
			return res->start - address;
		}
	}

	return (unsigned long)-1;
#endif
}


Either that, or you have more magic rabbits than me.

Best regards,
Liviu

> 
> 	Arnd
> 
>
Arnd Bergmann March 20, 2014, 11:17 a.m. UTC | #14
On Thursday 20 March 2014, Liviu Dudau wrote:
> On Wed, Mar 19, 2014 at 06:37:51PM +0000, Arnd Bergmann wrote:
> > On Wednesday 19 March 2014 17:21:41 Liviu Dudau wrote:
> > > 
> > > My ultimate point is that no matter how long we argue about the shape of the functions that
> > > I've added into arch/arm64/kernel/pci.c I don't think we can get away without having that
> > > file, or at least not in the first phase if we want speedy integration into mainline.
> > 
> > Let me simplify the discussion here:
> > 
> > NAK to adding yet another architecture specific implementation.
> 
> So what would be your approach for handling pci_address_to_pio() in a non-arch specific way?
> 
> unsigned long __weak pci_address_to_pio(phys_addr_t address)
> {
> #ifdef ARCH_HAS_IOSPACE
>         if (address > IO_SPACE_LIMIT)
>                 return (unsigned long)-1;
> 
>         return (unsigned long) address;
> #else
>         struct ioresource *res;
> 
>         list_for_each_entry(res, &io_list, list) {
>                 if (address >= res->start &&
>                         address < res->start + res->size) {
>                         return res->start - address;
>                 }
>         }
> 
>         return (unsigned long)-1;
> #endif
> }
> 
> 
> Either that, or you have more magic rabbits than me.

I don't even understand why you want to create a generic pci_address_to_pio
implementation, when we don't need that for arm64 at all. Unless I'm
missing something important, that function is only called in case of
PCI_PROBE_DEVTREE with pci_of_scan on PowerPC. I don't expect any
architecture to do the same thing, and the only other architecture that
needs something like it (sparc) has a different implementation.

The regular (non-DEVTREE) PCI bus scan should just be able to translate
the BUS I/O addresses into Linux I/O port numbers using io_offset,
without going through an intermediate step of translating into a CPU
physical address first, so the entire lookup method won't get used.

The reason why PowerPC needs it is that they traditionally don't
use PCI config space access to assign or look at resources, but
instead rely on the firmware to have set it up in advance and then
put matching information into DT and the BARs. For Solaris and AIX,
it's probably easier to use the information from DT, but in Linux,
we already need to implement the manual bus scan, e.g. to do
PCI device hotplugging if nothing else.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Liviu Dudau March 20, 2014, 11:38 a.m. UTC | #15
On Thu, Mar 20, 2014 at 11:17:22AM +0000, Arnd Bergmann wrote:
> On Thursday 20 March 2014, Liviu Dudau wrote:
> > On Wed, Mar 19, 2014 at 06:37:51PM +0000, Arnd Bergmann wrote:
> > > On Wednesday 19 March 2014 17:21:41 Liviu Dudau wrote:
> > > > 
> > > > My ultimate point is that no matter how long we argue about the shape of the functions that
> > > > I've added into arch/arm64/kernel/pci.c I don't think we can get away without having that
> > > > file, or at least not in the first phase if we want speedy integration into mainline.
> > > 
> > > Let me simplify the discussion here:
> > > 
> > > NAK to adding yet another architecture specific implementation.
> > 
> > So what would be your approach for handling pci_address_to_pio() in a non-arch specific way?
> > 
> > unsigned long __weak pci_address_to_pio(phys_addr_t address)
> > {
> > #ifdef ARCH_HAS_IOSPACE
> >         if (address > IO_SPACE_LIMIT)
> >                 return (unsigned long)-1;
> > 
> >         return (unsigned long) address;
> > #else
> >         struct ioresource *res;
> > 
> >         list_for_each_entry(res, &io_list, list) {
> >                 if (address >= res->start &&
> >                         address < res->start + res->size) {
> >                         return res->start - address;
> >                 }
> >         }
> > 
> >         return (unsigned long)-1;
> > #endif
> > }
> > 
> > 
> > Either that, or you have more magic rabbits than me.
> 
> I don't even understand why you want to create a generic pci_address_to_pio
> implementation, when we don't need that for arm64 at all. Unless I'm
> missing something important, that function is only called in case of
> PCI_PROBE_DEVTREE with pci_of_scan on PowerPC. I don't expect any
> architecture to do the same thing, and the only other architecture that
> needs something like it (sparc) has a different implementation.

Because in my [v7 2/6]* patch for the generic host bridge support I start
using pci_address_to_pio to fix the conversion of PCI ranges to resources.
That requires an arm64 (or more correctly, an arch with memory mapped IO
specific) version of pci_address_to_pio().

Best regards,
Liviu

> 
> The regular (non-DEVTREE) PCI bus scan should just be able to translate
> the BUS I/O addresses into Linux I/O port numbers using io_offset,
> without going through an intermediate step of translating into a CPU
> physical address first, so the entire lookup method won't get used.
> 
> The reason why PowerPC needs it is that they traditionally don't
> use PCI config space access to assign or look at resources, but
> instead rely on the firmware to have set it up in advance and then
> put matching information into DT and the BARs. For Solaris and AIX,
> it's probably easier to use the information from DT, but in Linux,
> we already need to implement the manual bus scan, e.g. to do
> PCI device hotplugging if nothing else.
> 
> 	Arnd
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Arnd Bergmann March 20, 2014, 12:26 p.m. UTC | #16
On Thursday 20 March 2014, Liviu Dudau wrote:
> > I don't even understand why you want to create a generic pci_address_to_pio
> > implementation, when we don't need that for arm64 at all. Unless I'm
> > missing something important, that function is only called in case of
> > PCI_PROBE_DEVTREE with pci_of_scan on PowerPC. I don't expect any
> > architecture to do the same thing, and the only other architecture that
> > needs something like it (sparc) has a different implementation.
> 
> Because in my [v7 2/6]* patch for the generic host bridge support I start
> using pci_address_to_pio to fix the conversion of PCI ranges to resources.
> That requires an arm64 (or more correctly, an arch with memory mapped IO
> specific) version of pci_address_to_pio().

Yes, but why do you use it there?

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Liviu Dudau March 20, 2014, 12:50 p.m. UTC | #17
On Thu, Mar 20, 2014 at 12:26:02PM +0000, Arnd Bergmann wrote:
> On Thursday 20 March 2014, Liviu Dudau wrote:
> > > I don't even understand why you want to create a generic pci_address_to_pio
> > > implementation, when we don't need that for arm64 at all. Unless I'm
> > > missing something important, that function is only called in case of
> > > PCI_PROBE_DEVTREE with pci_of_scan on PowerPC. I don't expect any
> > > architecture to do the same thing, and the only other architecture that
> > > needs something like it (sparc) has a different implementation.
> > 
> > Because in my [v7 2/6]* patch for the generic host bridge support I start
> > using pci_address_to_pio to fix the conversion of PCI ranges to resources.
> > That requires an arm64 (or more correctly, an arch with memory mapped IO
> > specific) version of pci_address_to_pio().
> 
> Yes, but why do you use it there?

I'm parsing the device tree and have reached the PCI IO range for the host bridge.
There is no host bridge created yet for that and hence no mapping. I need to
take the DT range declaration that gives me   CPU start .. SIZE --> BUS start and
convert it into   Logical IO port start .. Logical IO port end. While I could've
come up with (yet) another function that does the conversion from CPU address to
port IO address, I thought it would be nice to use the existing pci_address_to_pio()
function and adapt it to my needs. It has a __weak implementation anyway so I
could overwrite it in the architecture code.

To me it looked like a good plan and we had some discussions around my initial
goofy mistake of using pci_addr as physical address for translation. I never
thought it was considered a bad idea.

Best regards,
Liviu

> 
> 	Arnd
>
Bjorn Helgaas April 7, 2014, 11:58 p.m. UTC | #18
On Fri, Mar 14, 2014 at 03:34:18PM +0000, Liviu Dudau wrote:
> Use the generic host bridge functions to provide support for
> PCI Express on arm64. There is no support for ISA memory.
> 
> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> Tested-by: Tanmay Inamdar <tinamdar@apm.com>
> ---
>  arch/arm64/Kconfig            |  19 +++-
>  arch/arm64/include/asm/Kbuild |   1 +
>  arch/arm64/include/asm/io.h   |   3 +-
>  arch/arm64/include/asm/pci.h  |  51 ++++++++++
>  arch/arm64/kernel/Makefile    |   1 +
>  arch/arm64/kernel/pci.c       | 173 ++++++++++++++++++++++++++++++++
>  6 files changed, 246 insertions(+), 2 deletions(-)
>  create mode 100644 arch/arm64/include/asm/pci.h
>  create mode 100644 arch/arm64/kernel/pci.c
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 27bbcfc..d1c8568 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -62,7 +62,7 @@ config MMU
>  	def_bool y
>  
>  config NO_IOPORT
> -	def_bool y
> +	def_bool y if !PCI
>  
>  config STACKTRACE_SUPPORT
>  	def_bool y
> @@ -134,6 +134,23 @@ menu "Bus support"
>  config ARM_AMBA
>  	bool
>  
> +config PCI
> +	bool "PCI support"
> +	help
> +	  This feature enables support for PCIe bus system. If you say Y
> +	  here, the kernel will include drivers and infrastructure code
> +	  to support PCIe bus devices.
> +
> +config PCI_DOMAINS
> +	def_bool PCI
> +
> +config PCI_SYSCALL
> +	def_bool PCI
> +
> +source "drivers/pci/Kconfig"
> +source "drivers/pci/pcie/Kconfig"
> +source "drivers/pci/hotplug/Kconfig"
> +
>  endmenu
>  
>  menu "Kernel Features"
> diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
> index 71c53ec..46924bc 100644
> --- a/arch/arm64/include/asm/Kbuild
> +++ b/arch/arm64/include/asm/Kbuild
> @@ -26,6 +26,7 @@ generic-y += mman.h
>  generic-y += msgbuf.h
>  generic-y += mutex.h
>  generic-y += pci.h
> +generic-y += pci-bridge.h
>  generic-y += poll.h
>  generic-y += posix_types.h
>  generic-y += resource.h
> diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
> index 7846a6b..67463a5 100644
> --- a/arch/arm64/include/asm/io.h
> +++ b/arch/arm64/include/asm/io.h
> @@ -120,7 +120,8 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
>  /*
>   *  I/O port access primitives.
>   */
> -#define IO_SPACE_LIMIT		0xffff
> +#define arch_has_dev_port()	(1)
> +#define IO_SPACE_LIMIT		0x1ffffff
>  #define PCI_IOBASE		((void __iomem *)(MODULES_VADDR - SZ_32M))
>  
>  static inline u8 inb(unsigned long addr)
> diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
> new file mode 100644
> index 0000000..d93576f
> --- /dev/null
> +++ b/arch/arm64/include/asm/pci.h
> @@ -0,0 +1,51 @@
> +#ifndef __ASM_PCI_H
> +#define __ASM_PCI_H
> +#ifdef __KERNEL__
> +
> +#include <linux/types.h>
> +#include <linux/slab.h>
> +#include <linux/dma-mapping.h>
> +
> +#include <asm/io.h>
> +#include <asm-generic/pci-bridge.h>
> +#include <asm-generic/pci-dma-compat.h>
> +
> +#define PCIBIOS_MIN_IO		0x1000
> +#define PCIBIOS_MIN_MEM		0
> +
> +struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus);
> +
> +/*
> + * Set to 1 if the kernel should re-assign all PCI bus numbers
> + */
> +#define pcibios_assign_all_busses() \
> +	(pci_has_flag(PCI_REASSIGN_ALL_BUS))
> +
> +/*
> + * PCI address space differs from physical memory address space
> + */
> +#define PCI_DMA_BUS_IS_PHYS	(0)
> +
> +extern int isa_dma_bridge_buggy;
> +
> +#ifdef CONFIG_PCI
> +static inline int pci_domain_nr(struct pci_bus *bus)
> +{
> +	struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
> +
> +	if (bridge)
> +		return bridge->domain_nr;
> +
> +	return 0;
> +}
> +
> +static inline int pci_proc_domain(struct pci_bus *bus)
> +{
> +	return 1;
> +}
> +#endif
> +
> +extern unsigned long pci_ioremap_io(const struct resource *res, phys_addr_t phys_addr);
> +
> +#endif  /* __KERNEL__ */
> +#endif  /* __ASM_PCI_H */
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index 2d4554b..64fc479 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -20,6 +20,7 @@ arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
>  arm64-obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
>  arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
>  arm64-obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
> +arm64-obj-$(CONFIG_PCI)			+= pci.o
>  
>  obj-y					+= $(arm64-obj-y) vdso/
>  obj-m					+= $(arm64-obj-m)
> diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
> new file mode 100644
> index 0000000..9f29c9a
> --- /dev/null
> +++ b/arch/arm64/kernel/pci.c
> @@ -0,0 +1,173 @@
> +/*
> + * Code borrowed from powerpc/kernel/pci-common.c
> + *
> + * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
> + * Copyright (C) 2014 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/of_pci.h>
> +#include <linux/of_platform.h>
> +#include <linux/slab.h>
> +
> +#include <asm/pci-bridge.h>
> +
> +struct ioresource {
> +	struct list_head list;
> +	phys_addr_t start;
> +	resource_size_t size;
> +};
> +
> +static LIST_HEAD(io_list);
> +
> +int pci_register_io_range(phys_addr_t address, resource_size_t size)
> +{
> +	struct ioresource *res;
> +	resource_size_t allocated_size = 0;
> +
> +	/* find if the range has not been already allocated */
> +	list_for_each_entry(res, &io_list, list) {
> +		if (address >= res->start &&
> +			address + size <= res->start + size)
> +			return 0;
> +		allocated_size += res->size;
> +	}
> +
> +	/* range not already registered, check for space */
> +	if (allocated_size + size > IO_SPACE_LIMIT)
> +		return -E2BIG;
> +
> +	/* add the range in the list */
> +	res = kzalloc(sizeof(*res), GFP_KERNEL);
> +	if (!res)
> +		return -ENOMEM;
> +	res->start = address;
> +	res->size = size;
> +
> +	list_add_tail(&res->list, &io_list);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pci_register_io_range);
> +
> +unsigned long pci_address_to_pio(phys_addr_t address)
> +{
> +	struct ioresource *res;
> +
> +	list_for_each_entry(res, &io_list, list) {
> +		if (address >= res->start &&
> +			address < res->start + res->size) {
> +			return res->start - address;
> +		}
> +	}
> +
> +	return (unsigned long)-1;
> +}
> +EXPORT_SYMBOL_GPL(pci_address_to_pio);
> +
> +/*
> + * Called after each bus is probed, but before its children are examined
> + */
> +void pcibios_fixup_bus(struct pci_bus *bus)
> +{
> +	struct pci_dev *dev;
> +	struct resource *res;
> +	int i;
> +
> +	if (!pci_is_root_bus(bus)) {
> +		pci_read_bridge_bases(bus);
> +
> +		pci_bus_for_each_resource(bus, res, i) {
> +			if (!res || !res->flags || res->parent)
> +				continue;
> +
> +			/*
> +			 * If we are going to reassign everything, we can
> +			 * shrink the P2P resource to have zero size to
> +			 * save space
> +			 */
> +			if (pci_has_flag(PCI_REASSIGN_ALL_RSRC)) {
> +				res->flags |= IORESOURCE_UNSET;
> +				res->start = 0;
> +				res->end = -1;
> +				continue;
> +			}
> +		}
> +	}

Is there any other place we can put this?  I'm trying to nuke
pcibios_fixup_bus() because things like hotplug work better if we can do
them in a per-device way rather than a per-bus way.

> +
> +	list_for_each_entry(dev, &bus->devices, bus_list) {
> +		/* Ignore fully discovered devices */
> +		if (dev->is_added)
> +			continue;
> +
> +		set_dev_node(&dev->dev, pcibus_to_node(dev->bus));

Do you really need this?  pci_device_add() already contains the same line.

> +
> +		/* Read default IRQs and fixup if necessary */
> +		dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);

Could this be done in pcibios_add_device() or someplace similar?

> +	}
> +}
> +EXPORT_SYMBOL(pcibios_fixup_bus);
> +
> +/*
> + * We don't have to worry about legacy ISA devices, so nothing to do here
> + */
> +resource_size_t pcibios_align_resource(void *data, const struct resource *res,
> +				resource_size_t size, resource_size_t align)
> +{
> +	return res->start;
> +}
> +
> +int pcibios_enable_device(struct pci_dev *dev, int mask)
> +{
> +	return pci_enable_resources(dev, mask);
> +}

There is already a weak default implementation of pcibios_enable_device()
that does this, so you should be able to just drop this.

> +#define IO_SPACE_PAGES	((IO_SPACE_LIMIT + 1) / PAGE_SIZE)
> +static DECLARE_BITMAP(pci_iospace, IO_SPACE_PAGES);
> +
> +unsigned long pci_ioremap_io(const struct resource *res, phys_addr_t phys_addr)
> +{
> +	unsigned long start, len, virt_start;
> +	int err;
> +
> +	if (res->end > IO_SPACE_LIMIT)
> +		return -EINVAL;
> +
> +	/*
> +	 * try finding free space for the whole size first,
> +	 * fall back to 64K if not available
> +	 */
> +	len = resource_size(res);
> +	start = bitmap_find_next_zero_area(pci_iospace, IO_SPACE_PAGES,
> +				res->start / PAGE_SIZE, len / PAGE_SIZE, 0);
> +	if (start == IO_SPACE_PAGES && len > SZ_64K) {
> +		len = SZ_64K;
> +		start = 0;
> +		start = bitmap_find_next_zero_area(pci_iospace, IO_SPACE_PAGES,
> +					start, len / PAGE_SIZE, 0);
> +	}
> +
> +	/* no 64K area found */
> +	if (start == IO_SPACE_PAGES)
> +		return -ENOMEM;
> +
> +	/* ioremap physical aperture to virtual aperture */
> +	virt_start = start * PAGE_SIZE + (unsigned long)PCI_IOBASE;
> +	err = ioremap_page_range(virt_start, virt_start + len,
> +				phys_addr, __pgprot(PROT_DEVICE_nGnRE));
> +	if (err)
> +		return err;
> +
> +	bitmap_set(pci_iospace, start, len / PAGE_SIZE);
> +
> +	/* return io_offset */
> +	return start * PAGE_SIZE - res->start;
> +}
> -- 
> 1.9.0
> 
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Liviu Dudau April 8, 2014, 9:52 a.m. UTC | #19
On Tue, Apr 08, 2014 at 12:58:30AM +0100, Bjorn Helgaas wrote:
> On Fri, Mar 14, 2014 at 03:34:18PM +0000, Liviu Dudau wrote:
> > Use the generic host bridge functions to provide support for
> > PCI Express on arm64. There is no support for ISA memory.
> >
> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> > Tested-by: Tanmay Inamdar <tinamdar@apm.com>
> > ---
> >  arch/arm64/Kconfig            |  19 +++-
> >  arch/arm64/include/asm/Kbuild |   1 +
> >  arch/arm64/include/asm/io.h   |   3 +-
> >  arch/arm64/include/asm/pci.h  |  51 ++++++++++
> >  arch/arm64/kernel/Makefile    |   1 +
> >  arch/arm64/kernel/pci.c       | 173 ++++++++++++++++++++++++++++++++
> >  6 files changed, 246 insertions(+), 2 deletions(-)
> >  create mode 100644 arch/arm64/include/asm/pci.h
> >  create mode 100644 arch/arm64/kernel/pci.c
> >
> > diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> > index 27bbcfc..d1c8568 100644
> > --- a/arch/arm64/Kconfig
> > +++ b/arch/arm64/Kconfig
> > @@ -62,7 +62,7 @@ config MMU
> >       def_bool y
> >
> >  config NO_IOPORT
> > -     def_bool y
> > +     def_bool y if !PCI
> >
> >  config STACKTRACE_SUPPORT
> >       def_bool y
> > @@ -134,6 +134,23 @@ menu "Bus support"
> >  config ARM_AMBA
> >       bool
> >
> > +config PCI
> > +     bool "PCI support"
> > +     help
> > +       This feature enables support for PCIe bus system. If you say Y
> > +       here, the kernel will include drivers and infrastructure code
> > +       to support PCIe bus devices.
> > +
> > +config PCI_DOMAINS
> > +     def_bool PCI
> > +
> > +config PCI_SYSCALL
> > +     def_bool PCI
> > +
> > +source "drivers/pci/Kconfig"
> > +source "drivers/pci/pcie/Kconfig"
> > +source "drivers/pci/hotplug/Kconfig"
> > +
> >  endmenu
> >
> >  menu "Kernel Features"
> > diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
> > index 71c53ec..46924bc 100644
> > --- a/arch/arm64/include/asm/Kbuild
> > +++ b/arch/arm64/include/asm/Kbuild
> > @@ -26,6 +26,7 @@ generic-y += mman.h
> >  generic-y += msgbuf.h
> >  generic-y += mutex.h
> >  generic-y += pci.h
> > +generic-y += pci-bridge.h
> >  generic-y += poll.h
> >  generic-y += posix_types.h
> >  generic-y += resource.h
> > diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
> > index 7846a6b..67463a5 100644
> > --- a/arch/arm64/include/asm/io.h
> > +++ b/arch/arm64/include/asm/io.h
> > @@ -120,7 +120,8 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
> >  /*
> >   *  I/O port access primitives.
> >   */
> > -#define IO_SPACE_LIMIT               0xffff
> > +#define arch_has_dev_port()  (1)
> > +#define IO_SPACE_LIMIT               0x1ffffff
> >  #define PCI_IOBASE           ((void __iomem *)(MODULES_VADDR - SZ_32M))
> >
> >  static inline u8 inb(unsigned long addr)
> > diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
> > new file mode 100644
> > index 0000000..d93576f
> > --- /dev/null
> > +++ b/arch/arm64/include/asm/pci.h
> > @@ -0,0 +1,51 @@
> > +#ifndef __ASM_PCI_H
> > +#define __ASM_PCI_H
> > +#ifdef __KERNEL__
> > +
> > +#include <linux/types.h>
> > +#include <linux/slab.h>
> > +#include <linux/dma-mapping.h>
> > +
> > +#include <asm/io.h>
> > +#include <asm-generic/pci-bridge.h>
> > +#include <asm-generic/pci-dma-compat.h>
> > +
> > +#define PCIBIOS_MIN_IO               0x1000
> > +#define PCIBIOS_MIN_MEM              0
> > +
> > +struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus);
> > +
> > +/*
> > + * Set to 1 if the kernel should re-assign all PCI bus numbers
> > + */
> > +#define pcibios_assign_all_busses() \
> > +     (pci_has_flag(PCI_REASSIGN_ALL_BUS))
> > +
> > +/*
> > + * PCI address space differs from physical memory address space
> > + */
> > +#define PCI_DMA_BUS_IS_PHYS  (0)
> > +
> > +extern int isa_dma_bridge_buggy;
> > +
> > +#ifdef CONFIG_PCI
> > +static inline int pci_domain_nr(struct pci_bus *bus)
> > +{
> > +     struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
> > +
> > +     if (bridge)
> > +             return bridge->domain_nr;
> > +
> > +     return 0;
> > +}
> > +
> > +static inline int pci_proc_domain(struct pci_bus *bus)
> > +{
> > +     return 1;
> > +}
> > +#endif
> > +
> > +extern unsigned long pci_ioremap_io(const struct resource *res, phys_addr_t phys_addr);
> > +
> > +#endif  /* __KERNEL__ */
> > +#endif  /* __ASM_PCI_H */
> > diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> > index 2d4554b..64fc479 100644
> > --- a/arch/arm64/kernel/Makefile
> > +++ b/arch/arm64/kernel/Makefile
> > @@ -20,6 +20,7 @@ arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
> >  arm64-obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
> >  arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)        += sleep.o suspend.o
> >  arm64-obj-$(CONFIG_JUMP_LABEL)               += jump_label.o
> > +arm64-obj-$(CONFIG_PCI)                      += pci.o
> >
> >  obj-y                                        += $(arm64-obj-y) vdso/
> >  obj-m                                        += $(arm64-obj-m)
> > diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
> > new file mode 100644
> > index 0000000..9f29c9a
> > --- /dev/null
> > +++ b/arch/arm64/kernel/pci.c
> > @@ -0,0 +1,173 @@
> > +/*
> > + * Code borrowed from powerpc/kernel/pci-common.c
> > + *
> > + * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
> > + * Copyright (C) 2014 ARM Ltd.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2 as published by the Free Software Foundation.
> > + *
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mm.h>
> > +#include <linux/of_pci.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/slab.h>
> > +
> > +#include <asm/pci-bridge.h>
> > +
> > +struct ioresource {
> > +     struct list_head list;
> > +     phys_addr_t start;
> > +     resource_size_t size;
> > +};
> > +
> > +static LIST_HEAD(io_list);
> > +
> > +int pci_register_io_range(phys_addr_t address, resource_size_t size)
> > +{
> > +     struct ioresource *res;
> > +     resource_size_t allocated_size = 0;
> > +
> > +     /* find if the range has not been already allocated */
> > +     list_for_each_entry(res, &io_list, list) {
> > +             if (address >= res->start &&
> > +                     address + size <= res->start + size)
> > +                     return 0;
> > +             allocated_size += res->size;
> > +     }
> > +
> > +     /* range not already registered, check for space */
> > +     if (allocated_size + size > IO_SPACE_LIMIT)
> > +             return -E2BIG;
> > +
> > +     /* add the range in the list */
> > +     res = kzalloc(sizeof(*res), GFP_KERNEL);
> > +     if (!res)
> > +             return -ENOMEM;
> > +     res->start = address;
> > +     res->size = size;
> > +
> > +     list_add_tail(&res->list, &io_list);
> > +
> > +     return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(pci_register_io_range);
> > +
> > +unsigned long pci_address_to_pio(phys_addr_t address)
> > +{
> > +     struct ioresource *res;
> > +
> > +     list_for_each_entry(res, &io_list, list) {
> > +             if (address >= res->start &&
> > +                     address < res->start + res->size) {
> > +                     return res->start - address;
> > +             }
> > +     }
> > +
> > +     return (unsigned long)-1;
> > +}
> > +EXPORT_SYMBOL_GPL(pci_address_to_pio);
> > +
> > +/*
> > + * Called after each bus is probed, but before its children are examined
> > + */
> > +void pcibios_fixup_bus(struct pci_bus *bus)
> > +{
> > +     struct pci_dev *dev;
> > +     struct resource *res;
> > +     int i;
> > +
> > +     if (!pci_is_root_bus(bus)) {
> > +             pci_read_bridge_bases(bus);
> > +
> > +             pci_bus_for_each_resource(bus, res, i) {
> > +                     if (!res || !res->flags || res->parent)
> > +                             continue;
> > +
> > +                     /*
> > +                      * If we are going to reassign everything, we can
> > +                      * shrink the P2P resource to have zero size to
> > +                      * save space
> > +                      */
> > +                     if (pci_has_flag(PCI_REASSIGN_ALL_RSRC)) {
> > +                             res->flags |= IORESOURCE_UNSET;
> > +                             res->start = 0;
> > +                             res->end = -1;
> > +                             continue;
> > +                     }
> > +             }
> > +     }
> 
> Is there any other place we can put this?  I'm trying to nuke
> pcibios_fixup_bus() because things like hotplug work better if we can do
> them in a per-device way rather than a per-bus way.

That's good. I'm all for removing this one, will give it a go.

> 
> > +
> > +     list_for_each_entry(dev, &bus->devices, bus_list) {
> > +             /* Ignore fully discovered devices */
> > +             if (dev->is_added)
> > +                     continue;
> > +
> > +             set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
> 
> Do you really need this?  pci_device_add() already contains the same line.

OK.

> 
> > +
> > +             /* Read default IRQs and fixup if necessary */
> > +             dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
> 
> Could this be done in pcibios_add_device() or someplace similar?

Will do.

> 
> > +     }
> > +}
> > +EXPORT_SYMBOL(pcibios_fixup_bus);
> > +
> > +/*
> > + * We don't have to worry about legacy ISA devices, so nothing to do here
> > + */
> > +resource_size_t pcibios_align_resource(void *data, const struct resource *res,
> > +                             resource_size_t size, resource_size_t align)
> > +{
> > +     return res->start;
> > +}
> > +
> > +int pcibios_enable_device(struct pci_dev *dev, int mask)
> > +{
> > +     return pci_enable_resources(dev, mask);
> > +}
> 
> There is already a weak default implementation of pcibios_enable_device()
> that does this, so you should be able to just drop this.

OK.

Thanks for reviewing the series!

Liviu

> 
> > +#define IO_SPACE_PAGES       ((IO_SPACE_LIMIT + 1) / PAGE_SIZE)
> > +static DECLARE_BITMAP(pci_iospace, IO_SPACE_PAGES);
> > +
> > +unsigned long pci_ioremap_io(const struct resource *res, phys_addr_t phys_addr)
> > +{
> > +     unsigned long start, len, virt_start;
> > +     int err;
> > +
> > +     if (res->end > IO_SPACE_LIMIT)
> > +             return -EINVAL;
> > +
> > +     /*
> > +      * try finding free space for the whole size first,
> > +      * fall back to 64K if not available
> > +      */
> > +     len = resource_size(res);
> > +     start = bitmap_find_next_zero_area(pci_iospace, IO_SPACE_PAGES,
> > +                             res->start / PAGE_SIZE, len / PAGE_SIZE, 0);
> > +     if (start == IO_SPACE_PAGES && len > SZ_64K) {
> > +             len = SZ_64K;
> > +             start = 0;
> > +             start = bitmap_find_next_zero_area(pci_iospace, IO_SPACE_PAGES,
> > +                                     start, len / PAGE_SIZE, 0);
> > +     }
> > +
> > +     /* no 64K area found */
> > +     if (start == IO_SPACE_PAGES)
> > +             return -ENOMEM;
> > +
> > +     /* ioremap physical aperture to virtual aperture */
> > +     virt_start = start * PAGE_SIZE + (unsigned long)PCI_IOBASE;
> > +     err = ioremap_page_range(virt_start, virt_start + len,
> > +                             phys_addr, __pgprot(PROT_DEVICE_nGnRE));
> > +     if (err)
> > +             return err;
> > +
> > +     bitmap_set(pci_iospace, start, len / PAGE_SIZE);
> > +
> > +     /* return io_offset */
> > +     return start * PAGE_SIZE - res->start;
> > +}
> > --
> > 1.9.0
> >
>
diff mbox

Patch

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 27bbcfc..d1c8568 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -62,7 +62,7 @@  config MMU
 	def_bool y
 
 config NO_IOPORT
-	def_bool y
+	def_bool y if !PCI
 
 config STACKTRACE_SUPPORT
 	def_bool y
@@ -134,6 +134,23 @@  menu "Bus support"
 config ARM_AMBA
 	bool
 
+config PCI
+	bool "PCI support"
+	help
+	  This feature enables support for PCIe bus system. If you say Y
+	  here, the kernel will include drivers and infrastructure code
+	  to support PCIe bus devices.
+
+config PCI_DOMAINS
+	def_bool PCI
+
+config PCI_SYSCALL
+	def_bool PCI
+
+source "drivers/pci/Kconfig"
+source "drivers/pci/pcie/Kconfig"
+source "drivers/pci/hotplug/Kconfig"
+
 endmenu
 
 menu "Kernel Features"
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 71c53ec..46924bc 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -26,6 +26,7 @@  generic-y += mman.h
 generic-y += msgbuf.h
 generic-y += mutex.h
 generic-y += pci.h
+generic-y += pci-bridge.h
 generic-y += poll.h
 generic-y += posix_types.h
 generic-y += resource.h
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 7846a6b..67463a5 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -120,7 +120,8 @@  static inline u64 __raw_readq(const volatile void __iomem *addr)
 /*
  *  I/O port access primitives.
  */
-#define IO_SPACE_LIMIT		0xffff
+#define arch_has_dev_port()	(1)
+#define IO_SPACE_LIMIT		0x1ffffff
 #define PCI_IOBASE		((void __iomem *)(MODULES_VADDR - SZ_32M))
 
 static inline u8 inb(unsigned long addr)
diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
new file mode 100644
index 0000000..d93576f
--- /dev/null
+++ b/arch/arm64/include/asm/pci.h
@@ -0,0 +1,51 @@ 
+#ifndef __ASM_PCI_H
+#define __ASM_PCI_H
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm-generic/pci-bridge.h>
+#include <asm-generic/pci-dma-compat.h>
+
+#define PCIBIOS_MIN_IO		0x1000
+#define PCIBIOS_MIN_MEM		0
+
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus);
+
+/*
+ * Set to 1 if the kernel should re-assign all PCI bus numbers
+ */
+#define pcibios_assign_all_busses() \
+	(pci_has_flag(PCI_REASSIGN_ALL_BUS))
+
+/*
+ * PCI address space differs from physical memory address space
+ */
+#define PCI_DMA_BUS_IS_PHYS	(0)
+
+extern int isa_dma_bridge_buggy;
+
+#ifdef CONFIG_PCI
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+	struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
+
+	if (bridge)
+		return bridge->domain_nr;
+
+	return 0;
+}
+
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+	return 1;
+}
+#endif
+
+extern unsigned long pci_ioremap_io(const struct resource *res, phys_addr_t phys_addr);
+
+#endif  /* __KERNEL__ */
+#endif  /* __ASM_PCI_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 2d4554b..64fc479 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -20,6 +20,7 @@  arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
 arm64-obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
 arm64-obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
+arm64-obj-$(CONFIG_PCI)			+= pci.o
 
 obj-y					+= $(arm64-obj-y) vdso/
 obj-m					+= $(arm64-obj-m)
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
new file mode 100644
index 0000000..9f29c9a
--- /dev/null
+++ b/arch/arm64/kernel/pci.c
@@ -0,0 +1,173 @@ 
+/*
+ * Code borrowed from powerpc/kernel/pci-common.c
+ *
+ * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright (C) 2014 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#include <asm/pci-bridge.h>
+
+struct ioresource {
+	struct list_head list;
+	phys_addr_t start;
+	resource_size_t size;
+};
+
+static LIST_HEAD(io_list);
+
+int pci_register_io_range(phys_addr_t address, resource_size_t size)
+{
+	struct ioresource *res;
+	resource_size_t allocated_size = 0;
+
+	/* find if the range has not been already allocated */
+	list_for_each_entry(res, &io_list, list) {
+		if (address >= res->start &&
+			address + size <= res->start + size)
+			return 0;
+		allocated_size += res->size;
+	}
+
+	/* range not already registered, check for space */
+	if (allocated_size + size > IO_SPACE_LIMIT)
+		return -E2BIG;
+
+	/* add the range in the list */
+	res = kzalloc(sizeof(*res), GFP_KERNEL);
+	if (!res)
+		return -ENOMEM;
+	res->start = address;
+	res->size = size;
+
+	list_add_tail(&res->list, &io_list);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pci_register_io_range);
+
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+	struct ioresource *res;
+
+	list_for_each_entry(res, &io_list, list) {
+		if (address >= res->start &&
+			address < res->start + res->size) {
+			return res->start - address;
+		}
+	}
+
+	return (unsigned long)-1;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
+/*
+ * Called after each bus is probed, but before its children are examined
+ */
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+	struct resource *res;
+	int i;
+
+	if (!pci_is_root_bus(bus)) {
+		pci_read_bridge_bases(bus);
+
+		pci_bus_for_each_resource(bus, res, i) {
+			if (!res || !res->flags || res->parent)
+				continue;
+
+			/*
+			 * If we are going to reassign everything, we can
+			 * shrink the P2P resource to have zero size to
+			 * save space
+			 */
+			if (pci_has_flag(PCI_REASSIGN_ALL_RSRC)) {
+				res->flags |= IORESOURCE_UNSET;
+				res->start = 0;
+				res->end = -1;
+				continue;
+			}
+		}
+	}
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		/* Ignore fully discovered devices */
+		if (dev->is_added)
+			continue;
+
+		set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
+
+		/* Read default IRQs and fixup if necessary */
+		dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+	}
+}
+EXPORT_SYMBOL(pcibios_fixup_bus);
+
+/*
+ * We don't have to worry about legacy ISA devices, so nothing to do here
+ */
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+				resource_size_t size, resource_size_t align)
+{
+	return res->start;
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	return pci_enable_resources(dev, mask);
+}
+
+#define IO_SPACE_PAGES	((IO_SPACE_LIMIT + 1) / PAGE_SIZE)
+static DECLARE_BITMAP(pci_iospace, IO_SPACE_PAGES);
+
+unsigned long pci_ioremap_io(const struct resource *res, phys_addr_t phys_addr)
+{
+	unsigned long start, len, virt_start;
+	int err;
+
+	if (res->end > IO_SPACE_LIMIT)
+		return -EINVAL;
+
+	/*
+	 * try finding free space for the whole size first,
+	 * fall back to 64K if not available
+	 */
+	len = resource_size(res);
+	start = bitmap_find_next_zero_area(pci_iospace, IO_SPACE_PAGES,
+				res->start / PAGE_SIZE, len / PAGE_SIZE, 0);
+	if (start == IO_SPACE_PAGES && len > SZ_64K) {
+		len = SZ_64K;
+		start = 0;
+		start = bitmap_find_next_zero_area(pci_iospace, IO_SPACE_PAGES,
+					start, len / PAGE_SIZE, 0);
+	}
+
+	/* no 64K area found */
+	if (start == IO_SPACE_PAGES)
+		return -ENOMEM;
+
+	/* ioremap physical aperture to virtual aperture */
+	virt_start = start * PAGE_SIZE + (unsigned long)PCI_IOBASE;
+	err = ioremap_page_range(virt_start, virt_start + len,
+				phys_addr, __pgprot(PROT_DEVICE_nGnRE));
+	if (err)
+		return err;
+
+	bitmap_set(pci_iospace, start, len / PAGE_SIZE);
+
+	/* return io_offset */
+	return start * PAGE_SIZE - res->start;
+}