diff mbox

[v2,1/2] PCI support added to ARC

Message ID 6080d7d4283d7aec6482d3f4236e536d36a1b7d2.1450274797.git.jpinto@synopsys.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Joao Pinto Dec. 16, 2015, 2:14 p.m. UTC
This patch adds PCI support to ARC and updates drivers/pci Makefile enabling
the ARC arch to use the generic PCI setup functions.

Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
Change v1 -> v2:
- In arch/arc/Kconfig, the new menu entry (Bus Configuration) was moved to the
slot between sourcing of drivers/Kconfig and fs/Kconfig (Vineet Gupta)
- In arch/arc/plat-axs10x/Kconfig the "select MIGHT_HAVE_PCI" option was placed
in order as suggested (Vineet Gupta)
- ioport_map() and ioport_unmap() were static inlined and included in
the io.h (Vineet Gupta)
- pcibios_min_io and pcibios_min_mem declaration moved to
pcibios.c (Vineet Gupta)
- pr_err() replaced by dev_err() in pcibios_enable_device() (Bjorn Helgaas)
- string simplified in pcibios_enable_device() (Vineet Gupta)
- pci_host_bridge_window structure was replaced by resource_entry structure, and
list_for_each_entry() for resource_list_for_each_entry() in pcibios.c

 arch/arc/Kconfig                |  23 +++
 arch/arc/include/asm/dma.h      |   5 +
 arch/arc/include/asm/io.h       |  10 ++
 arch/arc/include/asm/mach/pci.h |  97 +++++++++++
 arch/arc/include/asm/pci.h      |  34 ++++
 arch/arc/kernel/Makefile        |   1 +
 arch/arc/kernel/pcibios.c       | 358 ++++++++++++++++++++++++++++++++++++++++
 arch/arc/mm/ioremap.c           |  10 +-
 arch/arc/plat-axs10x/Kconfig    |   1 +
 drivers/pci/Makefile            |   1 +
 10 files changed, 539 insertions(+), 1 deletion(-)
 create mode 100644 arch/arc/include/asm/mach/pci.h
 create mode 100644 arch/arc/include/asm/pci.h
 create mode 100644 arch/arc/kernel/pcibios.c

Comments

Bjorn Helgaas Dec. 17, 2015, 9:11 p.m. UTC | #1
On Wed, Dec 16, 2015 at 02:14:55PM +0000, Joao Pinto wrote:
> This patch adds PCI support to ARC and updates drivers/pci Makefile enabling
> the ARC arch to use the generic PCI setup functions.
> 
> Signed-off-by: Joao Pinto <jpinto@synopsys.com>

Checkpatch complains about some whitespace errors (new blank lines at
EOF).

Hmmm, almost all of this appears to be copied straight from arch/arm,
but almost none of it is actually used.  If that's true, it's good
because you can make the patches much smaller.  But it's a little bit
bad, too, because it means we almost merged a bunch of dead code.

> ---
> Change v1 -> v2:
> - In arch/arc/Kconfig, the new menu entry (Bus Configuration) was moved to the
> slot between sourcing of drivers/Kconfig and fs/Kconfig (Vineet Gupta)
> - In arch/arc/plat-axs10x/Kconfig the "select MIGHT_HAVE_PCI" option was placed
> in order as suggested (Vineet Gupta)
> - ioport_map() and ioport_unmap() were static inlined and included in
> the io.h (Vineet Gupta)
> - pcibios_min_io and pcibios_min_mem declaration moved to
> pcibios.c (Vineet Gupta)
> - pr_err() replaced by dev_err() in pcibios_enable_device() (Bjorn Helgaas)
> - string simplified in pcibios_enable_device() (Vineet Gupta)
> - pci_host_bridge_window structure was replaced by resource_entry structure, and
> list_for_each_entry() for resource_list_for_each_entry() in pcibios.c
> 
>  arch/arc/Kconfig                |  23 +++
>  arch/arc/include/asm/dma.h      |   5 +
>  arch/arc/include/asm/io.h       |  10 ++
>  arch/arc/include/asm/mach/pci.h |  97 +++++++++++
>  arch/arc/include/asm/pci.h      |  34 ++++
>  arch/arc/kernel/Makefile        |   1 +
>  arch/arc/kernel/pcibios.c       | 358 ++++++++++++++++++++++++++++++++++++++++
>  arch/arc/mm/ioremap.c           |  10 +-
>  arch/arc/plat-axs10x/Kconfig    |   1 +
>  drivers/pci/Makefile            |   1 +
>  10 files changed, 539 insertions(+), 1 deletion(-)
>  create mode 100644 arch/arc/include/asm/mach/pci.h
>  create mode 100644 arch/arc/include/asm/pci.h
>  create mode 100644 arch/arc/kernel/pcibios.c
> 
> diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
> index 2c2ac3f..98b32c1 100644
> --- a/arch/arc/Kconfig
> +++ b/arch/arc/Kconfig
> @@ -19,6 +19,7 @@ config ARC
>  	select GENERIC_FIND_FIRST_BIT
>  	# for now, we don't need GENERIC_IRQ_PROBE, CONFIG_GENERIC_IRQ_CHIP
>  	select GENERIC_IRQ_SHOW
> +	select GENERIC_PCI_IOMAP
>  	select GENERIC_PENDING_IRQ if SMP
>  	select GENERIC_SMP_IDLE_THREAD
>  	select HAVE_ARCH_KGDB
> @@ -39,6 +40,9 @@ config ARC
>  	select PERF_USE_VMALLOC
>  	select HAVE_DEBUG_STACKOVERFLOW
>  
> +config MIGHT_HAVE_PCI
> +	bool
> +
>  config TRACE_IRQFLAGS_SUPPORT
>  	def_bool y
>  
> @@ -570,6 +574,25 @@ endmenu	 # "ARC Architecture Configuration"
>  source "mm/Kconfig"
>  source "net/Kconfig"
>  source "drivers/Kconfig"
> +
> +menu "Bus Support"
> +
> +config PCI
> +	bool "PCI support" if MIGHT_HAVE_PCI
> +	help
> +	  PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside
> +	  your box.Find out if your board/platform have PCI.
> +	  Note: PCIE support for Synopsys Device will be available only when
> +	  HAPS DX is configured with PCIE RC bitmap. If you have PCI, say Y, otherwise N.
> +
> +config PCI_SYSCALL
> +	def_bool PCI
> +
> +source "drivers/pci/Kconfig"
> +source "drivers/pci/pcie/Kconfig"
> +
> +endmenu
> +
>  source "fs/Kconfig"
>  source "arch/arc/Kconfig.debug"
>  source "security/Kconfig"
> diff --git a/arch/arc/include/asm/dma.h b/arch/arc/include/asm/dma.h
> index ca7c451..37942fa 100644
> --- a/arch/arc/include/asm/dma.h
> +++ b/arch/arc/include/asm/dma.h
> @@ -10,5 +10,10 @@
>  #define ASM_ARC_DMA_H
>  
>  #define MAX_DMA_ADDRESS 0xC0000000
> +#ifdef CONFIG_PCI
> +extern int isa_dma_bridge_buggy;
> +#else
> +#define isa_dma_bridge_buggy    (0)
> +#endif
>  
>  #endif
> diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
> index 694ece8..2ec3cf4 100644
> --- a/arch/arc/include/asm/io.h
> +++ b/arch/arc/include/asm/io.h
> @@ -16,7 +16,17 @@
>  extern void __iomem *ioremap(unsigned long physaddr, unsigned long size);
>  extern void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
>  				  unsigned long flags);
> +static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
> +{
> +	return (void __iomem *)port;
> +}
> +
> +static inline void ioport_unmap(void __iomem *addr)
> +{
> +}
> +
>  extern void iounmap(const void __iomem *addr);
> +extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
>  
>  #define ioremap_nocache(phy, sz)	ioremap(phy, sz)
>  #define ioremap_wc(phy, sz)		ioremap(phy, sz)
> diff --git a/arch/arc/include/asm/mach/pci.h b/arch/arc/include/asm/mach/pci.h
> new file mode 100644
> index 0000000..9e75277
> --- /dev/null
> +++ b/arch/arc/include/asm/mach/pci.h
> @@ -0,0 +1,97 @@
> +/*
> + *  arch/arc/include/asm/mach/pci.h
> + *
> + *  Copyright (C) 2004-2014 Synopsys, Inc. (www.synopsys.com)
> + *
> + * 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.
> + */
> +
> +#ifndef __ASM_MACH_PCI_H
> +#define __ASM_MACH_PCI_H
> +
> +#include <linux/ioport.h>
> +
> +struct pci_sys_data;
> +struct pci_ops;
> +struct pci_bus;
> +struct device;
> +
> +struct hw_pci {
> +#ifdef CONFIG_PCI_DOMAINS
> +	int		domain;
> +#endif
> +	struct pci_ops	*ops;
> +	int		nr_controllers;
> +	void		**private_data;
> +	int		(*setup)(int nr, struct pci_sys_data *);
> +	struct pci_bus *(*scan)(int nr, struct pci_sys_data *);
> +	void		(*preinit)(void);
> +	void		(*postinit)(void);
> +	u8		(*swizzle)(struct pci_dev *dev, u8 *pin);
> +	int		(*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
> +	resource_size_t (*align_resource)(struct pci_dev *dev,
> +					  const struct resource *res,
> +					  resource_size_t start,
> +					  resource_size_t size,
> +					  resource_size_t align);
> +	void		(*add_bus)(struct pci_bus *bus);
> +	void		(*remove_bus)(struct pci_bus *bus);
> +};
> +
> +/*
> + * Per-controller structure
> + */
> +struct pci_sys_data {
> +#ifdef CONFIG_PCI_DOMAINS
> +	int		domain;
> +#endif
> +	struct list_head node;
> +	int		busnr;		/* primary bus number		    */
> +	u64		mem_offset;	/* bus->cpu memory mapping offset   */
> +	unsigned long	io_offset;	/* bus->cpu IO mapping offset	    */
> +	struct pci_bus	*bus;		/* PCI bus			    */
> +	struct list_head resources;	/* root bus resources (apertures)   */
> +	struct resource io_res;
> +	char		io_res_name[12];
> +					/* Bridge swizzling		    */
> +	u8		(*swizzle)(struct pci_dev *, u8 *);
> +					/* IRQ mapping			    */
> +	int		(*map_irq)(const struct pci_dev *, u8, u8);
> +					/* Resource alignement requirements */
> +	resource_size_t (*align_resource)(struct pci_dev *dev,
> +					  const struct resource *res,
> +					  resource_size_t start,
> +					  resource_size_t size,
> +					  resource_size_t align);
> +	void		(*add_bus)(struct pci_bus *bus);
> +	void		(*remove_bus)(struct pci_bus *bus);
> +	void		*private_data;	/* platform controller private data */
> +};
> +
> +/*
> + * Call this with your hw_pci struct to initialise the PCI system.
> + */
> +void pci_common_init_dev(struct device *, struct hw_pci *);
> +
> +/*
> + * Compatibility wrapper for older platforms that do not care about
> + * passing the parent device.
> + */
> +static inline void pci_common_init(struct hw_pci *hw)
> +{
> +	pci_common_init_dev(NULL, hw);
> +}

All the above stuff (hw_pci, pci_sys_data, pci_common_init_dev(),
pci_common_init()) appears to be unused.

> +
> +/*
> + * Setup early fixed I/O mapping.
> + */
> +#if defined(CONFIG_PCI)
> +extern void pci_map_io_early(unsigned long pfn);
> +#else
> +static inline void pci_map_io_early(unsigned long pfn) {}
> +#endif
> +
> +#endif /* __ASM_MACH_PCI_H */
> +
> diff --git a/arch/arc/include/asm/pci.h b/arch/arc/include/asm/pci.h
> new file mode 100644
> index 0000000..085b15f
> --- /dev/null
> +++ b/arch/arc/include/asm/pci.h
> @@ -0,0 +1,34 @@
> +/*
> + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
> + *
> + * 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.
> + */
> +
> +#ifndef _ASM_ARC_PCI_H
> +#define _ASM_ARC_PCI_H
> +
> +#ifdef __KERNEL__
> +#include <asm-generic/pci-dma-compat.h>
> +#include <asm-generic/pci-bridge.h>
> +
> +#include <asm/mach/pci.h> /* for pci_sys_data */
> +
> +extern unsigned long pcibios_min_io;
> +#define PCIBIOS_MIN_IO pcibios_min_io
> +extern unsigned long pcibios_min_mem;
> +#define PCIBIOS_MIN_MEM pcibios_min_mem
> +
> +#define pcibios_assign_all_busses()	1
> +/*
> + * The PCI address space does equal the physical memory address space.
> + * The networking and block device layers use this boolean for bounce
> + * buffer decisions.
> + */
> +#define PCI_DMA_BUS_IS_PHYS     (1)
> +
> +#endif /* __KERNEL__ */
> +
> +#endif /* _ASM_ARC_PCI_H */
> +
> diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
> index e7f3625..1bc2036 100644
> --- a/arch/arc/kernel/Makefile
> +++ b/arch/arc/kernel/Makefile
> @@ -12,6 +12,7 @@ obj-y	:= arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o
>  obj-y	+= signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o clk.o
>  obj-$(CONFIG_ISA_ARCOMPACT)		+= entry-compact.o intc-compact.o
>  obj-$(CONFIG_ISA_ARCV2)			+= entry-arcv2.o intc-arcv2.o
> +obj-$(CONFIG_PCI)  			+= pcibios.o
>  
>  obj-$(CONFIG_MODULES)			+= arcksyms.o module.o
>  obj-$(CONFIG_SMP) 			+= smp.o
> diff --git a/arch/arc/kernel/pcibios.c b/arch/arc/kernel/pcibios.c
> new file mode 100644
> index 0000000..5af7bf0
> --- /dev/null
> +++ b/arch/arc/kernel/pcibios.c
> @@ -0,0 +1,358 @@
> +/*
> + * Copyright (C) 2014-2015 Synopsys, Inc. (www.synopsys.com)
> + *
> + * 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/kernel.h>
> +#include <linux/pci.h>
> +#include <linux/delay.h>
> +#include <linux/string.h>
> +#include <linux/init.h>
> +#include <linux/sched.h>
> +#include <linux/errno.h>
> +#include <linux/bootmem.h>
> +#include <linux/sizes.h>
> +#include <linux/slab.h>
> +
> +#include <asm/pci.h>
> +#include <asm/mach/pci.h>
> +
> +unsigned long pcibios_min_io = 0x100;
> +EXPORT_SYMBOL(pcibios_min_io);
> +
> +unsigned long pcibios_min_mem = 0x100000;
> +EXPORT_SYMBOL(pcibios_min_mem);
> +
> +static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
> +{
> +	int ret;
> +	struct resource_entry *window;
> +
> +	if (list_empty(&sys->resources)) {
> +		pci_add_resource_offset(&sys->resources,
> +			 &iomem_resource, sys->mem_offset);
> +	}
> +
> +	resource_list_for_each_entry(window, &sys->resources) {
> +		if (resource_type(window->res) == IORESOURCE_IO)
> +			return 0;
> +	}
> +
> +	sys->io_res.start = (busnr * SZ_64K) ?  : pcibios_min_io;
> +	sys->io_res.end = (busnr + 1) * SZ_64K - 1;
> +	sys->io_res.flags = IORESOURCE_IO;
> +	sys->io_res.name = sys->io_res_name;
> +	sprintf(sys->io_res_name, "PCI%d I/O", busnr);
> +
> +	ret = request_resource(&ioport_resource, &sys->io_res);
> +	if (ret) {
> +		pr_err("PCI: unable to allocate I/O port region (%d)\n", ret);
> +		return ret;
> +	}
> +	pci_add_resource_offset(&sys->resources, &sys->io_res,
> +				sys->io_offset);
> +
> +	return 0;
> +}

Appears unused.

> +static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
> +			    struct list_head *head)
> +{
> +	struct pci_sys_data *sys = NULL;
> +	int ret;
> +	int nr, busnr;
> +
> +	for (nr = busnr = 0; nr < hw->nr_controllers; nr++) {
> +		sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL);
> +		if (!sys)
> +			panic("PCI: unable to allocate sys data!");
> +
> +#ifdef CONFIG_PCI_DOMAINS
> +		sys->domain  = hw->domain;
> +#endif
> +		sys->busnr   = busnr;
> +		sys->swizzle = hw->swizzle;
> +		sys->map_irq = hw->map_irq;
> +		sys->align_resource = hw->align_resource;
> +		sys->add_bus = hw->add_bus;
> +		sys->remove_bus = hw->remove_bus;
> +		INIT_LIST_HEAD(&sys->resources);
> +
> +
> +		if (hw->private_data)
> +			sys->private_data = hw->private_data[nr];
> +
> +		ret = hw->setup(nr, sys);
> +
> +		if (ret > 0) {
> +			ret = pcibios_init_resources(nr, sys);
> +			if (ret)  {
> +				kfree(sys);
> +				break;
> +			}
> +
> +			if (hw->scan)
> +				sys->bus = hw->scan(nr, sys);
> +			else
> +				sys->bus = pci_scan_root_bus(parent, sys->busnr,
> +						hw->ops, sys, &sys->resources);
> +
> +			if (!sys->bus)
> +				panic("PCI: unable to scan bus!");
> +
> +			busnr = sys->bus->busn_res.end + 1;
> +
> +			list_add(&sys->node, head);
> +		} else {
> +			kfree(sys);
> +			if (ret < 0)
> +				break;
> +		}
> +	}
> +}

Appears unused.

> +int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
> +{
> +	return 0;
> +}
> +
> +void pcibios_add_bus(struct pci_bus *bus)
> +{
> +}
> +
> +void pcibios_remove_bus(struct pci_bus *bus)
> +{
> +}

The above three are Unnecessary since drivers/pci/probe.c defines
default (weak) versions.

> +/*
> + * Swizzle the device pin each time we cross a bridge.  If a platform does
> + * not provide a swizzle function, we perform the standard PCI swizzling.
> + *
> + * The default swizzling walks up the bus tree one level at a time, applying
> + * the standard swizzle function at each step, stopping when it finds the PCI
> + * root bus.  This will return the slot number of the bridge device on the
> + * root bus and the interrupt pin on that device which should correspond
> + * with the downstream device interrupt.
> + *
> + * Platforms may override this, in which case the slot and pin returned
> + * depend entirely on the platform code.  However, please note that the
> + * PCI standard swizzle is implemented on plug-in cards and Cardbus based
> + * PCI extenders, so it can not be ignored.
> + */
> +static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
> +{
> +	int slot;
> +	struct pci_sys_data *sys = dev->sysdata;
> +
> +	if (sys->swizzle)
> +		slot = sys->swizzle(dev, pin);
> +	else
> +		slot = pci_common_swizzle(dev, pin);
> +
> +	return slot;
> +}

Appears unused.

> +/*
> + * Map a slot/pin to an IRQ.
> + */
> +static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> +{
> +	struct pci_sys_data *sys = dev->sysdata;
> +	int irq = -1;
> +
> +	if (sys->map_irq)
> +		irq = sys->map_irq(dev, slot, pin);
> +
> +	return irq;
> +}

Appears unused.

> +void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
> +{
> +	struct pci_sys_data *sys;
> +	LIST_HEAD(head);
> +
> +	pci_add_flags(PCI_REASSIGN_ALL_RSRC);
> +	if (hw->preinit)
> +		hw->preinit();
> +	pcibios_init_hw(parent, hw, &head);
> +	if (hw->postinit)
> +		hw->postinit();
> +
> +	pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq);
> +
> +	list_for_each_entry(sys, &head, node) {
> +		struct pci_bus *bus = sys->bus;
> +
> +		if (!pci_has_flag(PCI_PROBE_ONLY)) {
> +			/*
> +			 * Size the bridge windows.
> +			 */
> +			pci_bus_size_bridges(bus);
> +
> +			/*
> +			 * Assign resources.
> +			 */
> +			pci_bus_assign_resources(bus);
> +		}
> +
> +		/*
> +		 * Tell drivers about devices found.
> +		 */
> +		pci_bus_add_devices(bus);
> +	}
> +}

Appears unused.

> +/*
> + * 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;
> +}
> +
> +/**
> + * pcibios_enable_device - Enable I/O and memory.
> + * @dev: PCI device to be enabled
> + */
> +int pcibios_enable_device(struct pci_dev *pci_dev, int mask)
> +{
> +	u16 cmd, old_cmd;
> +	int idx;
> +	struct resource *r;
> +
> +	pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
> +	old_cmd = cmd;
> +	for (idx = 0; idx < 6; idx++) {
> +		/* Only set up the requested stuff */
> +		if (!(mask & (1 << idx)))
> +			continue;
> +
> +		r = pci_dev->resource + idx;
> +		if (!r->start && r->end) {
> +			dev_err(&pci_dev->dev, "PCI: Device %s not available\n",
> +							pci_name(pci_dev));
> +			return -EINVAL;
> +		}
> +		if (r->flags & IORESOURCE_IO)
> +			cmd |= PCI_COMMAND_IO;
> +		if (r->flags & IORESOURCE_MEM)
> +			cmd |= PCI_COMMAND_MEMORY;
> +	}
> +
> +	/*
> +	 * Bridges (eg, cardbus bridges) need to be fully enabled
> +	 */
> +	if ((pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
> +		cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
> +
> +	if (cmd != old_cmd) {
> +		pr_info("PCI: enabling device %s (%04x -> %04x)\n",
> +		       pci_name(pci_dev), old_cmd, cmd);
> +		pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
> +	}
> +	return 0;
> +}

There's a default (weak) version of pcibios_enable_device().  You
should omit this definition and use the default unless your arch
requires something special.

> +
> +/*
> + * If the bus contains any of these devices, then we must not turn on
> + * parity checking of any kind.  Currently this is CyberPro 20x0 only.
> + */
> +static inline int pdev_bad_for_parity(struct pci_dev *dev)
> +{
> +	return ((dev->vendor == PCI_VENDOR_ID_INTERG &&
> +		 (dev->device == PCI_DEVICE_ID_INTERG_2000 ||
> +		  dev->device == PCI_DEVICE_ID_INTERG_2010)) ||
> +		(dev->vendor == PCI_VENDOR_ID_ITE &&
> +		 dev->device == PCI_DEVICE_ID_ITE_8152));
> +
> +}
> +
> +/*
> + * pcibios_fixup_bus - Called after each bus is probed,
> + * but before its children are examined.
> + */
> +void pcibios_fixup_bus(struct pci_bus *bus)
> +{
> +	struct pci_dev *dev;
> +	u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY
> +			| PCI_COMMAND_FAST_BACK;
> +
> +	/*
> +	 * Walk the devices on this bus, working out what we can
> +	 * and can't support.
> +	 */
> +	list_for_each_entry(dev, &bus->devices, bus_list) {
> +		u16 status;
> +
> +		pci_read_config_word(dev, PCI_STATUS, &status);
> +
> +		/*
> +		 * If any device on this bus does not support fast back
> +		 * to back transfers, then the bus as a whole is not able
> +		 * to support them.  Having fast back to back transfers
> +		 * on saves us one PCI cycle per transaction.
> +		 */
> +		if (!(status & PCI_STATUS_FAST_BACK))
> +			features &= ~PCI_COMMAND_FAST_BACK;
> +
> +		if (pdev_bad_for_parity(dev))
> +			features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
> +
> +		switch (dev->class >> 8) {
> +		case PCI_CLASS_BRIDGE_PCI:
> +			pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status);
> +			status |= PCI_BRIDGE_CTL_PARITY
> +					|PCI_BRIDGE_CTL_MASTER_ABORT;
> +			status &= ~(PCI_BRIDGE_CTL_BUS_RESET
> +					|PCI_BRIDGE_CTL_FAST_BACK);
> +			pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status);
> +			break;
> +
> +		case PCI_CLASS_BRIDGE_CARDBUS:
> +			pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL,
> +						&status);
> +			status |= PCI_CB_BRIDGE_CTL_PARITY
> +					|PCI_CB_BRIDGE_CTL_MASTER_ABORT;
> +			pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL,
> +						status);
> +			break;
> +		}
> +	}
> +
> +	/*
> +	 * Now walk the devices again, this time setting them up.
> +	 */
> +	list_for_each_entry(dev, &bus->devices, bus_list) {
> +		u16 cmd;
> +
> +		pci_read_config_word(dev, PCI_COMMAND, &cmd);
> +		cmd |= features;
> +		pci_write_config_word(dev, PCI_COMMAND, cmd);
> +
> +		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
> +				      L1_CACHE_BYTES >> 2);
> +	}
> +
> +	/*
> +	 * Propagate the flags to the PCI bridge.
> +	 */
> +	if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
> +		if (features & PCI_COMMAND_FAST_BACK)
> +			bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK;
> +		if (features & PCI_COMMAND_PARITY)
> +			bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY;
> +	}
> +
> +	/*
> +	 * Report what we did for this bus
> +	 */
> +	pr_info("PCI: bus%d: Fast back to back transfers %sabled\n",
> +		bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
> +}
> +EXPORT_SYMBOL(pcibios_fixup_bus);

This pcibios_fixup_bus() implementation has been blindly copied all
over the place, but I don't think it's relevant for most arches.  I
think you could probably make it an empty function as on arm64.

> diff --git a/arch/arc/mm/ioremap.c b/arch/arc/mm/ioremap.c
> index 739e65f..fe807b0 100644
> --- a/arch/arc/mm/ioremap.c
> +++ b/arch/arc/mm/ioremap.c
> @@ -13,6 +13,7 @@
>  #include <linux/mm.h>
>  #include <linux/slab.h>
>  #include <linux/cache.h>
> +#include <linux/sizes.h>
>  
>  void __iomem *ioremap(unsigned long paddr, unsigned long size)
>  {
> @@ -80,7 +81,6 @@ void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size,
>  }
>  EXPORT_SYMBOL(ioremap_prot);
>  
> -
>  void iounmap(const void __iomem *addr)
>  {
>  	if (addr >= (void __force __iomem *)ARC_UNCACHED_ADDR_SPACE)
> @@ -89,3 +89,11 @@ void iounmap(const void __iomem *addr)
>  	vfree((void *)(PAGE_MASK & (unsigned long __force)addr));
>  }
>  EXPORT_SYMBOL(iounmap);
> +
> +#ifdef CONFIG_PCI
> +int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
> +{
> +	return ioremap_nocache(phys_addr + offset,  SZ_64K);
> +}
> +EXPORT_SYMBOL_GPL(pci_ioremap_io);
> +#endif
> diff --git a/arch/arc/plat-axs10x/Kconfig b/arch/arc/plat-axs10x/Kconfig
> index d475f9d..426ac4b 100644
> --- a/arch/arc/plat-axs10x/Kconfig
> +++ b/arch/arc/plat-axs10x/Kconfig
> @@ -11,6 +11,7 @@ menuconfig ARC_PLAT_AXS10X
>  	select DW_APB_ICTL
>  	select GPIO_DWAPB
>  	select OF_GPIO
> +	select MIGHT_HAVE_PCI
>  	select GENERIC_IRQ_CHIP
>  	select ARCH_REQUIRE_GPIOLIB
>  	help
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index be3f631..2154092 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_PCI_IOV) += iov.o
>  # Some architectures use the generic PCI setup functions
>  #
>  obj-$(CONFIG_ALPHA) += setup-irq.o
> +obj-$(CONFIG_ARC) += setup-irq.o
>  obj-$(CONFIG_ARM) += setup-irq.o
>  obj-$(CONFIG_ARM64) += setup-irq.o
>  obj-$(CONFIG_UNICORE32) += setup-irq.o
> -- 
> 1.8.1.5
> 
> --
> 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
--
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
Joao Pinto Dec. 18, 2015, 11:11 a.m. UTC | #2
Hi Bjorn,

Thanks for the review. I am going to simplify the code and send a v3 patch set.

Joao

On 12/17/2015 9:11 PM, Bjorn Helgaas wrote:
> On Wed, Dec 16, 2015 at 02:14:55PM +0000, Joao Pinto wrote:
>> This patch adds PCI support to ARC and updates drivers/pci Makefile enabling
>> the ARC arch to use the generic PCI setup functions.
>>
>> Signed-off-by: Joao Pinto <jpinto@synopsys.com>
> 
> Checkpatch complains about some whitespace errors (new blank lines at
> EOF).
> 
> Hmmm, almost all of this appears to be copied straight from arch/arm,
> but almost none of it is actually used.  If that's true, it's good
> because you can make the patches much smaller.  But it's a little bit
> bad, too, because it means we almost merged a bunch of dead code.
> 
>> ---
>> Change v1 -> v2:
>> - In arch/arc/Kconfig, the new menu entry (Bus Configuration) was moved to the
>> slot between sourcing of drivers/Kconfig and fs/Kconfig (Vineet Gupta)
>> - In arch/arc/plat-axs10x/Kconfig the "select MIGHT_HAVE_PCI" option was placed
>> in order as suggested (Vineet Gupta)
>> - ioport_map() and ioport_unmap() were static inlined and included in
>> the io.h (Vineet Gupta)
>> - pcibios_min_io and pcibios_min_mem declaration moved to
>> pcibios.c (Vineet Gupta)
>> - pr_err() replaced by dev_err() in pcibios_enable_device() (Bjorn Helgaas)
>> - string simplified in pcibios_enable_device() (Vineet Gupta)
>> - pci_host_bridge_window structure was replaced by resource_entry structure, and
>> list_for_each_entry() for resource_list_for_each_entry() in pcibios.c
>>
>>  arch/arc/Kconfig                |  23 +++
>>  arch/arc/include/asm/dma.h      |   5 +
>>  arch/arc/include/asm/io.h       |  10 ++
>>  arch/arc/include/asm/mach/pci.h |  97 +++++++++++
>>  arch/arc/include/asm/pci.h      |  34 ++++
>>  arch/arc/kernel/Makefile        |   1 +
>>  arch/arc/kernel/pcibios.c       | 358 ++++++++++++++++++++++++++++++++++++++++
>>  arch/arc/mm/ioremap.c           |  10 +-
>>  arch/arc/plat-axs10x/Kconfig    |   1 +
>>  drivers/pci/Makefile            |   1 +
>>  10 files changed, 539 insertions(+), 1 deletion(-)
>>  create mode 100644 arch/arc/include/asm/mach/pci.h
>>  create mode 100644 arch/arc/include/asm/pci.h
>>  create mode 100644 arch/arc/kernel/pcibios.c
>>
>> diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
>> index 2c2ac3f..98b32c1 100644
>> --- a/arch/arc/Kconfig
>> +++ b/arch/arc/Kconfig
>> @@ -19,6 +19,7 @@ config ARC
>>  	select GENERIC_FIND_FIRST_BIT
>>  	# for now, we don't need GENERIC_IRQ_PROBE, CONFIG_GENERIC_IRQ_CHIP
>>  	select GENERIC_IRQ_SHOW
>> +	select GENERIC_PCI_IOMAP
>>  	select GENERIC_PENDING_IRQ if SMP
>>  	select GENERIC_SMP_IDLE_THREAD
>>  	select HAVE_ARCH_KGDB
>> @@ -39,6 +40,9 @@ config ARC
>>  	select PERF_USE_VMALLOC
>>  	select HAVE_DEBUG_STACKOVERFLOW
>>  
>> +config MIGHT_HAVE_PCI
>> +	bool
>> +
>>  config TRACE_IRQFLAGS_SUPPORT
>>  	def_bool y
>>  
>> @@ -570,6 +574,25 @@ endmenu	 # "ARC Architecture Configuration"
>>  source "mm/Kconfig"
>>  source "net/Kconfig"
>>  source "drivers/Kconfig"
>> +
>> +menu "Bus Support"
>> +
>> +config PCI
>> +	bool "PCI support" if MIGHT_HAVE_PCI
>> +	help
>> +	  PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside
>> +	  your box.Find out if your board/platform have PCI.
>> +	  Note: PCIE support for Synopsys Device will be available only when
>> +	  HAPS DX is configured with PCIE RC bitmap. If you have PCI, say Y, otherwise N.
>> +
>> +config PCI_SYSCALL
>> +	def_bool PCI
>> +
>> +source "drivers/pci/Kconfig"
>> +source "drivers/pci/pcie/Kconfig"
>> +
>> +endmenu
>> +
>>  source "fs/Kconfig"
>>  source "arch/arc/Kconfig.debug"
>>  source "security/Kconfig"
>> diff --git a/arch/arc/include/asm/dma.h b/arch/arc/include/asm/dma.h
>> index ca7c451..37942fa 100644
>> --- a/arch/arc/include/asm/dma.h
>> +++ b/arch/arc/include/asm/dma.h
>> @@ -10,5 +10,10 @@
>>  #define ASM_ARC_DMA_H
>>  
>>  #define MAX_DMA_ADDRESS 0xC0000000
>> +#ifdef CONFIG_PCI
>> +extern int isa_dma_bridge_buggy;
>> +#else
>> +#define isa_dma_bridge_buggy    (0)
>> +#endif
>>  
>>  #endif
>> diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
>> index 694ece8..2ec3cf4 100644
>> --- a/arch/arc/include/asm/io.h
>> +++ b/arch/arc/include/asm/io.h
>> @@ -16,7 +16,17 @@
>>  extern void __iomem *ioremap(unsigned long physaddr, unsigned long size);
>>  extern void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
>>  				  unsigned long flags);
>> +static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
>> +{
>> +	return (void __iomem *)port;
>> +}
>> +
>> +static inline void ioport_unmap(void __iomem *addr)
>> +{
>> +}
>> +
>>  extern void iounmap(const void __iomem *addr);
>> +extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
>>  
>>  #define ioremap_nocache(phy, sz)	ioremap(phy, sz)
>>  #define ioremap_wc(phy, sz)		ioremap(phy, sz)
>> diff --git a/arch/arc/include/asm/mach/pci.h b/arch/arc/include/asm/mach/pci.h
>> new file mode 100644
>> index 0000000..9e75277
>> --- /dev/null
>> +++ b/arch/arc/include/asm/mach/pci.h
>> @@ -0,0 +1,97 @@
>> +/*
>> + *  arch/arc/include/asm/mach/pci.h
>> + *
>> + *  Copyright (C) 2004-2014 Synopsys, Inc. (www.synopsys.com)
>> + *
>> + * 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.
>> + */
>> +
>> +#ifndef __ASM_MACH_PCI_H
>> +#define __ASM_MACH_PCI_H
>> +
>> +#include <linux/ioport.h>
>> +
>> +struct pci_sys_data;
>> +struct pci_ops;
>> +struct pci_bus;
>> +struct device;
>> +
>> +struct hw_pci {
>> +#ifdef CONFIG_PCI_DOMAINS
>> +	int		domain;
>> +#endif
>> +	struct pci_ops	*ops;
>> +	int		nr_controllers;
>> +	void		**private_data;
>> +	int		(*setup)(int nr, struct pci_sys_data *);
>> +	struct pci_bus *(*scan)(int nr, struct pci_sys_data *);
>> +	void		(*preinit)(void);
>> +	void		(*postinit)(void);
>> +	u8		(*swizzle)(struct pci_dev *dev, u8 *pin);
>> +	int		(*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
>> +	resource_size_t (*align_resource)(struct pci_dev *dev,
>> +					  const struct resource *res,
>> +					  resource_size_t start,
>> +					  resource_size_t size,
>> +					  resource_size_t align);
>> +	void		(*add_bus)(struct pci_bus *bus);
>> +	void		(*remove_bus)(struct pci_bus *bus);
>> +};
>> +
>> +/*
>> + * Per-controller structure
>> + */
>> +struct pci_sys_data {
>> +#ifdef CONFIG_PCI_DOMAINS
>> +	int		domain;
>> +#endif
>> +	struct list_head node;
>> +	int		busnr;		/* primary bus number		    */
>> +	u64		mem_offset;	/* bus->cpu memory mapping offset   */
>> +	unsigned long	io_offset;	/* bus->cpu IO mapping offset	    */
>> +	struct pci_bus	*bus;		/* PCI bus			    */
>> +	struct list_head resources;	/* root bus resources (apertures)   */
>> +	struct resource io_res;
>> +	char		io_res_name[12];
>> +					/* Bridge swizzling		    */
>> +	u8		(*swizzle)(struct pci_dev *, u8 *);
>> +					/* IRQ mapping			    */
>> +	int		(*map_irq)(const struct pci_dev *, u8, u8);
>> +					/* Resource alignement requirements */
>> +	resource_size_t (*align_resource)(struct pci_dev *dev,
>> +					  const struct resource *res,
>> +					  resource_size_t start,
>> +					  resource_size_t size,
>> +					  resource_size_t align);
>> +	void		(*add_bus)(struct pci_bus *bus);
>> +	void		(*remove_bus)(struct pci_bus *bus);
>> +	void		*private_data;	/* platform controller private data */
>> +};
>> +
>> +/*
>> + * Call this with your hw_pci struct to initialise the PCI system.
>> + */
>> +void pci_common_init_dev(struct device *, struct hw_pci *);
>> +
>> +/*
>> + * Compatibility wrapper for older platforms that do not care about
>> + * passing the parent device.
>> + */
>> +static inline void pci_common_init(struct hw_pci *hw)
>> +{
>> +	pci_common_init_dev(NULL, hw);
>> +}
> 
> All the above stuff (hw_pci, pci_sys_data, pci_common_init_dev(),
> pci_common_init()) appears to be unused.
> 
>> +
>> +/*
>> + * Setup early fixed I/O mapping.
>> + */
>> +#if defined(CONFIG_PCI)
>> +extern void pci_map_io_early(unsigned long pfn);
>> +#else
>> +static inline void pci_map_io_early(unsigned long pfn) {}
>> +#endif
>> +
>> +#endif /* __ASM_MACH_PCI_H */
>> +
>> diff --git a/arch/arc/include/asm/pci.h b/arch/arc/include/asm/pci.h
>> new file mode 100644
>> index 0000000..085b15f
>> --- /dev/null
>> +++ b/arch/arc/include/asm/pci.h
>> @@ -0,0 +1,34 @@
>> +/*
>> + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
>> + *
>> + * 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.
>> + */
>> +
>> +#ifndef _ASM_ARC_PCI_H
>> +#define _ASM_ARC_PCI_H
>> +
>> +#ifdef __KERNEL__
>> +#include <asm-generic/pci-dma-compat.h>
>> +#include <asm-generic/pci-bridge.h>
>> +
>> +#include <asm/mach/pci.h> /* for pci_sys_data */
>> +
>> +extern unsigned long pcibios_min_io;
>> +#define PCIBIOS_MIN_IO pcibios_min_io
>> +extern unsigned long pcibios_min_mem;
>> +#define PCIBIOS_MIN_MEM pcibios_min_mem
>> +
>> +#define pcibios_assign_all_busses()	1
>> +/*
>> + * The PCI address space does equal the physical memory address space.
>> + * The networking and block device layers use this boolean for bounce
>> + * buffer decisions.
>> + */
>> +#define PCI_DMA_BUS_IS_PHYS     (1)
>> +
>> +#endif /* __KERNEL__ */
>> +
>> +#endif /* _ASM_ARC_PCI_H */
>> +
>> diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
>> index e7f3625..1bc2036 100644
>> --- a/arch/arc/kernel/Makefile
>> +++ b/arch/arc/kernel/Makefile
>> @@ -12,6 +12,7 @@ obj-y	:= arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o
>>  obj-y	+= signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o clk.o
>>  obj-$(CONFIG_ISA_ARCOMPACT)		+= entry-compact.o intc-compact.o
>>  obj-$(CONFIG_ISA_ARCV2)			+= entry-arcv2.o intc-arcv2.o
>> +obj-$(CONFIG_PCI)  			+= pcibios.o
>>  
>>  obj-$(CONFIG_MODULES)			+= arcksyms.o module.o
>>  obj-$(CONFIG_SMP) 			+= smp.o
>> diff --git a/arch/arc/kernel/pcibios.c b/arch/arc/kernel/pcibios.c
>> new file mode 100644
>> index 0000000..5af7bf0
>> --- /dev/null
>> +++ b/arch/arc/kernel/pcibios.c
>> @@ -0,0 +1,358 @@
>> +/*
>> + * Copyright (C) 2014-2015 Synopsys, Inc. (www.synopsys.com)
>> + *
>> + * 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/kernel.h>
>> +#include <linux/pci.h>
>> +#include <linux/delay.h>
>> +#include <linux/string.h>
>> +#include <linux/init.h>
>> +#include <linux/sched.h>
>> +#include <linux/errno.h>
>> +#include <linux/bootmem.h>
>> +#include <linux/sizes.h>
>> +#include <linux/slab.h>
>> +
>> +#include <asm/pci.h>
>> +#include <asm/mach/pci.h>
>> +
>> +unsigned long pcibios_min_io = 0x100;
>> +EXPORT_SYMBOL(pcibios_min_io);
>> +
>> +unsigned long pcibios_min_mem = 0x100000;
>> +EXPORT_SYMBOL(pcibios_min_mem);
>> +
>> +static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
>> +{
>> +	int ret;
>> +	struct resource_entry *window;
>> +
>> +	if (list_empty(&sys->resources)) {
>> +		pci_add_resource_offset(&sys->resources,
>> +			 &iomem_resource, sys->mem_offset);
>> +	}
>> +
>> +	resource_list_for_each_entry(window, &sys->resources) {
>> +		if (resource_type(window->res) == IORESOURCE_IO)
>> +			return 0;
>> +	}
>> +
>> +	sys->io_res.start = (busnr * SZ_64K) ?  : pcibios_min_io;
>> +	sys->io_res.end = (busnr + 1) * SZ_64K - 1;
>> +	sys->io_res.flags = IORESOURCE_IO;
>> +	sys->io_res.name = sys->io_res_name;
>> +	sprintf(sys->io_res_name, "PCI%d I/O", busnr);
>> +
>> +	ret = request_resource(&ioport_resource, &sys->io_res);
>> +	if (ret) {
>> +		pr_err("PCI: unable to allocate I/O port region (%d)\n", ret);
>> +		return ret;
>> +	}
>> +	pci_add_resource_offset(&sys->resources, &sys->io_res,
>> +				sys->io_offset);
>> +
>> +	return 0;
>> +}
> 
> Appears unused.
> 
>> +static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
>> +			    struct list_head *head)
>> +{
>> +	struct pci_sys_data *sys = NULL;
>> +	int ret;
>> +	int nr, busnr;
>> +
>> +	for (nr = busnr = 0; nr < hw->nr_controllers; nr++) {
>> +		sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL);
>> +		if (!sys)
>> +			panic("PCI: unable to allocate sys data!");
>> +
>> +#ifdef CONFIG_PCI_DOMAINS
>> +		sys->domain  = hw->domain;
>> +#endif
>> +		sys->busnr   = busnr;
>> +		sys->swizzle = hw->swizzle;
>> +		sys->map_irq = hw->map_irq;
>> +		sys->align_resource = hw->align_resource;
>> +		sys->add_bus = hw->add_bus;
>> +		sys->remove_bus = hw->remove_bus;
>> +		INIT_LIST_HEAD(&sys->resources);
>> +
>> +
>> +		if (hw->private_data)
>> +			sys->private_data = hw->private_data[nr];
>> +
>> +		ret = hw->setup(nr, sys);
>> +
>> +		if (ret > 0) {
>> +			ret = pcibios_init_resources(nr, sys);
>> +			if (ret)  {
>> +				kfree(sys);
>> +				break;
>> +			}
>> +
>> +			if (hw->scan)
>> +				sys->bus = hw->scan(nr, sys);
>> +			else
>> +				sys->bus = pci_scan_root_bus(parent, sys->busnr,
>> +						hw->ops, sys, &sys->resources);
>> +
>> +			if (!sys->bus)
>> +				panic("PCI: unable to scan bus!");
>> +
>> +			busnr = sys->bus->busn_res.end + 1;
>> +
>> +			list_add(&sys->node, head);
>> +		} else {
>> +			kfree(sys);
>> +			if (ret < 0)
>> +				break;
>> +		}
>> +	}
>> +}
> 
> Appears unused.
> 
>> +int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
>> +{
>> +	return 0;
>> +}
>> +
>> +void pcibios_add_bus(struct pci_bus *bus)
>> +{
>> +}
>> +
>> +void pcibios_remove_bus(struct pci_bus *bus)
>> +{
>> +}
> 
> The above three are Unnecessary since drivers/pci/probe.c defines
> default (weak) versions.
> 
>> +/*
>> + * Swizzle the device pin each time we cross a bridge.  If a platform does
>> + * not provide a swizzle function, we perform the standard PCI swizzling.
>> + *
>> + * The default swizzling walks up the bus tree one level at a time, applying
>> + * the standard swizzle function at each step, stopping when it finds the PCI
>> + * root bus.  This will return the slot number of the bridge device on the
>> + * root bus and the interrupt pin on that device which should correspond
>> + * with the downstream device interrupt.
>> + *
>> + * Platforms may override this, in which case the slot and pin returned
>> + * depend entirely on the platform code.  However, please note that the
>> + * PCI standard swizzle is implemented on plug-in cards and Cardbus based
>> + * PCI extenders, so it can not be ignored.
>> + */
>> +static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
>> +{
>> +	int slot;
>> +	struct pci_sys_data *sys = dev->sysdata;
>> +
>> +	if (sys->swizzle)
>> +		slot = sys->swizzle(dev, pin);
>> +	else
>> +		slot = pci_common_swizzle(dev, pin);
>> +
>> +	return slot;
>> +}
> 
> Appears unused.
> 
>> +/*
>> + * Map a slot/pin to an IRQ.
>> + */
>> +static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
>> +{
>> +	struct pci_sys_data *sys = dev->sysdata;
>> +	int irq = -1;
>> +
>> +	if (sys->map_irq)
>> +		irq = sys->map_irq(dev, slot, pin);
>> +
>> +	return irq;
>> +}
> 
> Appears unused.
> 
>> +void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
>> +{
>> +	struct pci_sys_data *sys;
>> +	LIST_HEAD(head);
>> +
>> +	pci_add_flags(PCI_REASSIGN_ALL_RSRC);
>> +	if (hw->preinit)
>> +		hw->preinit();
>> +	pcibios_init_hw(parent, hw, &head);
>> +	if (hw->postinit)
>> +		hw->postinit();
>> +
>> +	pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq);
>> +
>> +	list_for_each_entry(sys, &head, node) {
>> +		struct pci_bus *bus = sys->bus;
>> +
>> +		if (!pci_has_flag(PCI_PROBE_ONLY)) {
>> +			/*
>> +			 * Size the bridge windows.
>> +			 */
>> +			pci_bus_size_bridges(bus);
>> +
>> +			/*
>> +			 * Assign resources.
>> +			 */
>> +			pci_bus_assign_resources(bus);
>> +		}
>> +
>> +		/*
>> +		 * Tell drivers about devices found.
>> +		 */
>> +		pci_bus_add_devices(bus);
>> +	}
>> +}
> 
> Appears unused.
> 
>> +/*
>> + * 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;
>> +}
>> +
>> +/**
>> + * pcibios_enable_device - Enable I/O and memory.
>> + * @dev: PCI device to be enabled
>> + */
>> +int pcibios_enable_device(struct pci_dev *pci_dev, int mask)
>> +{
>> +	u16 cmd, old_cmd;
>> +	int idx;
>> +	struct resource *r;
>> +
>> +	pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
>> +	old_cmd = cmd;
>> +	for (idx = 0; idx < 6; idx++) {
>> +		/* Only set up the requested stuff */
>> +		if (!(mask & (1 << idx)))
>> +			continue;
>> +
>> +		r = pci_dev->resource + idx;
>> +		if (!r->start && r->end) {
>> +			dev_err(&pci_dev->dev, "PCI: Device %s not available\n",
>> +							pci_name(pci_dev));
>> +			return -EINVAL;
>> +		}
>> +		if (r->flags & IORESOURCE_IO)
>> +			cmd |= PCI_COMMAND_IO;
>> +		if (r->flags & IORESOURCE_MEM)
>> +			cmd |= PCI_COMMAND_MEMORY;
>> +	}
>> +
>> +	/*
>> +	 * Bridges (eg, cardbus bridges) need to be fully enabled
>> +	 */
>> +	if ((pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
>> +		cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
>> +
>> +	if (cmd != old_cmd) {
>> +		pr_info("PCI: enabling device %s (%04x -> %04x)\n",
>> +		       pci_name(pci_dev), old_cmd, cmd);
>> +		pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
>> +	}
>> +	return 0;
>> +}
> 
> There's a default (weak) version of pcibios_enable_device().  You
> should omit this definition and use the default unless your arch
> requires something special.
> 
>> +
>> +/*
>> + * If the bus contains any of these devices, then we must not turn on
>> + * parity checking of any kind.  Currently this is CyberPro 20x0 only.
>> + */
>> +static inline int pdev_bad_for_parity(struct pci_dev *dev)
>> +{
>> +	return ((dev->vendor == PCI_VENDOR_ID_INTERG &&
>> +		 (dev->device == PCI_DEVICE_ID_INTERG_2000 ||
>> +		  dev->device == PCI_DEVICE_ID_INTERG_2010)) ||
>> +		(dev->vendor == PCI_VENDOR_ID_ITE &&
>> +		 dev->device == PCI_DEVICE_ID_ITE_8152));
>> +
>> +}
>> +
>> +/*
>> + * pcibios_fixup_bus - Called after each bus is probed,
>> + * but before its children are examined.
>> + */
>> +void pcibios_fixup_bus(struct pci_bus *bus)
>> +{
>> +	struct pci_dev *dev;
>> +	u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY
>> +			| PCI_COMMAND_FAST_BACK;
>> +
>> +	/*
>> +	 * Walk the devices on this bus, working out what we can
>> +	 * and can't support.
>> +	 */
>> +	list_for_each_entry(dev, &bus->devices, bus_list) {
>> +		u16 status;
>> +
>> +		pci_read_config_word(dev, PCI_STATUS, &status);
>> +
>> +		/*
>> +		 * If any device on this bus does not support fast back
>> +		 * to back transfers, then the bus as a whole is not able
>> +		 * to support them.  Having fast back to back transfers
>> +		 * on saves us one PCI cycle per transaction.
>> +		 */
>> +		if (!(status & PCI_STATUS_FAST_BACK))
>> +			features &= ~PCI_COMMAND_FAST_BACK;
>> +
>> +		if (pdev_bad_for_parity(dev))
>> +			features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
>> +
>> +		switch (dev->class >> 8) {
>> +		case PCI_CLASS_BRIDGE_PCI:
>> +			pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status);
>> +			status |= PCI_BRIDGE_CTL_PARITY
>> +					|PCI_BRIDGE_CTL_MASTER_ABORT;
>> +			status &= ~(PCI_BRIDGE_CTL_BUS_RESET
>> +					|PCI_BRIDGE_CTL_FAST_BACK);
>> +			pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status);
>> +			break;
>> +
>> +		case PCI_CLASS_BRIDGE_CARDBUS:
>> +			pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL,
>> +						&status);
>> +			status |= PCI_CB_BRIDGE_CTL_PARITY
>> +					|PCI_CB_BRIDGE_CTL_MASTER_ABORT;
>> +			pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL,
>> +						status);
>> +			break;
>> +		}
>> +	}
>> +
>> +	/*
>> +	 * Now walk the devices again, this time setting them up.
>> +	 */
>> +	list_for_each_entry(dev, &bus->devices, bus_list) {
>> +		u16 cmd;
>> +
>> +		pci_read_config_word(dev, PCI_COMMAND, &cmd);
>> +		cmd |= features;
>> +		pci_write_config_word(dev, PCI_COMMAND, cmd);
>> +
>> +		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
>> +				      L1_CACHE_BYTES >> 2);
>> +	}
>> +
>> +	/*
>> +	 * Propagate the flags to the PCI bridge.
>> +	 */
>> +	if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
>> +		if (features & PCI_COMMAND_FAST_BACK)
>> +			bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK;
>> +		if (features & PCI_COMMAND_PARITY)
>> +			bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY;
>> +	}
>> +
>> +	/*
>> +	 * Report what we did for this bus
>> +	 */
>> +	pr_info("PCI: bus%d: Fast back to back transfers %sabled\n",
>> +		bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
>> +}
>> +EXPORT_SYMBOL(pcibios_fixup_bus);
> 
> This pcibios_fixup_bus() implementation has been blindly copied all
> over the place, but I don't think it's relevant for most arches.  I
> think you could probably make it an empty function as on arm64.
> 
>> diff --git a/arch/arc/mm/ioremap.c b/arch/arc/mm/ioremap.c
>> index 739e65f..fe807b0 100644
>> --- a/arch/arc/mm/ioremap.c
>> +++ b/arch/arc/mm/ioremap.c
>> @@ -13,6 +13,7 @@
>>  #include <linux/mm.h>
>>  #include <linux/slab.h>
>>  #include <linux/cache.h>
>> +#include <linux/sizes.h>
>>  
>>  void __iomem *ioremap(unsigned long paddr, unsigned long size)
>>  {
>> @@ -80,7 +81,6 @@ void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size,
>>  }
>>  EXPORT_SYMBOL(ioremap_prot);
>>  
>> -
>>  void iounmap(const void __iomem *addr)
>>  {
>>  	if (addr >= (void __force __iomem *)ARC_UNCACHED_ADDR_SPACE)
>> @@ -89,3 +89,11 @@ void iounmap(const void __iomem *addr)
>>  	vfree((void *)(PAGE_MASK & (unsigned long __force)addr));
>>  }
>>  EXPORT_SYMBOL(iounmap);
>> +
>> +#ifdef CONFIG_PCI
>> +int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
>> +{
>> +	return ioremap_nocache(phys_addr + offset,  SZ_64K);
>> +}
>> +EXPORT_SYMBOL_GPL(pci_ioremap_io);
>> +#endif
>> diff --git a/arch/arc/plat-axs10x/Kconfig b/arch/arc/plat-axs10x/Kconfig
>> index d475f9d..426ac4b 100644
>> --- a/arch/arc/plat-axs10x/Kconfig
>> +++ b/arch/arc/plat-axs10x/Kconfig
>> @@ -11,6 +11,7 @@ menuconfig ARC_PLAT_AXS10X
>>  	select DW_APB_ICTL
>>  	select GPIO_DWAPB
>>  	select OF_GPIO
>> +	select MIGHT_HAVE_PCI
>>  	select GENERIC_IRQ_CHIP
>>  	select ARCH_REQUIRE_GPIOLIB
>>  	help
>> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
>> index be3f631..2154092 100644
>> --- a/drivers/pci/Makefile
>> +++ b/drivers/pci/Makefile
>> @@ -32,6 +32,7 @@ obj-$(CONFIG_PCI_IOV) += iov.o
>>  # Some architectures use the generic PCI setup functions
>>  #
>>  obj-$(CONFIG_ALPHA) += setup-irq.o
>> +obj-$(CONFIG_ARC) += setup-irq.o
>>  obj-$(CONFIG_ARM) += setup-irq.o
>>  obj-$(CONFIG_ARM64) += setup-irq.o
>>  obj-$(CONFIG_UNICORE32) += setup-irq.o
>> -- 
>> 1.8.1.5
>>
>> --
>> 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

--
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
diff mbox

Patch

diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 2c2ac3f..98b32c1 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -19,6 +19,7 @@  config ARC
 	select GENERIC_FIND_FIRST_BIT
 	# for now, we don't need GENERIC_IRQ_PROBE, CONFIG_GENERIC_IRQ_CHIP
 	select GENERIC_IRQ_SHOW
+	select GENERIC_PCI_IOMAP
 	select GENERIC_PENDING_IRQ if SMP
 	select GENERIC_SMP_IDLE_THREAD
 	select HAVE_ARCH_KGDB
@@ -39,6 +40,9 @@  config ARC
 	select PERF_USE_VMALLOC
 	select HAVE_DEBUG_STACKOVERFLOW
 
+config MIGHT_HAVE_PCI
+	bool
+
 config TRACE_IRQFLAGS_SUPPORT
 	def_bool y
 
@@ -570,6 +574,25 @@  endmenu	 # "ARC Architecture Configuration"
 source "mm/Kconfig"
 source "net/Kconfig"
 source "drivers/Kconfig"
+
+menu "Bus Support"
+
+config PCI
+	bool "PCI support" if MIGHT_HAVE_PCI
+	help
+	  PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside
+	  your box.Find out if your board/platform have PCI.
+	  Note: PCIE support for Synopsys Device will be available only when
+	  HAPS DX is configured with PCIE RC bitmap. If you have PCI, say Y, otherwise N.
+
+config PCI_SYSCALL
+	def_bool PCI
+
+source "drivers/pci/Kconfig"
+source "drivers/pci/pcie/Kconfig"
+
+endmenu
+
 source "fs/Kconfig"
 source "arch/arc/Kconfig.debug"
 source "security/Kconfig"
diff --git a/arch/arc/include/asm/dma.h b/arch/arc/include/asm/dma.h
index ca7c451..37942fa 100644
--- a/arch/arc/include/asm/dma.h
+++ b/arch/arc/include/asm/dma.h
@@ -10,5 +10,10 @@ 
 #define ASM_ARC_DMA_H
 
 #define MAX_DMA_ADDRESS 0xC0000000
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy    (0)
+#endif
 
 #endif
diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
index 694ece8..2ec3cf4 100644
--- a/arch/arc/include/asm/io.h
+++ b/arch/arc/include/asm/io.h
@@ -16,7 +16,17 @@ 
 extern void __iomem *ioremap(unsigned long physaddr, unsigned long size);
 extern void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
 				  unsigned long flags);
+static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+	return (void __iomem *)port;
+}
+
+static inline void ioport_unmap(void __iomem *addr)
+{
+}
+
 extern void iounmap(const void __iomem *addr);
+extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
 
 #define ioremap_nocache(phy, sz)	ioremap(phy, sz)
 #define ioremap_wc(phy, sz)		ioremap(phy, sz)
diff --git a/arch/arc/include/asm/mach/pci.h b/arch/arc/include/asm/mach/pci.h
new file mode 100644
index 0000000..9e75277
--- /dev/null
+++ b/arch/arc/include/asm/mach/pci.h
@@ -0,0 +1,97 @@ 
+/*
+ *  arch/arc/include/asm/mach/pci.h
+ *
+ *  Copyright (C) 2004-2014 Synopsys, Inc. (www.synopsys.com)
+ *
+ * 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.
+ */
+
+#ifndef __ASM_MACH_PCI_H
+#define __ASM_MACH_PCI_H
+
+#include <linux/ioport.h>
+
+struct pci_sys_data;
+struct pci_ops;
+struct pci_bus;
+struct device;
+
+struct hw_pci {
+#ifdef CONFIG_PCI_DOMAINS
+	int		domain;
+#endif
+	struct pci_ops	*ops;
+	int		nr_controllers;
+	void		**private_data;
+	int		(*setup)(int nr, struct pci_sys_data *);
+	struct pci_bus *(*scan)(int nr, struct pci_sys_data *);
+	void		(*preinit)(void);
+	void		(*postinit)(void);
+	u8		(*swizzle)(struct pci_dev *dev, u8 *pin);
+	int		(*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
+	resource_size_t (*align_resource)(struct pci_dev *dev,
+					  const struct resource *res,
+					  resource_size_t start,
+					  resource_size_t size,
+					  resource_size_t align);
+	void		(*add_bus)(struct pci_bus *bus);
+	void		(*remove_bus)(struct pci_bus *bus);
+};
+
+/*
+ * Per-controller structure
+ */
+struct pci_sys_data {
+#ifdef CONFIG_PCI_DOMAINS
+	int		domain;
+#endif
+	struct list_head node;
+	int		busnr;		/* primary bus number		    */
+	u64		mem_offset;	/* bus->cpu memory mapping offset   */
+	unsigned long	io_offset;	/* bus->cpu IO mapping offset	    */
+	struct pci_bus	*bus;		/* PCI bus			    */
+	struct list_head resources;	/* root bus resources (apertures)   */
+	struct resource io_res;
+	char		io_res_name[12];
+					/* Bridge swizzling		    */
+	u8		(*swizzle)(struct pci_dev *, u8 *);
+					/* IRQ mapping			    */
+	int		(*map_irq)(const struct pci_dev *, u8, u8);
+					/* Resource alignement requirements */
+	resource_size_t (*align_resource)(struct pci_dev *dev,
+					  const struct resource *res,
+					  resource_size_t start,
+					  resource_size_t size,
+					  resource_size_t align);
+	void		(*add_bus)(struct pci_bus *bus);
+	void		(*remove_bus)(struct pci_bus *bus);
+	void		*private_data;	/* platform controller private data */
+};
+
+/*
+ * Call this with your hw_pci struct to initialise the PCI system.
+ */
+void pci_common_init_dev(struct device *, struct hw_pci *);
+
+/*
+ * Compatibility wrapper for older platforms that do not care about
+ * passing the parent device.
+ */
+static inline void pci_common_init(struct hw_pci *hw)
+{
+	pci_common_init_dev(NULL, hw);
+}
+
+/*
+ * Setup early fixed I/O mapping.
+ */
+#if defined(CONFIG_PCI)
+extern void pci_map_io_early(unsigned long pfn);
+#else
+static inline void pci_map_io_early(unsigned long pfn) {}
+#endif
+
+#endif /* __ASM_MACH_PCI_H */
+
diff --git a/arch/arc/include/asm/pci.h b/arch/arc/include/asm/pci.h
new file mode 100644
index 0000000..085b15f
--- /dev/null
+++ b/arch/arc/include/asm/pci.h
@@ -0,0 +1,34 @@ 
+/*
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * 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.
+ */
+
+#ifndef _ASM_ARC_PCI_H
+#define _ASM_ARC_PCI_H
+
+#ifdef __KERNEL__
+#include <asm-generic/pci-dma-compat.h>
+#include <asm-generic/pci-bridge.h>
+
+#include <asm/mach/pci.h> /* for pci_sys_data */
+
+extern unsigned long pcibios_min_io;
+#define PCIBIOS_MIN_IO pcibios_min_io
+extern unsigned long pcibios_min_mem;
+#define PCIBIOS_MIN_MEM pcibios_min_mem
+
+#define pcibios_assign_all_busses()	1
+/*
+ * The PCI address space does equal the physical memory address space.
+ * The networking and block device layers use this boolean for bounce
+ * buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS     (1)
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_ARC_PCI_H */
+
diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile
index e7f3625..1bc2036 100644
--- a/arch/arc/kernel/Makefile
+++ b/arch/arc/kernel/Makefile
@@ -12,6 +12,7 @@  obj-y	:= arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o
 obj-y	+= signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o clk.o
 obj-$(CONFIG_ISA_ARCOMPACT)		+= entry-compact.o intc-compact.o
 obj-$(CONFIG_ISA_ARCV2)			+= entry-arcv2.o intc-arcv2.o
+obj-$(CONFIG_PCI)  			+= pcibios.o
 
 obj-$(CONFIG_MODULES)			+= arcksyms.o module.o
 obj-$(CONFIG_SMP) 			+= smp.o
diff --git a/arch/arc/kernel/pcibios.c b/arch/arc/kernel/pcibios.c
new file mode 100644
index 0000000..5af7bf0
--- /dev/null
+++ b/arch/arc/kernel/pcibios.c
@@ -0,0 +1,358 @@ 
+/*
+ * Copyright (C) 2014-2015 Synopsys, Inc. (www.synopsys.com)
+ *
+ * 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+#include <asm/pci.h>
+#include <asm/mach/pci.h>
+
+unsigned long pcibios_min_io = 0x100;
+EXPORT_SYMBOL(pcibios_min_io);
+
+unsigned long pcibios_min_mem = 0x100000;
+EXPORT_SYMBOL(pcibios_min_mem);
+
+static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
+{
+	int ret;
+	struct resource_entry *window;
+
+	if (list_empty(&sys->resources)) {
+		pci_add_resource_offset(&sys->resources,
+			 &iomem_resource, sys->mem_offset);
+	}
+
+	resource_list_for_each_entry(window, &sys->resources) {
+		if (resource_type(window->res) == IORESOURCE_IO)
+			return 0;
+	}
+
+	sys->io_res.start = (busnr * SZ_64K) ?  : pcibios_min_io;
+	sys->io_res.end = (busnr + 1) * SZ_64K - 1;
+	sys->io_res.flags = IORESOURCE_IO;
+	sys->io_res.name = sys->io_res_name;
+	sprintf(sys->io_res_name, "PCI%d I/O", busnr);
+
+	ret = request_resource(&ioport_resource, &sys->io_res);
+	if (ret) {
+		pr_err("PCI: unable to allocate I/O port region (%d)\n", ret);
+		return ret;
+	}
+	pci_add_resource_offset(&sys->resources, &sys->io_res,
+				sys->io_offset);
+
+	return 0;
+}
+
+
+static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
+			    struct list_head *head)
+{
+	struct pci_sys_data *sys = NULL;
+	int ret;
+	int nr, busnr;
+
+	for (nr = busnr = 0; nr < hw->nr_controllers; nr++) {
+		sys = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL);
+		if (!sys)
+			panic("PCI: unable to allocate sys data!");
+
+#ifdef CONFIG_PCI_DOMAINS
+		sys->domain  = hw->domain;
+#endif
+		sys->busnr   = busnr;
+		sys->swizzle = hw->swizzle;
+		sys->map_irq = hw->map_irq;
+		sys->align_resource = hw->align_resource;
+		sys->add_bus = hw->add_bus;
+		sys->remove_bus = hw->remove_bus;
+		INIT_LIST_HEAD(&sys->resources);
+
+
+		if (hw->private_data)
+			sys->private_data = hw->private_data[nr];
+
+		ret = hw->setup(nr, sys);
+
+		if (ret > 0) {
+			ret = pcibios_init_resources(nr, sys);
+			if (ret)  {
+				kfree(sys);
+				break;
+			}
+
+			if (hw->scan)
+				sys->bus = hw->scan(nr, sys);
+			else
+				sys->bus = pci_scan_root_bus(parent, sys->busnr,
+						hw->ops, sys, &sys->resources);
+
+			if (!sys->bus)
+				panic("PCI: unable to scan bus!");
+
+			busnr = sys->bus->busn_res.end + 1;
+
+			list_add(&sys->node, head);
+		} else {
+			kfree(sys);
+			if (ret < 0)
+				break;
+		}
+	}
+}
+
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+	return 0;
+}
+
+void pcibios_add_bus(struct pci_bus *bus)
+{
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+}
+
+/*
+ * Swizzle the device pin each time we cross a bridge.  If a platform does
+ * not provide a swizzle function, we perform the standard PCI swizzling.
+ *
+ * The default swizzling walks up the bus tree one level at a time, applying
+ * the standard swizzle function at each step, stopping when it finds the PCI
+ * root bus.  This will return the slot number of the bridge device on the
+ * root bus and the interrupt pin on that device which should correspond
+ * with the downstream device interrupt.
+ *
+ * Platforms may override this, in which case the slot and pin returned
+ * depend entirely on the platform code.  However, please note that the
+ * PCI standard swizzle is implemented on plug-in cards and Cardbus based
+ * PCI extenders, so it can not be ignored.
+ */
+static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
+{
+	int slot;
+	struct pci_sys_data *sys = dev->sysdata;
+
+	if (sys->swizzle)
+		slot = sys->swizzle(dev, pin);
+	else
+		slot = pci_common_swizzle(dev, pin);
+
+	return slot;
+}
+
+/*
+ * Map a slot/pin to an IRQ.
+ */
+static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	struct pci_sys_data *sys = dev->sysdata;
+	int irq = -1;
+
+	if (sys->map_irq)
+		irq = sys->map_irq(dev, slot, pin);
+
+	return irq;
+}
+
+void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
+{
+	struct pci_sys_data *sys;
+	LIST_HEAD(head);
+
+	pci_add_flags(PCI_REASSIGN_ALL_RSRC);
+	if (hw->preinit)
+		hw->preinit();
+	pcibios_init_hw(parent, hw, &head);
+	if (hw->postinit)
+		hw->postinit();
+
+	pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq);
+
+	list_for_each_entry(sys, &head, node) {
+		struct pci_bus *bus = sys->bus;
+
+		if (!pci_has_flag(PCI_PROBE_ONLY)) {
+			/*
+			 * Size the bridge windows.
+			 */
+			pci_bus_size_bridges(bus);
+
+			/*
+			 * Assign resources.
+			 */
+			pci_bus_assign_resources(bus);
+		}
+
+		/*
+		 * Tell drivers about devices found.
+		 */
+		pci_bus_add_devices(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;
+}
+
+/**
+ * pcibios_enable_device - Enable I/O and memory.
+ * @dev: PCI device to be enabled
+ */
+int pcibios_enable_device(struct pci_dev *pci_dev, int mask)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx = 0; idx < 6; idx++) {
+		/* Only set up the requested stuff */
+		if (!(mask & (1 << idx)))
+			continue;
+
+		r = pci_dev->resource + idx;
+		if (!r->start && r->end) {
+			dev_err(&pci_dev->dev, "PCI: Device %s not available\n",
+							pci_name(pci_dev));
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+
+	/*
+	 * Bridges (eg, cardbus bridges) need to be fully enabled
+	 */
+	if ((pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
+		cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+
+	if (cmd != old_cmd) {
+		pr_info("PCI: enabling device %s (%04x -> %04x)\n",
+		       pci_name(pci_dev), old_cmd, cmd);
+		pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+/*
+ * If the bus contains any of these devices, then we must not turn on
+ * parity checking of any kind.  Currently this is CyberPro 20x0 only.
+ */
+static inline int pdev_bad_for_parity(struct pci_dev *dev)
+{
+	return ((dev->vendor == PCI_VENDOR_ID_INTERG &&
+		 (dev->device == PCI_DEVICE_ID_INTERG_2000 ||
+		  dev->device == PCI_DEVICE_ID_INTERG_2010)) ||
+		(dev->vendor == PCI_VENDOR_ID_ITE &&
+		 dev->device == PCI_DEVICE_ID_ITE_8152));
+
+}
+
+/*
+ * pcibios_fixup_bus - Called after each bus is probed,
+ * but before its children are examined.
+ */
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+	u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY
+			| PCI_COMMAND_FAST_BACK;
+
+	/*
+	 * Walk the devices on this bus, working out what we can
+	 * and can't support.
+	 */
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		u16 status;
+
+		pci_read_config_word(dev, PCI_STATUS, &status);
+
+		/*
+		 * If any device on this bus does not support fast back
+		 * to back transfers, then the bus as a whole is not able
+		 * to support them.  Having fast back to back transfers
+		 * on saves us one PCI cycle per transaction.
+		 */
+		if (!(status & PCI_STATUS_FAST_BACK))
+			features &= ~PCI_COMMAND_FAST_BACK;
+
+		if (pdev_bad_for_parity(dev))
+			features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+
+		switch (dev->class >> 8) {
+		case PCI_CLASS_BRIDGE_PCI:
+			pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status);
+			status |= PCI_BRIDGE_CTL_PARITY
+					|PCI_BRIDGE_CTL_MASTER_ABORT;
+			status &= ~(PCI_BRIDGE_CTL_BUS_RESET
+					|PCI_BRIDGE_CTL_FAST_BACK);
+			pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status);
+			break;
+
+		case PCI_CLASS_BRIDGE_CARDBUS:
+			pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL,
+						&status);
+			status |= PCI_CB_BRIDGE_CTL_PARITY
+					|PCI_CB_BRIDGE_CTL_MASTER_ABORT;
+			pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL,
+						status);
+			break;
+		}
+	}
+
+	/*
+	 * Now walk the devices again, this time setting them up.
+	 */
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		u16 cmd;
+
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		cmd |= features;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+				      L1_CACHE_BYTES >> 2);
+	}
+
+	/*
+	 * Propagate the flags to the PCI bridge.
+	 */
+	if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		if (features & PCI_COMMAND_FAST_BACK)
+			bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK;
+		if (features & PCI_COMMAND_PARITY)
+			bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY;
+	}
+
+	/*
+	 * Report what we did for this bus
+	 */
+	pr_info("PCI: bus%d: Fast back to back transfers %sabled\n",
+		bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
+}
+EXPORT_SYMBOL(pcibios_fixup_bus);
diff --git a/arch/arc/mm/ioremap.c b/arch/arc/mm/ioremap.c
index 739e65f..fe807b0 100644
--- a/arch/arc/mm/ioremap.c
+++ b/arch/arc/mm/ioremap.c
@@ -13,6 +13,7 @@ 
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/cache.h>
+#include <linux/sizes.h>
 
 void __iomem *ioremap(unsigned long paddr, unsigned long size)
 {
@@ -80,7 +81,6 @@  void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size,
 }
 EXPORT_SYMBOL(ioremap_prot);
 
-
 void iounmap(const void __iomem *addr)
 {
 	if (addr >= (void __force __iomem *)ARC_UNCACHED_ADDR_SPACE)
@@ -89,3 +89,11 @@  void iounmap(const void __iomem *addr)
 	vfree((void *)(PAGE_MASK & (unsigned long __force)addr));
 }
 EXPORT_SYMBOL(iounmap);
+
+#ifdef CONFIG_PCI
+int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
+{
+	return ioremap_nocache(phys_addr + offset,  SZ_64K);
+}
+EXPORT_SYMBOL_GPL(pci_ioremap_io);
+#endif
diff --git a/arch/arc/plat-axs10x/Kconfig b/arch/arc/plat-axs10x/Kconfig
index d475f9d..426ac4b 100644
--- a/arch/arc/plat-axs10x/Kconfig
+++ b/arch/arc/plat-axs10x/Kconfig
@@ -11,6 +11,7 @@  menuconfig ARC_PLAT_AXS10X
 	select DW_APB_ICTL
 	select GPIO_DWAPB
 	select OF_GPIO
+	select MIGHT_HAVE_PCI
 	select GENERIC_IRQ_CHIP
 	select ARCH_REQUIRE_GPIOLIB
 	help
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index be3f631..2154092 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -32,6 +32,7 @@  obj-$(CONFIG_PCI_IOV) += iov.o
 # Some architectures use the generic PCI setup functions
 #
 obj-$(CONFIG_ALPHA) += setup-irq.o
+obj-$(CONFIG_ARC) += setup-irq.o
 obj-$(CONFIG_ARM) += setup-irq.o
 obj-$(CONFIG_ARM64) += setup-irq.o
 obj-$(CONFIG_UNICORE32) += setup-irq.o