All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 0/5] ACPI based PCI support for arm64
@ 2016-01-29  9:05 ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

Here is another update to this patchset.

This patchset provides a generic ACPI based PCI host controller
implementation and uses it on arm64.

The first patch moves the common code to handle MCFG ACPI table from
arch/x86 to drivers/acpi/pci_mcfg.c. The last patch in the patchset
provides the generic implementation of an ACPI based PCI host
controller with a new file drivers/acpi/pci_host_acpi.c. The other
patches are to fix up arm64 and ACPI code to work with these two
patches.

The pci host controller implementation keeps a reference to
pci_mmcfg_region entry so that config space access is done with a
simple mapping and generic PCI config read/write. There is also an
implementation of raw_pci_read/raw_pci_write provided by walking the
pci_mmcfg_list.

The patchset is against 4.5-rc1. This is tested with arm64 QEMU and
OVMF and on x86 with qemu.

More testing or comments are welcome. The idea is to provide a
simpler alternative for ACPI PCI support in arm64, any feedback
from PCI or ACPI maintainers would be appreciated on this front.

Thanks,
JC.

v6->v7:
 - minor update of patches so that CONFIG_ACPI_PCI_HOST_GENERIC
   is only used when it is defined
 - rebased to 4.5-rc1

v5->v6:
 - fix arm64 with xen compile issue reported by kbuild bot

v4->v5:
 - Fix arm build issue reported by the kbuild bot
 - Use config_enabled instead of ifdef in pci_mcfg.c

v3->v4:
 - Handle suggestions from Arnd Bergmann <arnd@arndb.de>
    * move the implementation of host controller to drivers/acpi
      under config option CONFIG_ACPI_PCI_HOST_GENERIC
    * remove unnecessary arch hooks (this done as much as possible
      without affecting the scope of the patch, will need another
      separate patchset for the rest).
    * remove pcibios_assign_resources fs_initcall that was added
 - fixup domain_nr assignment code, and move ACPI companion set
   to PCI code.
 - Call map resource correctly in setup code
 - fix kbuild robot report
 - More testing

v2->v3:
 - Move maintenance of the pci_mmcfg_list to drivers/acpi/pci_mcfg.c
   without changing x86 logic
 - use the pci_mmcfg_list in ARM64 implementation
 - provide raw_pci_read/raw_pci_write

v1->v2:
 - use CONFIG_PCI_MMCONFIG on arm64, provide a weak implementation
   of pci_mmcfg_late_init for arm64.
 - The real implementation of pci_mmcfg_late_init is in pci-host-acpi.c
   and it will save the MCFG table entries to an array. Earlier this
   was done with an arch_init call
 - remove unneeded pci_bus_add_devices call and fix MCFG saving code
 - Added a patch to ACPI pci_root.c to handle arm64 PCI IO resources

Jayachandran C (5):
  APCI: MCFG: Move mmcfg_list management to drivers/acpi
  PCI: Handle ACPI companion and domain number
  ACPI: PCI: Support platforms that need pci_remap_iospace
  arm64: pci: Add ACPI support
  PCI: ACPI: Add a generic ACPI based host controller

Jayachandran C (5):
  APCI: MCFG: Move mmcfg_list management to drivers/acpi
  ACPI: PCI: Support platforms that need pci_remap_iospace
  PCI: Handle ACPI companion and domain number
  arm64: pci: Add ACPI support
  PCI: ACPI: Add a generic ACPI based host controller

 arch/arm64/Kconfig             |   3 +
 arch/arm64/kernel/pci.c        |  34 ++++-
 arch/x86/include/asm/pci_x86.h |  24 +---
 arch/x86/pci/mmconfig-shared.c | 269 +++++------------------------------
 arch/x86/pci/mmconfig_32.c     |   1 +
 arch/x86/pci/mmconfig_64.c     |   1 +
 arch/x86/pci/numachip.c        |   1 +
 drivers/acpi/Kconfig           |   8 ++
 drivers/acpi/Makefile          |   2 +
 drivers/acpi/pci_host_acpi.c   | 186 ++++++++++++++++++++++++
 drivers/acpi/pci_mcfg.c        | 312 +++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/pci_root.c        |  62 +++++++-
 drivers/acpi/resource.c        |   2 +
 drivers/pci/pci.c              |  15 +-
 drivers/pci/probe.c            |   2 +
 drivers/xen/pci.c              |   5 +-
 include/linux/pci-acpi.h       |  59 ++++++++
 17 files changed, 717 insertions(+), 269 deletions(-)
 create mode 100644 drivers/acpi/pci_host_acpi.c
 create mode 100644 drivers/acpi/pci_mcfg.c

-- 
1.9.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 0/5] ACPI based PCI support for arm64
@ 2016-01-29  9:05 ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

Here is another update to this patchset.

This patchset provides a generic ACPI based PCI host controller
implementation and uses it on arm64.

The first patch moves the common code to handle MCFG ACPI table from
arch/x86 to drivers/acpi/pci_mcfg.c. The last patch in the patchset
provides the generic implementation of an ACPI based PCI host
controller with a new file drivers/acpi/pci_host_acpi.c. The other
patches are to fix up arm64 and ACPI code to work with these two
patches.

The pci host controller implementation keeps a reference to
pci_mmcfg_region entry so that config space access is done with a
simple mapping and generic PCI config read/write. There is also an
implementation of raw_pci_read/raw_pci_write provided by walking the
pci_mmcfg_list.

The patchset is against 4.5-rc1. This is tested with arm64 QEMU and
OVMF and on x86 with qemu.

More testing or comments are welcome. The idea is to provide a
simpler alternative for ACPI PCI support in arm64, any feedback
from PCI or ACPI maintainers would be appreciated on this front.

Thanks,
JC.

v6->v7:
 - minor update of patches so that CONFIG_ACPI_PCI_HOST_GENERIC
   is only used when it is defined
 - rebased to 4.5-rc1

v5->v6:
 - fix arm64 with xen compile issue reported by kbuild bot

v4->v5:
 - Fix arm build issue reported by the kbuild bot
 - Use config_enabled instead of ifdef in pci_mcfg.c

v3->v4:
 - Handle suggestions from Arnd Bergmann <arnd@arndb.de>
    * move the implementation of host controller to drivers/acpi
      under config option CONFIG_ACPI_PCI_HOST_GENERIC
    * remove unnecessary arch hooks (this done as much as possible
      without affecting the scope of the patch, will need another
      separate patchset for the rest).
    * remove pcibios_assign_resources fs_initcall that was added
 - fixup domain_nr assignment code, and move ACPI companion set
   to PCI code.
 - Call map resource correctly in setup code
 - fix kbuild robot report
 - More testing

v2->v3:
 - Move maintenance of the pci_mmcfg_list to drivers/acpi/pci_mcfg.c
   without changing x86 logic
 - use the pci_mmcfg_list in ARM64 implementation
 - provide raw_pci_read/raw_pci_write

v1->v2:
 - use CONFIG_PCI_MMCONFIG on arm64, provide a weak implementation
   of pci_mmcfg_late_init for arm64.
 - The real implementation of pci_mmcfg_late_init is in pci-host-acpi.c
   and it will save the MCFG table entries to an array. Earlier this
   was done with an arch_init call
 - remove unneeded pci_bus_add_devices call and fix MCFG saving code
 - Added a patch to ACPI pci_root.c to handle arm64 PCI IO resources

Jayachandran C (5):
  APCI: MCFG: Move mmcfg_list management to drivers/acpi
  PCI: Handle ACPI companion and domain number
  ACPI: PCI: Support platforms that need pci_remap_iospace
  arm64: pci: Add ACPI support
  PCI: ACPI: Add a generic ACPI based host controller

Jayachandran C (5):
  APCI: MCFG: Move mmcfg_list management to drivers/acpi
  ACPI: PCI: Support platforms that need pci_remap_iospace
  PCI: Handle ACPI companion and domain number
  arm64: pci: Add ACPI support
  PCI: ACPI: Add a generic ACPI based host controller

 arch/arm64/Kconfig             |   3 +
 arch/arm64/kernel/pci.c        |  34 ++++-
 arch/x86/include/asm/pci_x86.h |  24 +---
 arch/x86/pci/mmconfig-shared.c | 269 +++++------------------------------
 arch/x86/pci/mmconfig_32.c     |   1 +
 arch/x86/pci/mmconfig_64.c     |   1 +
 arch/x86/pci/numachip.c        |   1 +
 drivers/acpi/Kconfig           |   8 ++
 drivers/acpi/Makefile          |   2 +
 drivers/acpi/pci_host_acpi.c   | 186 ++++++++++++++++++++++++
 drivers/acpi/pci_mcfg.c        | 312 +++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/pci_root.c        |  62 +++++++-
 drivers/acpi/resource.c        |   2 +
 drivers/pci/pci.c              |  15 +-
 drivers/pci/probe.c            |   2 +
 drivers/xen/pci.c              |   5 +-
 include/linux/pci-acpi.h       |  59 ++++++++
 17 files changed, 717 insertions(+), 269 deletions(-)
 create mode 100644 drivers/acpi/pci_host_acpi.c
 create mode 100644 drivers/acpi/pci_mcfg.c

-- 
1.9.1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 0/5] ACPI based PCI support for arm64
@ 2016-01-29  9:05 ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

Here is another update to this patchset.

This patchset provides a generic ACPI based PCI host controller
implementation and uses it on arm64.

The first patch moves the common code to handle MCFG ACPI table from
arch/x86 to drivers/acpi/pci_mcfg.c. The last patch in the patchset
provides the generic implementation of an ACPI based PCI host
controller with a new file drivers/acpi/pci_host_acpi.c. The other
patches are to fix up arm64 and ACPI code to work with these two
patches.

The pci host controller implementation keeps a reference to
pci_mmcfg_region entry so that config space access is done with a
simple mapping and generic PCI config read/write. There is also an
implementation of raw_pci_read/raw_pci_write provided by walking the
pci_mmcfg_list.

The patchset is against 4.5-rc1. This is tested with arm64 QEMU and
OVMF and on x86 with qemu.

More testing or comments are welcome. The idea is to provide a
simpler alternative for ACPI PCI support in arm64, any feedback
from PCI or ACPI maintainers would be appreciated on this front.

Thanks,
JC.

v6->v7:
 - minor update of patches so that CONFIG_ACPI_PCI_HOST_GENERIC
   is only used when it is defined
 - rebased to 4.5-rc1

v5->v6:
 - fix arm64 with xen compile issue reported by kbuild bot

v4->v5:
 - Fix arm build issue reported by the kbuild bot
 - Use config_enabled instead of ifdef in pci_mcfg.c

v3->v4:
 - Handle suggestions from Arnd Bergmann <arnd@arndb.de>
    * move the implementation of host controller to drivers/acpi
      under config option CONFIG_ACPI_PCI_HOST_GENERIC
    * remove unnecessary arch hooks (this done as much as possible
      without affecting the scope of the patch, will need another
      separate patchset for the rest).
    * remove pcibios_assign_resources fs_initcall that was added
 - fixup domain_nr assignment code, and move ACPI companion set
   to PCI code.
 - Call map resource correctly in setup code
 - fix kbuild robot report
 - More testing

v2->v3:
 - Move maintenance of the pci_mmcfg_list to drivers/acpi/pci_mcfg.c
   without changing x86 logic
 - use the pci_mmcfg_list in ARM64 implementation
 - provide raw_pci_read/raw_pci_write

v1->v2:
 - use CONFIG_PCI_MMCONFIG on arm64, provide a weak implementation
   of pci_mmcfg_late_init for arm64.
 - The real implementation of pci_mmcfg_late_init is in pci-host-acpi.c
   and it will save the MCFG table entries to an array. Earlier this
   was done with an arch_init call
 - remove unneeded pci_bus_add_devices call and fix MCFG saving code
 - Added a patch to ACPI pci_root.c to handle arm64 PCI IO resources

Jayachandran C (5):
  APCI: MCFG: Move mmcfg_list management to drivers/acpi
  PCI: Handle ACPI companion and domain number
  ACPI: PCI: Support platforms that need pci_remap_iospace
  arm64: pci: Add ACPI support
  PCI: ACPI: Add a generic ACPI based host controller

Jayachandran C (5):
  APCI: MCFG: Move mmcfg_list management to drivers/acpi
  ACPI: PCI: Support platforms that need pci_remap_iospace
  PCI: Handle ACPI companion and domain number
  arm64: pci: Add ACPI support
  PCI: ACPI: Add a generic ACPI based host controller

 arch/arm64/Kconfig             |   3 +
 arch/arm64/kernel/pci.c        |  34 ++++-
 arch/x86/include/asm/pci_x86.h |  24 +---
 arch/x86/pci/mmconfig-shared.c | 269 +++++------------------------------
 arch/x86/pci/mmconfig_32.c     |   1 +
 arch/x86/pci/mmconfig_64.c     |   1 +
 arch/x86/pci/numachip.c        |   1 +
 drivers/acpi/Kconfig           |   8 ++
 drivers/acpi/Makefile          |   2 +
 drivers/acpi/pci_host_acpi.c   | 186 ++++++++++++++++++++++++
 drivers/acpi/pci_mcfg.c        | 312 +++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/pci_root.c        |  62 +++++++-
 drivers/acpi/resource.c        |   2 +
 drivers/pci/pci.c              |  15 +-
 drivers/pci/probe.c            |   2 +
 drivers/xen/pci.c              |   5 +-
 include/linux/pci-acpi.h       |  59 ++++++++
 17 files changed, 717 insertions(+), 269 deletions(-)
 create mode 100644 drivers/acpi/pci_host_acpi.c
 create mode 100644 drivers/acpi/pci_mcfg.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 1/5] APCI: MCFG: Move mmcfg_list management to drivers/acpi
  2016-01-29  9:05 ` Jayachandran C
  (?)
@ 2016-01-29  9:05   ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

Move pci_mmcfg_list handling to a drivers/acpi/pci_mcfg.c. This is
to share the API and code with ARM64 later. The corresponding
declarations are moved from asm/pci_x86.h to linux/pci-acpi.h

As a part of this we introduce three functions that can be
implemented by the arch code: pci_mmconfig_map_resource() to map a
mcfg entry, pci_mmconfig_unmap_resource to do the corresponding
unmap and pci_mmconfig_enabled to see if the arch setup of
mcfg entries was successful. We also provide weak implementations
of these, which will be used from ARM64. On x86, we retain the
old logic by providing platform specific implementation.

This patch is purely rearranging code, it should not have any
impact on the logic of MCFG parsing or list handling.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
[Xen parts:]
Acked-by: David Vrabel <david.vrabel@citrix.com>

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 arch/x86/include/asm/pci_x86.h |  24 +---
 arch/x86/pci/mmconfig-shared.c | 269 +++++------------------------------
 arch/x86/pci/mmconfig_32.c     |   1 +
 arch/x86/pci/mmconfig_64.c     |   1 +
 arch/x86/pci/numachip.c        |   1 +
 drivers/acpi/Makefile          |   1 +
 drivers/acpi/pci_mcfg.c        | 312 +++++++++++++++++++++++++++++++++++++++++
 drivers/xen/pci.c              |   5 +-
 include/linux/pci-acpi.h       |  33 +++++
 9 files changed, 386 insertions(+), 261 deletions(-)
 create mode 100644 drivers/acpi/pci_mcfg.c

diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index 46873fb..7824626 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -122,33 +122,11 @@ extern int pci_legacy_init(void);
 extern void pcibios_fixup_irqs(void);
 
 /* pci-mmconfig.c */
-
-/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
-#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
-
-struct pci_mmcfg_region {
-	struct list_head list;
-	struct resource res;
-	u64 address;
-	char __iomem *virt;
-	u16 segment;
-	u8 start_bus;
-	u8 end_bus;
-	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
-};
-
+struct pci_mmcfg_region;
 extern int __init pci_mmcfg_arch_init(void);
 extern void __init pci_mmcfg_arch_free(void);
 extern int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
 extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
-extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
-			       phys_addr_t addr);
-extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
-extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
-
-extern struct list_head pci_mmcfg_list;
-
-#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
 
 /*
  * On AMD Fam10h CPUs, all PCI MMIO configuration space accesses must use
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index dd30b7e..626710b 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -12,13 +12,12 @@
 
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/sfi_acpi.h>
 #include <linux/bitmap.h>
-#include <linux/dmi.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/rculist.h>
 #include <asm/e820.h>
+#include <linux/pci-acpi.h>
 #include <asm/pci_x86.h>
 #include <asm/acpi.h>
 
@@ -27,9 +26,6 @@
 /* Indicate if the mmcfg resources have been placed into the resource table. */
 static bool pci_mmcfg_running_state;
 static bool pci_mmcfg_arch_init_failed;
-static DEFINE_MUTEX(pci_mmcfg_lock);
-
-LIST_HEAD(pci_mmcfg_list);
 
 static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
 {
@@ -48,83 +44,6 @@ static void __init free_all_mmcfg(void)
 		pci_mmconfig_remove(cfg);
 }
 
-static void list_add_sorted(struct pci_mmcfg_region *new)
-{
-	struct pci_mmcfg_region *cfg;
-
-	/* keep list sorted by segment and starting bus number */
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
-		if (cfg->segment > new->segment ||
-		    (cfg->segment == new->segment &&
-		     cfg->start_bus >= new->start_bus)) {
-			list_add_tail_rcu(&new->list, &cfg->list);
-			return;
-		}
-	}
-	list_add_tail_rcu(&new->list, &pci_mmcfg_list);
-}
-
-static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
-						   int end, u64 addr)
-{
-	struct pci_mmcfg_region *new;
-	struct resource *res;
-
-	if (addr == 0)
-		return NULL;
-
-	new = kzalloc(sizeof(*new), GFP_KERNEL);
-	if (!new)
-		return NULL;
-
-	new->address = addr;
-	new->segment = segment;
-	new->start_bus = start;
-	new->end_bus = end;
-
-	res = &new->res;
-	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
-	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
-	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-	snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
-		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
-	res->name = new->name;
-
-	return new;
-}
-
-static struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
-							int end, u64 addr)
-{
-	struct pci_mmcfg_region *new;
-
-	new = pci_mmconfig_alloc(segment, start, end, addr);
-	if (new) {
-		mutex_lock(&pci_mmcfg_lock);
-		list_add_sorted(new);
-		mutex_unlock(&pci_mmcfg_lock);
-
-		pr_info(PREFIX
-		       "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
-		       "(base %#lx)\n",
-		       segment, start, end, &new->res, (unsigned long)addr);
-	}
-
-	return new;
-}
-
-struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
-{
-	struct pci_mmcfg_region *cfg;
-
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
-		if (cfg->segment == segment &&
-		    cfg->start_bus <= bus && bus <= cfg->end_bus)
-			return cfg;
-
-	return NULL;
-}
-
 static const char *__init pci_mmcfg_e7520(void)
 {
 	u32 win;
@@ -543,73 +462,6 @@ static void __init pci_mmcfg_reject_broken(int early)
 	}
 }
 
-static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
-					struct acpi_mcfg_allocation *cfg)
-{
-	int year;
-
-	if (cfg->address < 0xFFFFFFFF)
-		return 0;
-
-	if (!strncmp(mcfg->header.oem_id, "SGI", 3))
-		return 0;
-
-	if (mcfg->header.revision >= 1) {
-		if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
-		    year >= 2010)
-			return 0;
-	}
-
-	pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
-	       "is above 4GB, ignored\n", cfg->pci_segment,
-	       cfg->start_bus_number, cfg->end_bus_number, cfg->address);
-	return -EINVAL;
-}
-
-static int __init pci_parse_mcfg(struct acpi_table_header *header)
-{
-	struct acpi_table_mcfg *mcfg;
-	struct acpi_mcfg_allocation *cfg_table, *cfg;
-	unsigned long i;
-	int entries;
-
-	if (!header)
-		return -EINVAL;
-
-	mcfg = (struct acpi_table_mcfg *)header;
-
-	/* how many config structures do we have */
-	free_all_mmcfg();
-	entries = 0;
-	i = header->length - sizeof(struct acpi_table_mcfg);
-	while (i >= sizeof(struct acpi_mcfg_allocation)) {
-		entries++;
-		i -= sizeof(struct acpi_mcfg_allocation);
-	}
-	if (entries == 0) {
-		pr_err(PREFIX "MMCONFIG has no entries\n");
-		return -ENODEV;
-	}
-
-	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
-	for (i = 0; i < entries; i++) {
-		cfg = &cfg_table[i];
-		if (acpi_mcfg_check_entry(mcfg, cfg)) {
-			free_all_mmcfg();
-			return -ENODEV;
-		}
-
-		if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
-				   cfg->end_bus_number, cfg->address) == NULL) {
-			pr_warn(PREFIX "no memory for MCFG entries\n");
-			free_all_mmcfg();
-			return -ENOMEM;
-		}
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_ACPI_APEI
 extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,
 				     void *data), void *data);
@@ -662,13 +514,20 @@ static void __init __pci_mmcfg_init(int early)
 
 static int __initdata known_bridge;
 
+static void __init pci_mmcfg_list_setup(void)
+{
+	free_all_mmcfg();
+	if (pci_mmconfig_parse_table())
+		free_all_mmcfg();
+}
+
 void __init pci_mmcfg_early_init(void)
 {
 	if (pci_probe & PCI_PROBE_MMCONF) {
 		if (pci_mmcfg_check_hostbridge())
 			known_bridge = 1;
 		else
-			acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+			pci_mmcfg_list_setup();
 		__pci_mmcfg_init(1);
 
 		set_apei_filter();
@@ -686,7 +545,7 @@ void __init pci_mmcfg_late_init(void)
 
 	/* MMCONFIG hasn't been enabled yet, try again */
 	if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) {
-		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+		pci_mmcfg_list_setup();
 		__pci_mmcfg_init(0);
 	}
 }
@@ -720,99 +579,41 @@ static int __init pci_mmcfg_late_insert_resources(void)
  */
 late_initcall(pci_mmcfg_late_insert_resources);
 
-/* Add MMCFG information for host bridges */
-int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
-			phys_addr_t addr)
+int pci_mmconfig_map_resource(struct device *dev, struct pci_mmcfg_region *cfg)
 {
-	int rc;
-	struct resource *tmp = NULL;
-	struct pci_mmcfg_region *cfg;
+	struct resource *tmp;
 
-	if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
-		return -ENODEV;
-
-	if (start > end)
-		return -EINVAL;
-
-	mutex_lock(&pci_mmcfg_lock);
-	cfg = pci_mmconfig_lookup(seg, start);
-	if (cfg) {
-		if (cfg->end_bus < end)
-			dev_info(dev, FW_INFO
-				 "MMCONFIG for "
-				 "domain %04x [bus %02x-%02x] "
-				 "only partially covers this bridge\n",
-				  cfg->segment, cfg->start_bus, cfg->end_bus);
-		mutex_unlock(&pci_mmcfg_lock);
-		return -EEXIST;
-	}
-
-	if (!addr) {
-		mutex_unlock(&pci_mmcfg_lock);
-		return -EINVAL;
-	}
-
-	rc = -EBUSY;
-	cfg = pci_mmconfig_alloc(seg, start, end, addr);
-	if (cfg == NULL) {
-		dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
-		rc = -ENOMEM;
-	} else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
+	if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
 		dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n",
 			 &cfg->res);
-	} else {
-		/* Insert resource if it's not in boot stage */
-		if (pci_mmcfg_running_state)
-			tmp = insert_resource_conflict(&iomem_resource,
-						       &cfg->res);
-
+		return -EBUSY;
+	}
+	/* Insert resource if it's not in boot stage */
+	if (pci_mmcfg_running_state) {
+		tmp = insert_resource_conflict(&iomem_resource,
+					       &cfg->res);
 		if (tmp) {
-			dev_warn(dev,
-				 "MMCONFIG %pR conflicts with "
-				 "%s %pR\n",
-				 &cfg->res, tmp->name, tmp);
-		} else if (pci_mmcfg_arch_map(cfg)) {
-			dev_warn(dev, "fail to map MMCONFIG %pR.\n",
-				 &cfg->res);
-		} else {
-			list_add_sorted(cfg);
-			dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
-				 &cfg->res, (unsigned long)addr);
-			cfg = NULL;
-			rc = 0;
+			dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
+				&cfg->res, tmp->name, tmp);
+			return -EBUSY;
 		}
 	}
-
-	if (cfg) {
-		if (cfg->res.parent)
-			release_resource(&cfg->res);
-		kfree(cfg);
+	if (pci_mmcfg_arch_map(cfg)) {
+		dev_warn(dev, "fail to map MMCONFIG %pR.\n", &cfg->res);
+		return -EBUSY;
 	}
-
-	mutex_unlock(&pci_mmcfg_lock);
-
-	return rc;
+	return 0;
 }
 
-/* Delete MMCFG information for host bridges */
-int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
+void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *cfg)
 {
-	struct pci_mmcfg_region *cfg;
-
-	mutex_lock(&pci_mmcfg_lock);
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
-		if (cfg->segment == seg && cfg->start_bus == start &&
-		    cfg->end_bus == end) {
-			list_del_rcu(&cfg->list);
-			synchronize_rcu();
-			pci_mmcfg_arch_unmap(cfg);
-			if (cfg->res.parent)
-				release_resource(&cfg->res);
-			mutex_unlock(&pci_mmcfg_lock);
-			kfree(cfg);
-			return 0;
-		}
-	mutex_unlock(&pci_mmcfg_lock);
+	pci_mmcfg_arch_unmap(cfg);
+	if (cfg->res.parent)
+		release_resource(&cfg->res);
+	cfg->res.parent = NULL;
+}
 
-	return -ENOENT;
+int pci_mmconfig_enabled(void)
+{
+	return (pci_probe & PCI_PROBE_MMCONF) && !pci_mmcfg_arch_init_failed;
 }
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 43984bc..38a37f8 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -12,6 +12,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/rcupdate.h>
+#include <linux/pci-acpi.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index bea5249..29253ec 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -10,6 +10,7 @@
 #include <linux/acpi.h>
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
+#include <linux/pci-acpi.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
diff --git a/arch/x86/pci/numachip.c b/arch/x86/pci/numachip.c
index 2e565e6..c181eeb 100644
--- a/arch/x86/pci/numachip.c
+++ b/arch/x86/pci/numachip.c
@@ -14,6 +14,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <asm/pci_x86.h>
 
 static u8 limit __read_mostly;
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index cb648a4..74976f1 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
 acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
+acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
 acpi-y				+= acpi_lpss.o acpi_apd.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= acpi_pnp.o
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
new file mode 100644
index 0000000..ea84365
--- /dev/null
+++ b/drivers/acpi/pci_mcfg.c
@@ -0,0 +1,312 @@
+/*
+ * pci_mcfg.c
+ *
+ * Common code to maintain the MCFG areas and mappings
+ *
+ * This has been extracted from arch/x86/pci/mmconfig-shared.c
+ * and moved here so that other architectures can use this code.
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/pci-acpi.h>
+#include <linux/sfi_acpi.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/rculist.h>
+
+#define PREFIX	"ACPI: "
+
+static DEFINE_MUTEX(pci_mmcfg_lock);
+LIST_HEAD(pci_mmcfg_list);
+
+static void list_add_sorted(struct pci_mmcfg_region *new)
+{
+	struct pci_mmcfg_region *cfg;
+
+	/* keep list sorted by segment and starting bus number */
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
+		if (cfg->segment > new->segment ||
+		    (cfg->segment == new->segment &&
+		     cfg->start_bus >= new->start_bus)) {
+			list_add_tail_rcu(&new->list, &cfg->list);
+			return;
+		}
+	}
+	list_add_tail_rcu(&new->list, &pci_mmcfg_list);
+}
+
+static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
+						   int end, u64 addr)
+{
+	struct pci_mmcfg_region *new;
+	struct resource *res;
+
+	if (addr == 0)
+		return NULL;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return NULL;
+
+	new->address = addr;
+	new->segment = segment;
+	new->start_bus = start;
+	new->end_bus = end;
+
+	res = &new->res;
+	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
+	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
+	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+	snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
+		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
+	res->name = new->name;
+
+	return new;
+}
+
+struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+							int end, u64 addr)
+{
+	struct pci_mmcfg_region *new;
+
+	new = pci_mmconfig_alloc(segment, start, end, addr);
+	if (new) {
+		mutex_lock(&pci_mmcfg_lock);
+		list_add_sorted(new);
+		mutex_unlock(&pci_mmcfg_lock);
+
+		pr_info(PREFIX
+		       "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
+		       "(base %#lx)\n",
+		       segment, start, end, &new->res, (unsigned long)addr);
+	}
+
+	return new;
+}
+
+struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
+{
+	struct pci_mmcfg_region *cfg;
+
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
+		if (cfg->segment == segment &&
+		    cfg->start_bus <= bus && bus <= cfg->end_bus)
+			return cfg;
+
+	return NULL;
+}
+
+/*
+ * Map a pci_mmcfg_region, can be overrriden by arch
+ */
+int __weak pci_mmconfig_map_resource(struct device *dev,
+	struct pci_mmcfg_region *mcfg)
+{
+	struct resource *tmp;
+	void __iomem *vaddr;
+
+	tmp = insert_resource_conflict(&iomem_resource, &mcfg->res);
+	if (tmp) {
+		dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
+			&mcfg->res, tmp->name, tmp);
+		return -EBUSY;
+	}
+
+	vaddr =  ioremap(mcfg->res.start, resource_size(&mcfg->res));
+	if (!vaddr) {
+		release_resource(&mcfg->res);
+		return -ENOMEM;
+	}
+
+	mcfg->virt = vaddr;
+	return 0;
+}
+
+/*
+ * Unmap a pci_mmcfg_region, can be overrriden by arch
+ */
+void __weak pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg)
+{
+	if (mcfg->virt) {
+		iounmap(mcfg->virt);
+		mcfg->virt = NULL;
+	}
+	if (mcfg->res.parent) {
+		release_resource(&mcfg->res);
+		mcfg->res.parent = NULL;
+	}
+}
+
+/*
+ * check if the mmconfig is enabled and configured
+ */
+int __weak pci_mmconfig_enabled(void)
+{
+	return 1;
+}
+
+/* Add MMCFG information for host bridges */
+int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+			phys_addr_t addr)
+{
+	struct pci_mmcfg_region *cfg;
+	int rc;
+
+	if (!pci_mmconfig_enabled())
+		return -ENODEV;
+	if (start > end)
+		return -EINVAL;
+
+	mutex_lock(&pci_mmcfg_lock);
+	cfg = pci_mmconfig_lookup(seg, start);
+	if (cfg) {
+		if (cfg->end_bus < end)
+			dev_info(dev, FW_INFO
+				 "MMCONFIG for "
+				 "domain %04x [bus %02x-%02x] "
+				 "only partially covers this bridge\n",
+				  cfg->segment, cfg->start_bus, cfg->end_bus);
+		rc = -EEXIST;
+		goto err;
+	}
+
+	if (!addr) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	cfg = pci_mmconfig_alloc(seg, start, end, addr);
+	if (cfg == NULL) {
+		dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+	rc = pci_mmconfig_map_resource(dev, cfg);
+	if (!rc) {
+		list_add_sorted(cfg);
+		dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
+				 &cfg->res, (unsigned long)addr);
+		return 0;
+	} else {
+		if (cfg->res.parent)
+			release_resource(&cfg->res);
+		kfree(cfg);
+	}
+
+err:
+	mutex_unlock(&pci_mmcfg_lock);
+	return rc;
+}
+
+/* Delete MMCFG information for host bridges */
+int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
+{
+	struct pci_mmcfg_region *cfg;
+
+	mutex_lock(&pci_mmcfg_lock);
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
+		if (cfg->segment == seg && cfg->start_bus == start &&
+		    cfg->end_bus == end) {
+			list_del_rcu(&cfg->list);
+			synchronize_rcu();
+			pci_mmconfig_unmap_resource(cfg);
+			mutex_unlock(&pci_mmcfg_lock);
+			kfree(cfg);
+			return 0;
+		}
+	mutex_unlock(&pci_mmcfg_lock);
+
+	return -ENOENT;
+}
+
+static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+					struct acpi_mcfg_allocation *cfg)
+{
+	int year;
+
+	if (!config_enabled(CONFIG_X86))
+		return 0;
+
+	if (cfg->address < 0xFFFFFFFF)
+		return 0;
+
+	if (!strncmp(mcfg->header.oem_id, "SGI", 3))
+		return 0;
+
+	if (mcfg->header.revision >= 1) {
+		if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
+		    year >= 2010)
+			return 0;
+	}
+
+	pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
+	       "is above 4GB, ignored\n", cfg->pci_segment,
+	       cfg->start_bus_number, cfg->end_bus_number, cfg->address);
+	return -EINVAL;
+}
+
+static int __init pci_parse_mcfg(struct acpi_table_header *header)
+{
+	struct acpi_table_mcfg *mcfg;
+	struct acpi_mcfg_allocation *cfg_table, *cfg;
+	unsigned long i;
+	int entries;
+
+	if (!header)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *)header;
+
+	/* how many config structures do we have */
+	entries = 0;
+	i = header->length - sizeof(struct acpi_table_mcfg);
+	while (i >= sizeof(struct acpi_mcfg_allocation)) {
+		entries++;
+		i -= sizeof(struct acpi_mcfg_allocation);
+	}
+	if (entries == 0) {
+		pr_err(PREFIX "MMCONFIG has no entries\n");
+		return -ENODEV;
+	}
+
+	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
+	for (i = 0; i < entries; i++) {
+		cfg = &cfg_table[i];
+		if (acpi_mcfg_check_entry(mcfg, cfg))
+			return -ENODEV;
+
+		if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
+				   cfg->end_bus_number, cfg->address) == NULL) {
+			pr_warn(PREFIX "no memory for MCFG entries\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int __init pci_mmconfig_parse_table(void)
+{
+	return acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+}
+
+void __weak __init pci_mmcfg_late_init(void)
+{
+	int err, n = 0;
+	struct pci_mmcfg_region *cfg;
+
+	err = pci_mmconfig_parse_table();
+	if (err) {
+		pr_err(PREFIX " Failed to parse MCFG (%d)\n", err);
+		return;
+	}
+
+	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+		pci_mmconfig_map_resource(NULL, cfg);
+		n++;
+	}
+
+	pr_info(PREFIX " MCFG table loaded %d entries\n", n);
+}
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
index 7494dbe..97aa9d3 100644
--- a/drivers/xen/pci.c
+++ b/drivers/xen/pci.c
@@ -27,9 +27,6 @@
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 #include "../pci/pci.h"
-#ifdef CONFIG_PCI_MMCONFIG
-#include <asm/pci_x86.h>
-#endif
 
 static bool __read_mostly pci_seg_supported = true;
 
@@ -221,7 +218,7 @@ static int __init xen_mcfg_late(void)
 	if (!xen_initial_domain())
 		return 0;
 
-	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+	if (!pci_mmconfig_enabled())
 		return 0;
 
 	if (list_empty(&pci_mmcfg_list))
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 89ab057..e9450ef 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -106,6 +106,39 @@ extern const u8 pci_acpi_dsm_uuid[];
 #define RESET_DELAY_DSM		0x08
 #define FUNCTION_DELAY_DSM	0x09
 
+/* common API to maintain list of MCFG regions */
+/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
+#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
+
+struct pci_mmcfg_region {
+	struct list_head list;
+	struct resource res;
+	u64 address;
+	char __iomem *virt;
+	u16 segment;
+	u8 start_bus;
+	u8 end_bus;
+	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
+};
+
+extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+			       phys_addr_t addr);
+extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
+
+extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
+extern struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+							int end, u64 addr);
+extern int pci_mmconfig_map_resource(struct device *dev,
+	struct pci_mmcfg_region *mcfg);
+extern void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg);
+extern int pci_mmconfig_enabled(void);
+extern int __init pci_mmconfig_parse_table(void);
+
+extern struct list_head pci_mmcfg_list;
+
+#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
+#define PCI_MMCFG_OFFSET(bus, devfn)   ((bus) << 20 | (devfn) << 12)
+
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 1/5] APCI: MCFG: Move mmcfg_list management to drivers/acpi
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

Move pci_mmcfg_list handling to a drivers/acpi/pci_mcfg.c. This is
to share the API and code with ARM64 later. The corresponding
declarations are moved from asm/pci_x86.h to linux/pci-acpi.h

As a part of this we introduce three functions that can be
implemented by the arch code: pci_mmconfig_map_resource() to map a
mcfg entry, pci_mmconfig_unmap_resource to do the corresponding
unmap and pci_mmconfig_enabled to see if the arch setup of
mcfg entries was successful. We also provide weak implementations
of these, which will be used from ARM64. On x86, we retain the
old logic by providing platform specific implementation.

This patch is purely rearranging code, it should not have any
impact on the logic of MCFG parsing or list handling.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
[Xen parts:]
Acked-by: David Vrabel <david.vrabel@citrix.com>

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 arch/x86/include/asm/pci_x86.h |  24 +---
 arch/x86/pci/mmconfig-shared.c | 269 +++++------------------------------
 arch/x86/pci/mmconfig_32.c     |   1 +
 arch/x86/pci/mmconfig_64.c     |   1 +
 arch/x86/pci/numachip.c        |   1 +
 drivers/acpi/Makefile          |   1 +
 drivers/acpi/pci_mcfg.c        | 312 +++++++++++++++++++++++++++++++++++++++++
 drivers/xen/pci.c              |   5 +-
 include/linux/pci-acpi.h       |  33 +++++
 9 files changed, 386 insertions(+), 261 deletions(-)
 create mode 100644 drivers/acpi/pci_mcfg.c

diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index 46873fb..7824626 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -122,33 +122,11 @@ extern int pci_legacy_init(void);
 extern void pcibios_fixup_irqs(void);
 
 /* pci-mmconfig.c */
-
-/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
-#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
-
-struct pci_mmcfg_region {
-	struct list_head list;
-	struct resource res;
-	u64 address;
-	char __iomem *virt;
-	u16 segment;
-	u8 start_bus;
-	u8 end_bus;
-	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
-};
-
+struct pci_mmcfg_region;
 extern int __init pci_mmcfg_arch_init(void);
 extern void __init pci_mmcfg_arch_free(void);
 extern int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
 extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
-extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
-			       phys_addr_t addr);
-extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
-extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
-
-extern struct list_head pci_mmcfg_list;
-
-#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
 
 /*
  * On AMD Fam10h CPUs, all PCI MMIO configuration space accesses must use
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index dd30b7e..626710b 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -12,13 +12,12 @@
 
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/sfi_acpi.h>
 #include <linux/bitmap.h>
-#include <linux/dmi.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/rculist.h>
 #include <asm/e820.h>
+#include <linux/pci-acpi.h>
 #include <asm/pci_x86.h>
 #include <asm/acpi.h>
 
@@ -27,9 +26,6 @@
 /* Indicate if the mmcfg resources have been placed into the resource table. */
 static bool pci_mmcfg_running_state;
 static bool pci_mmcfg_arch_init_failed;
-static DEFINE_MUTEX(pci_mmcfg_lock);
-
-LIST_HEAD(pci_mmcfg_list);
 
 static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
 {
@@ -48,83 +44,6 @@ static void __init free_all_mmcfg(void)
 		pci_mmconfig_remove(cfg);
 }
 
-static void list_add_sorted(struct pci_mmcfg_region *new)
-{
-	struct pci_mmcfg_region *cfg;
-
-	/* keep list sorted by segment and starting bus number */
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
-		if (cfg->segment > new->segment ||
-		    (cfg->segment == new->segment &&
-		     cfg->start_bus >= new->start_bus)) {
-			list_add_tail_rcu(&new->list, &cfg->list);
-			return;
-		}
-	}
-	list_add_tail_rcu(&new->list, &pci_mmcfg_list);
-}
-
-static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
-						   int end, u64 addr)
-{
-	struct pci_mmcfg_region *new;
-	struct resource *res;
-
-	if (addr == 0)
-		return NULL;
-
-	new = kzalloc(sizeof(*new), GFP_KERNEL);
-	if (!new)
-		return NULL;
-
-	new->address = addr;
-	new->segment = segment;
-	new->start_bus = start;
-	new->end_bus = end;
-
-	res = &new->res;
-	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
-	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
-	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-	snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
-		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
-	res->name = new->name;
-
-	return new;
-}
-
-static struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
-							int end, u64 addr)
-{
-	struct pci_mmcfg_region *new;
-
-	new = pci_mmconfig_alloc(segment, start, end, addr);
-	if (new) {
-		mutex_lock(&pci_mmcfg_lock);
-		list_add_sorted(new);
-		mutex_unlock(&pci_mmcfg_lock);
-
-		pr_info(PREFIX
-		       "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
-		       "(base %#lx)\n",
-		       segment, start, end, &new->res, (unsigned long)addr);
-	}
-
-	return new;
-}
-
-struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
-{
-	struct pci_mmcfg_region *cfg;
-
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
-		if (cfg->segment == segment &&
-		    cfg->start_bus <= bus && bus <= cfg->end_bus)
-			return cfg;
-
-	return NULL;
-}
-
 static const char *__init pci_mmcfg_e7520(void)
 {
 	u32 win;
@@ -543,73 +462,6 @@ static void __init pci_mmcfg_reject_broken(int early)
 	}
 }
 
-static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
-					struct acpi_mcfg_allocation *cfg)
-{
-	int year;
-
-	if (cfg->address < 0xFFFFFFFF)
-		return 0;
-
-	if (!strncmp(mcfg->header.oem_id, "SGI", 3))
-		return 0;
-
-	if (mcfg->header.revision >= 1) {
-		if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
-		    year >= 2010)
-			return 0;
-	}
-
-	pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
-	       "is above 4GB, ignored\n", cfg->pci_segment,
-	       cfg->start_bus_number, cfg->end_bus_number, cfg->address);
-	return -EINVAL;
-}
-
-static int __init pci_parse_mcfg(struct acpi_table_header *header)
-{
-	struct acpi_table_mcfg *mcfg;
-	struct acpi_mcfg_allocation *cfg_table, *cfg;
-	unsigned long i;
-	int entries;
-
-	if (!header)
-		return -EINVAL;
-
-	mcfg = (struct acpi_table_mcfg *)header;
-
-	/* how many config structures do we have */
-	free_all_mmcfg();
-	entries = 0;
-	i = header->length - sizeof(struct acpi_table_mcfg);
-	while (i >= sizeof(struct acpi_mcfg_allocation)) {
-		entries++;
-		i -= sizeof(struct acpi_mcfg_allocation);
-	}
-	if (entries == 0) {
-		pr_err(PREFIX "MMCONFIG has no entries\n");
-		return -ENODEV;
-	}
-
-	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
-	for (i = 0; i < entries; i++) {
-		cfg = &cfg_table[i];
-		if (acpi_mcfg_check_entry(mcfg, cfg)) {
-			free_all_mmcfg();
-			return -ENODEV;
-		}
-
-		if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
-				   cfg->end_bus_number, cfg->address) == NULL) {
-			pr_warn(PREFIX "no memory for MCFG entries\n");
-			free_all_mmcfg();
-			return -ENOMEM;
-		}
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_ACPI_APEI
 extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,
 				     void *data), void *data);
@@ -662,13 +514,20 @@ static void __init __pci_mmcfg_init(int early)
 
 static int __initdata known_bridge;
 
+static void __init pci_mmcfg_list_setup(void)
+{
+	free_all_mmcfg();
+	if (pci_mmconfig_parse_table())
+		free_all_mmcfg();
+}
+
 void __init pci_mmcfg_early_init(void)
 {
 	if (pci_probe & PCI_PROBE_MMCONF) {
 		if (pci_mmcfg_check_hostbridge())
 			known_bridge = 1;
 		else
-			acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+			pci_mmcfg_list_setup();
 		__pci_mmcfg_init(1);
 
 		set_apei_filter();
@@ -686,7 +545,7 @@ void __init pci_mmcfg_late_init(void)
 
 	/* MMCONFIG hasn't been enabled yet, try again */
 	if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) {
-		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+		pci_mmcfg_list_setup();
 		__pci_mmcfg_init(0);
 	}
 }
@@ -720,99 +579,41 @@ static int __init pci_mmcfg_late_insert_resources(void)
  */
 late_initcall(pci_mmcfg_late_insert_resources);
 
-/* Add MMCFG information for host bridges */
-int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
-			phys_addr_t addr)
+int pci_mmconfig_map_resource(struct device *dev, struct pci_mmcfg_region *cfg)
 {
-	int rc;
-	struct resource *tmp = NULL;
-	struct pci_mmcfg_region *cfg;
+	struct resource *tmp;
 
-	if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
-		return -ENODEV;
-
-	if (start > end)
-		return -EINVAL;
-
-	mutex_lock(&pci_mmcfg_lock);
-	cfg = pci_mmconfig_lookup(seg, start);
-	if (cfg) {
-		if (cfg->end_bus < end)
-			dev_info(dev, FW_INFO
-				 "MMCONFIG for "
-				 "domain %04x [bus %02x-%02x] "
-				 "only partially covers this bridge\n",
-				  cfg->segment, cfg->start_bus, cfg->end_bus);
-		mutex_unlock(&pci_mmcfg_lock);
-		return -EEXIST;
-	}
-
-	if (!addr) {
-		mutex_unlock(&pci_mmcfg_lock);
-		return -EINVAL;
-	}
-
-	rc = -EBUSY;
-	cfg = pci_mmconfig_alloc(seg, start, end, addr);
-	if (cfg == NULL) {
-		dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
-		rc = -ENOMEM;
-	} else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
+	if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
 		dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n",
 			 &cfg->res);
-	} else {
-		/* Insert resource if it's not in boot stage */
-		if (pci_mmcfg_running_state)
-			tmp = insert_resource_conflict(&iomem_resource,
-						       &cfg->res);
-
+		return -EBUSY;
+	}
+	/* Insert resource if it's not in boot stage */
+	if (pci_mmcfg_running_state) {
+		tmp = insert_resource_conflict(&iomem_resource,
+					       &cfg->res);
 		if (tmp) {
-			dev_warn(dev,
-				 "MMCONFIG %pR conflicts with "
-				 "%s %pR\n",
-				 &cfg->res, tmp->name, tmp);
-		} else if (pci_mmcfg_arch_map(cfg)) {
-			dev_warn(dev, "fail to map MMCONFIG %pR.\n",
-				 &cfg->res);
-		} else {
-			list_add_sorted(cfg);
-			dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
-				 &cfg->res, (unsigned long)addr);
-			cfg = NULL;
-			rc = 0;
+			dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
+				&cfg->res, tmp->name, tmp);
+			return -EBUSY;
 		}
 	}
-
-	if (cfg) {
-		if (cfg->res.parent)
-			release_resource(&cfg->res);
-		kfree(cfg);
+	if (pci_mmcfg_arch_map(cfg)) {
+		dev_warn(dev, "fail to map MMCONFIG %pR.\n", &cfg->res);
+		return -EBUSY;
 	}
-
-	mutex_unlock(&pci_mmcfg_lock);
-
-	return rc;
+	return 0;
 }
 
-/* Delete MMCFG information for host bridges */
-int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
+void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *cfg)
 {
-	struct pci_mmcfg_region *cfg;
-
-	mutex_lock(&pci_mmcfg_lock);
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
-		if (cfg->segment == seg && cfg->start_bus == start &&
-		    cfg->end_bus == end) {
-			list_del_rcu(&cfg->list);
-			synchronize_rcu();
-			pci_mmcfg_arch_unmap(cfg);
-			if (cfg->res.parent)
-				release_resource(&cfg->res);
-			mutex_unlock(&pci_mmcfg_lock);
-			kfree(cfg);
-			return 0;
-		}
-	mutex_unlock(&pci_mmcfg_lock);
+	pci_mmcfg_arch_unmap(cfg);
+	if (cfg->res.parent)
+		release_resource(&cfg->res);
+	cfg->res.parent = NULL;
+}
 
-	return -ENOENT;
+int pci_mmconfig_enabled(void)
+{
+	return (pci_probe & PCI_PROBE_MMCONF) && !pci_mmcfg_arch_init_failed;
 }
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 43984bc..38a37f8 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -12,6 +12,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/rcupdate.h>
+#include <linux/pci-acpi.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index bea5249..29253ec 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -10,6 +10,7 @@
 #include <linux/acpi.h>
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
+#include <linux/pci-acpi.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
diff --git a/arch/x86/pci/numachip.c b/arch/x86/pci/numachip.c
index 2e565e6..c181eeb 100644
--- a/arch/x86/pci/numachip.c
+++ b/arch/x86/pci/numachip.c
@@ -14,6 +14,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <asm/pci_x86.h>
 
 static u8 limit __read_mostly;
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index cb648a4..74976f1 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
 acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
+acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
 acpi-y				+= acpi_lpss.o acpi_apd.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= acpi_pnp.o
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
new file mode 100644
index 0000000..ea84365
--- /dev/null
+++ b/drivers/acpi/pci_mcfg.c
@@ -0,0 +1,312 @@
+/*
+ * pci_mcfg.c
+ *
+ * Common code to maintain the MCFG areas and mappings
+ *
+ * This has been extracted from arch/x86/pci/mmconfig-shared.c
+ * and moved here so that other architectures can use this code.
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/pci-acpi.h>
+#include <linux/sfi_acpi.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/rculist.h>
+
+#define PREFIX	"ACPI: "
+
+static DEFINE_MUTEX(pci_mmcfg_lock);
+LIST_HEAD(pci_mmcfg_list);
+
+static void list_add_sorted(struct pci_mmcfg_region *new)
+{
+	struct pci_mmcfg_region *cfg;
+
+	/* keep list sorted by segment and starting bus number */
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
+		if (cfg->segment > new->segment ||
+		    (cfg->segment == new->segment &&
+		     cfg->start_bus >= new->start_bus)) {
+			list_add_tail_rcu(&new->list, &cfg->list);
+			return;
+		}
+	}
+	list_add_tail_rcu(&new->list, &pci_mmcfg_list);
+}
+
+static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
+						   int end, u64 addr)
+{
+	struct pci_mmcfg_region *new;
+	struct resource *res;
+
+	if (addr == 0)
+		return NULL;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return NULL;
+
+	new->address = addr;
+	new->segment = segment;
+	new->start_bus = start;
+	new->end_bus = end;
+
+	res = &new->res;
+	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
+	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
+	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+	snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
+		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
+	res->name = new->name;
+
+	return new;
+}
+
+struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+							int end, u64 addr)
+{
+	struct pci_mmcfg_region *new;
+
+	new = pci_mmconfig_alloc(segment, start, end, addr);
+	if (new) {
+		mutex_lock(&pci_mmcfg_lock);
+		list_add_sorted(new);
+		mutex_unlock(&pci_mmcfg_lock);
+
+		pr_info(PREFIX
+		       "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
+		       "(base %#lx)\n",
+		       segment, start, end, &new->res, (unsigned long)addr);
+	}
+
+	return new;
+}
+
+struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
+{
+	struct pci_mmcfg_region *cfg;
+
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
+		if (cfg->segment == segment &&
+		    cfg->start_bus <= bus && bus <= cfg->end_bus)
+			return cfg;
+
+	return NULL;
+}
+
+/*
+ * Map a pci_mmcfg_region, can be overrriden by arch
+ */
+int __weak pci_mmconfig_map_resource(struct device *dev,
+	struct pci_mmcfg_region *mcfg)
+{
+	struct resource *tmp;
+	void __iomem *vaddr;
+
+	tmp = insert_resource_conflict(&iomem_resource, &mcfg->res);
+	if (tmp) {
+		dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
+			&mcfg->res, tmp->name, tmp);
+		return -EBUSY;
+	}
+
+	vaddr =  ioremap(mcfg->res.start, resource_size(&mcfg->res));
+	if (!vaddr) {
+		release_resource(&mcfg->res);
+		return -ENOMEM;
+	}
+
+	mcfg->virt = vaddr;
+	return 0;
+}
+
+/*
+ * Unmap a pci_mmcfg_region, can be overrriden by arch
+ */
+void __weak pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg)
+{
+	if (mcfg->virt) {
+		iounmap(mcfg->virt);
+		mcfg->virt = NULL;
+	}
+	if (mcfg->res.parent) {
+		release_resource(&mcfg->res);
+		mcfg->res.parent = NULL;
+	}
+}
+
+/*
+ * check if the mmconfig is enabled and configured
+ */
+int __weak pci_mmconfig_enabled(void)
+{
+	return 1;
+}
+
+/* Add MMCFG information for host bridges */
+int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+			phys_addr_t addr)
+{
+	struct pci_mmcfg_region *cfg;
+	int rc;
+
+	if (!pci_mmconfig_enabled())
+		return -ENODEV;
+	if (start > end)
+		return -EINVAL;
+
+	mutex_lock(&pci_mmcfg_lock);
+	cfg = pci_mmconfig_lookup(seg, start);
+	if (cfg) {
+		if (cfg->end_bus < end)
+			dev_info(dev, FW_INFO
+				 "MMCONFIG for "
+				 "domain %04x [bus %02x-%02x] "
+				 "only partially covers this bridge\n",
+				  cfg->segment, cfg->start_bus, cfg->end_bus);
+		rc = -EEXIST;
+		goto err;
+	}
+
+	if (!addr) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	cfg = pci_mmconfig_alloc(seg, start, end, addr);
+	if (cfg == NULL) {
+		dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+	rc = pci_mmconfig_map_resource(dev, cfg);
+	if (!rc) {
+		list_add_sorted(cfg);
+		dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
+				 &cfg->res, (unsigned long)addr);
+		return 0;
+	} else {
+		if (cfg->res.parent)
+			release_resource(&cfg->res);
+		kfree(cfg);
+	}
+
+err:
+	mutex_unlock(&pci_mmcfg_lock);
+	return rc;
+}
+
+/* Delete MMCFG information for host bridges */
+int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
+{
+	struct pci_mmcfg_region *cfg;
+
+	mutex_lock(&pci_mmcfg_lock);
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
+		if (cfg->segment == seg && cfg->start_bus == start &&
+		    cfg->end_bus == end) {
+			list_del_rcu(&cfg->list);
+			synchronize_rcu();
+			pci_mmconfig_unmap_resource(cfg);
+			mutex_unlock(&pci_mmcfg_lock);
+			kfree(cfg);
+			return 0;
+		}
+	mutex_unlock(&pci_mmcfg_lock);
+
+	return -ENOENT;
+}
+
+static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+					struct acpi_mcfg_allocation *cfg)
+{
+	int year;
+
+	if (!config_enabled(CONFIG_X86))
+		return 0;
+
+	if (cfg->address < 0xFFFFFFFF)
+		return 0;
+
+	if (!strncmp(mcfg->header.oem_id, "SGI", 3))
+		return 0;
+
+	if (mcfg->header.revision >= 1) {
+		if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
+		    year >= 2010)
+			return 0;
+	}
+
+	pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
+	       "is above 4GB, ignored\n", cfg->pci_segment,
+	       cfg->start_bus_number, cfg->end_bus_number, cfg->address);
+	return -EINVAL;
+}
+
+static int __init pci_parse_mcfg(struct acpi_table_header *header)
+{
+	struct acpi_table_mcfg *mcfg;
+	struct acpi_mcfg_allocation *cfg_table, *cfg;
+	unsigned long i;
+	int entries;
+
+	if (!header)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *)header;
+
+	/* how many config structures do we have */
+	entries = 0;
+	i = header->length - sizeof(struct acpi_table_mcfg);
+	while (i >= sizeof(struct acpi_mcfg_allocation)) {
+		entries++;
+		i -= sizeof(struct acpi_mcfg_allocation);
+	}
+	if (entries == 0) {
+		pr_err(PREFIX "MMCONFIG has no entries\n");
+		return -ENODEV;
+	}
+
+	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
+	for (i = 0; i < entries; i++) {
+		cfg = &cfg_table[i];
+		if (acpi_mcfg_check_entry(mcfg, cfg))
+			return -ENODEV;
+
+		if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
+				   cfg->end_bus_number, cfg->address) == NULL) {
+			pr_warn(PREFIX "no memory for MCFG entries\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int __init pci_mmconfig_parse_table(void)
+{
+	return acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+}
+
+void __weak __init pci_mmcfg_late_init(void)
+{
+	int err, n = 0;
+	struct pci_mmcfg_region *cfg;
+
+	err = pci_mmconfig_parse_table();
+	if (err) {
+		pr_err(PREFIX " Failed to parse MCFG (%d)\n", err);
+		return;
+	}
+
+	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+		pci_mmconfig_map_resource(NULL, cfg);
+		n++;
+	}
+
+	pr_info(PREFIX " MCFG table loaded %d entries\n", n);
+}
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
index 7494dbe..97aa9d3 100644
--- a/drivers/xen/pci.c
+++ b/drivers/xen/pci.c
@@ -27,9 +27,6 @@
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 #include "../pci/pci.h"
-#ifdef CONFIG_PCI_MMCONFIG
-#include <asm/pci_x86.h>
-#endif
 
 static bool __read_mostly pci_seg_supported = true;
 
@@ -221,7 +218,7 @@ static int __init xen_mcfg_late(void)
 	if (!xen_initial_domain())
 		return 0;
 
-	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+	if (!pci_mmconfig_enabled())
 		return 0;
 
 	if (list_empty(&pci_mmcfg_list))
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 89ab057..e9450ef 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -106,6 +106,39 @@ extern const u8 pci_acpi_dsm_uuid[];
 #define RESET_DELAY_DSM		0x08
 #define FUNCTION_DELAY_DSM	0x09
 
+/* common API to maintain list of MCFG regions */
+/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
+#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
+
+struct pci_mmcfg_region {
+	struct list_head list;
+	struct resource res;
+	u64 address;
+	char __iomem *virt;
+	u16 segment;
+	u8 start_bus;
+	u8 end_bus;
+	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
+};
+
+extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+			       phys_addr_t addr);
+extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
+
+extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
+extern struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+							int end, u64 addr);
+extern int pci_mmconfig_map_resource(struct device *dev,
+	struct pci_mmcfg_region *mcfg);
+extern void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg);
+extern int pci_mmconfig_enabled(void);
+extern int __init pci_mmconfig_parse_table(void);
+
+extern struct list_head pci_mmcfg_list;
+
+#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
+#define PCI_MMCFG_OFFSET(bus, devfn)   ((bus) << 20 | (devfn) << 12)
+
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 1/5] APCI: MCFG: Move mmcfg_list management to drivers/acpi
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

Move pci_mmcfg_list handling to a drivers/acpi/pci_mcfg.c. This is
to share the API and code with ARM64 later. The corresponding
declarations are moved from asm/pci_x86.h to linux/pci-acpi.h

As a part of this we introduce three functions that can be
implemented by the arch code: pci_mmconfig_map_resource() to map a
mcfg entry, pci_mmconfig_unmap_resource to do the corresponding
unmap and pci_mmconfig_enabled to see if the arch setup of
mcfg entries was successful. We also provide weak implementations
of these, which will be used from ARM64. On x86, we retain the
old logic by providing platform specific implementation.

This patch is purely rearranging code, it should not have any
impact on the logic of MCFG parsing or list handling.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
[Xen parts:]
Acked-by: David Vrabel <david.vrabel@citrix.com>

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 arch/x86/include/asm/pci_x86.h |  24 +---
 arch/x86/pci/mmconfig-shared.c | 269 +++++------------------------------
 arch/x86/pci/mmconfig_32.c     |   1 +
 arch/x86/pci/mmconfig_64.c     |   1 +
 arch/x86/pci/numachip.c        |   1 +
 drivers/acpi/Makefile          |   1 +
 drivers/acpi/pci_mcfg.c        | 312 +++++++++++++++++++++++++++++++++++++++++
 drivers/xen/pci.c              |   5 +-
 include/linux/pci-acpi.h       |  33 +++++
 9 files changed, 386 insertions(+), 261 deletions(-)
 create mode 100644 drivers/acpi/pci_mcfg.c

diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index 46873fb..7824626 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -122,33 +122,11 @@ extern int pci_legacy_init(void);
 extern void pcibios_fixup_irqs(void);
 
 /* pci-mmconfig.c */
-
-/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
-#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
-
-struct pci_mmcfg_region {
-	struct list_head list;
-	struct resource res;
-	u64 address;
-	char __iomem *virt;
-	u16 segment;
-	u8 start_bus;
-	u8 end_bus;
-	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
-};
-
+struct pci_mmcfg_region;
 extern int __init pci_mmcfg_arch_init(void);
 extern void __init pci_mmcfg_arch_free(void);
 extern int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
 extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
-extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
-			       phys_addr_t addr);
-extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
-extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
-
-extern struct list_head pci_mmcfg_list;
-
-#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
 
 /*
  * On AMD Fam10h CPUs, all PCI MMIO configuration space accesses must use
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index dd30b7e..626710b 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -12,13 +12,12 @@
 
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/sfi_acpi.h>
 #include <linux/bitmap.h>
-#include <linux/dmi.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/rculist.h>
 #include <asm/e820.h>
+#include <linux/pci-acpi.h>
 #include <asm/pci_x86.h>
 #include <asm/acpi.h>
 
@@ -27,9 +26,6 @@
 /* Indicate if the mmcfg resources have been placed into the resource table. */
 static bool pci_mmcfg_running_state;
 static bool pci_mmcfg_arch_init_failed;
-static DEFINE_MUTEX(pci_mmcfg_lock);
-
-LIST_HEAD(pci_mmcfg_list);
 
 static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
 {
@@ -48,83 +44,6 @@ static void __init free_all_mmcfg(void)
 		pci_mmconfig_remove(cfg);
 }
 
-static void list_add_sorted(struct pci_mmcfg_region *new)
-{
-	struct pci_mmcfg_region *cfg;
-
-	/* keep list sorted by segment and starting bus number */
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
-		if (cfg->segment > new->segment ||
-		    (cfg->segment == new->segment &&
-		     cfg->start_bus >= new->start_bus)) {
-			list_add_tail_rcu(&new->list, &cfg->list);
-			return;
-		}
-	}
-	list_add_tail_rcu(&new->list, &pci_mmcfg_list);
-}
-
-static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
-						   int end, u64 addr)
-{
-	struct pci_mmcfg_region *new;
-	struct resource *res;
-
-	if (addr == 0)
-		return NULL;
-
-	new = kzalloc(sizeof(*new), GFP_KERNEL);
-	if (!new)
-		return NULL;
-
-	new->address = addr;
-	new->segment = segment;
-	new->start_bus = start;
-	new->end_bus = end;
-
-	res = &new->res;
-	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
-	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
-	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-	snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
-		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
-	res->name = new->name;
-
-	return new;
-}
-
-static struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
-							int end, u64 addr)
-{
-	struct pci_mmcfg_region *new;
-
-	new = pci_mmconfig_alloc(segment, start, end, addr);
-	if (new) {
-		mutex_lock(&pci_mmcfg_lock);
-		list_add_sorted(new);
-		mutex_unlock(&pci_mmcfg_lock);
-
-		pr_info(PREFIX
-		       "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
-		       "(base %#lx)\n",
-		       segment, start, end, &new->res, (unsigned long)addr);
-	}
-
-	return new;
-}
-
-struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
-{
-	struct pci_mmcfg_region *cfg;
-
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
-		if (cfg->segment == segment &&
-		    cfg->start_bus <= bus && bus <= cfg->end_bus)
-			return cfg;
-
-	return NULL;
-}
-
 static const char *__init pci_mmcfg_e7520(void)
 {
 	u32 win;
@@ -543,73 +462,6 @@ static void __init pci_mmcfg_reject_broken(int early)
 	}
 }
 
-static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
-					struct acpi_mcfg_allocation *cfg)
-{
-	int year;
-
-	if (cfg->address < 0xFFFFFFFF)
-		return 0;
-
-	if (!strncmp(mcfg->header.oem_id, "SGI", 3))
-		return 0;
-
-	if (mcfg->header.revision >= 1) {
-		if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
-		    year >= 2010)
-			return 0;
-	}
-
-	pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
-	       "is above 4GB, ignored\n", cfg->pci_segment,
-	       cfg->start_bus_number, cfg->end_bus_number, cfg->address);
-	return -EINVAL;
-}
-
-static int __init pci_parse_mcfg(struct acpi_table_header *header)
-{
-	struct acpi_table_mcfg *mcfg;
-	struct acpi_mcfg_allocation *cfg_table, *cfg;
-	unsigned long i;
-	int entries;
-
-	if (!header)
-		return -EINVAL;
-
-	mcfg = (struct acpi_table_mcfg *)header;
-
-	/* how many config structures do we have */
-	free_all_mmcfg();
-	entries = 0;
-	i = header->length - sizeof(struct acpi_table_mcfg);
-	while (i >= sizeof(struct acpi_mcfg_allocation)) {
-		entries++;
-		i -= sizeof(struct acpi_mcfg_allocation);
-	}
-	if (entries == 0) {
-		pr_err(PREFIX "MMCONFIG has no entries\n");
-		return -ENODEV;
-	}
-
-	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
-	for (i = 0; i < entries; i++) {
-		cfg = &cfg_table[i];
-		if (acpi_mcfg_check_entry(mcfg, cfg)) {
-			free_all_mmcfg();
-			return -ENODEV;
-		}
-
-		if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
-				   cfg->end_bus_number, cfg->address) == NULL) {
-			pr_warn(PREFIX "no memory for MCFG entries\n");
-			free_all_mmcfg();
-			return -ENOMEM;
-		}
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_ACPI_APEI
 extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,
 				     void *data), void *data);
@@ -662,13 +514,20 @@ static void __init __pci_mmcfg_init(int early)
 
 static int __initdata known_bridge;
 
+static void __init pci_mmcfg_list_setup(void)
+{
+	free_all_mmcfg();
+	if (pci_mmconfig_parse_table())
+		free_all_mmcfg();
+}
+
 void __init pci_mmcfg_early_init(void)
 {
 	if (pci_probe & PCI_PROBE_MMCONF) {
 		if (pci_mmcfg_check_hostbridge())
 			known_bridge = 1;
 		else
-			acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+			pci_mmcfg_list_setup();
 		__pci_mmcfg_init(1);
 
 		set_apei_filter();
@@ -686,7 +545,7 @@ void __init pci_mmcfg_late_init(void)
 
 	/* MMCONFIG hasn't been enabled yet, try again */
 	if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) {
-		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+		pci_mmcfg_list_setup();
 		__pci_mmcfg_init(0);
 	}
 }
@@ -720,99 +579,41 @@ static int __init pci_mmcfg_late_insert_resources(void)
  */
 late_initcall(pci_mmcfg_late_insert_resources);
 
-/* Add MMCFG information for host bridges */
-int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
-			phys_addr_t addr)
+int pci_mmconfig_map_resource(struct device *dev, struct pci_mmcfg_region *cfg)
 {
-	int rc;
-	struct resource *tmp = NULL;
-	struct pci_mmcfg_region *cfg;
+	struct resource *tmp;
 
-	if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
-		return -ENODEV;
-
-	if (start > end)
-		return -EINVAL;
-
-	mutex_lock(&pci_mmcfg_lock);
-	cfg = pci_mmconfig_lookup(seg, start);
-	if (cfg) {
-		if (cfg->end_bus < end)
-			dev_info(dev, FW_INFO
-				 "MMCONFIG for "
-				 "domain %04x [bus %02x-%02x] "
-				 "only partially covers this bridge\n",
-				  cfg->segment, cfg->start_bus, cfg->end_bus);
-		mutex_unlock(&pci_mmcfg_lock);
-		return -EEXIST;
-	}
-
-	if (!addr) {
-		mutex_unlock(&pci_mmcfg_lock);
-		return -EINVAL;
-	}
-
-	rc = -EBUSY;
-	cfg = pci_mmconfig_alloc(seg, start, end, addr);
-	if (cfg == NULL) {
-		dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
-		rc = -ENOMEM;
-	} else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
+	if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
 		dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n",
 			 &cfg->res);
-	} else {
-		/* Insert resource if it's not in boot stage */
-		if (pci_mmcfg_running_state)
-			tmp = insert_resource_conflict(&iomem_resource,
-						       &cfg->res);
-
+		return -EBUSY;
+	}
+	/* Insert resource if it's not in boot stage */
+	if (pci_mmcfg_running_state) {
+		tmp = insert_resource_conflict(&iomem_resource,
+					       &cfg->res);
 		if (tmp) {
-			dev_warn(dev,
-				 "MMCONFIG %pR conflicts with "
-				 "%s %pR\n",
-				 &cfg->res, tmp->name, tmp);
-		} else if (pci_mmcfg_arch_map(cfg)) {
-			dev_warn(dev, "fail to map MMCONFIG %pR.\n",
-				 &cfg->res);
-		} else {
-			list_add_sorted(cfg);
-			dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
-				 &cfg->res, (unsigned long)addr);
-			cfg = NULL;
-			rc = 0;
+			dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
+				&cfg->res, tmp->name, tmp);
+			return -EBUSY;
 		}
 	}
-
-	if (cfg) {
-		if (cfg->res.parent)
-			release_resource(&cfg->res);
-		kfree(cfg);
+	if (pci_mmcfg_arch_map(cfg)) {
+		dev_warn(dev, "fail to map MMCONFIG %pR.\n", &cfg->res);
+		return -EBUSY;
 	}
-
-	mutex_unlock(&pci_mmcfg_lock);
-
-	return rc;
+	return 0;
 }
 
-/* Delete MMCFG information for host bridges */
-int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
+void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *cfg)
 {
-	struct pci_mmcfg_region *cfg;
-
-	mutex_lock(&pci_mmcfg_lock);
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
-		if (cfg->segment == seg && cfg->start_bus == start &&
-		    cfg->end_bus == end) {
-			list_del_rcu(&cfg->list);
-			synchronize_rcu();
-			pci_mmcfg_arch_unmap(cfg);
-			if (cfg->res.parent)
-				release_resource(&cfg->res);
-			mutex_unlock(&pci_mmcfg_lock);
-			kfree(cfg);
-			return 0;
-		}
-	mutex_unlock(&pci_mmcfg_lock);
+	pci_mmcfg_arch_unmap(cfg);
+	if (cfg->res.parent)
+		release_resource(&cfg->res);
+	cfg->res.parent = NULL;
+}
 
-	return -ENOENT;
+int pci_mmconfig_enabled(void)
+{
+	return (pci_probe & PCI_PROBE_MMCONF) && !pci_mmcfg_arch_init_failed;
 }
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 43984bc..38a37f8 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -12,6 +12,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/rcupdate.h>
+#include <linux/pci-acpi.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index bea5249..29253ec 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -10,6 +10,7 @@
 #include <linux/acpi.h>
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
+#include <linux/pci-acpi.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
diff --git a/arch/x86/pci/numachip.c b/arch/x86/pci/numachip.c
index 2e565e6..c181eeb 100644
--- a/arch/x86/pci/numachip.c
+++ b/arch/x86/pci/numachip.c
@@ -14,6 +14,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <asm/pci_x86.h>
 
 static u8 limit __read_mostly;
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index cb648a4..74976f1 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
 acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
+acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
 acpi-y				+= acpi_lpss.o acpi_apd.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= acpi_pnp.o
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
new file mode 100644
index 0000000..ea84365
--- /dev/null
+++ b/drivers/acpi/pci_mcfg.c
@@ -0,0 +1,312 @@
+/*
+ * pci_mcfg.c
+ *
+ * Common code to maintain the MCFG areas and mappings
+ *
+ * This has been extracted from arch/x86/pci/mmconfig-shared.c
+ * and moved here so that other architectures can use this code.
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/pci-acpi.h>
+#include <linux/sfi_acpi.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/rculist.h>
+
+#define PREFIX	"ACPI: "
+
+static DEFINE_MUTEX(pci_mmcfg_lock);
+LIST_HEAD(pci_mmcfg_list);
+
+static void list_add_sorted(struct pci_mmcfg_region *new)
+{
+	struct pci_mmcfg_region *cfg;
+
+	/* keep list sorted by segment and starting bus number */
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
+		if (cfg->segment > new->segment ||
+		    (cfg->segment == new->segment &&
+		     cfg->start_bus >= new->start_bus)) {
+			list_add_tail_rcu(&new->list, &cfg->list);
+			return;
+		}
+	}
+	list_add_tail_rcu(&new->list, &pci_mmcfg_list);
+}
+
+static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
+						   int end, u64 addr)
+{
+	struct pci_mmcfg_region *new;
+	struct resource *res;
+
+	if (addr == 0)
+		return NULL;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return NULL;
+
+	new->address = addr;
+	new->segment = segment;
+	new->start_bus = start;
+	new->end_bus = end;
+
+	res = &new->res;
+	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
+	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
+	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+	snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
+		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
+	res->name = new->name;
+
+	return new;
+}
+
+struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+							int end, u64 addr)
+{
+	struct pci_mmcfg_region *new;
+
+	new = pci_mmconfig_alloc(segment, start, end, addr);
+	if (new) {
+		mutex_lock(&pci_mmcfg_lock);
+		list_add_sorted(new);
+		mutex_unlock(&pci_mmcfg_lock);
+
+		pr_info(PREFIX
+		       "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
+		       "(base %#lx)\n",
+		       segment, start, end, &new->res, (unsigned long)addr);
+	}
+
+	return new;
+}
+
+struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
+{
+	struct pci_mmcfg_region *cfg;
+
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
+		if (cfg->segment == segment &&
+		    cfg->start_bus <= bus && bus <= cfg->end_bus)
+			return cfg;
+
+	return NULL;
+}
+
+/*
+ * Map a pci_mmcfg_region, can be overrriden by arch
+ */
+int __weak pci_mmconfig_map_resource(struct device *dev,
+	struct pci_mmcfg_region *mcfg)
+{
+	struct resource *tmp;
+	void __iomem *vaddr;
+
+	tmp = insert_resource_conflict(&iomem_resource, &mcfg->res);
+	if (tmp) {
+		dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
+			&mcfg->res, tmp->name, tmp);
+		return -EBUSY;
+	}
+
+	vaddr =  ioremap(mcfg->res.start, resource_size(&mcfg->res));
+	if (!vaddr) {
+		release_resource(&mcfg->res);
+		return -ENOMEM;
+	}
+
+	mcfg->virt = vaddr;
+	return 0;
+}
+
+/*
+ * Unmap a pci_mmcfg_region, can be overrriden by arch
+ */
+void __weak pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg)
+{
+	if (mcfg->virt) {
+		iounmap(mcfg->virt);
+		mcfg->virt = NULL;
+	}
+	if (mcfg->res.parent) {
+		release_resource(&mcfg->res);
+		mcfg->res.parent = NULL;
+	}
+}
+
+/*
+ * check if the mmconfig is enabled and configured
+ */
+int __weak pci_mmconfig_enabled(void)
+{
+	return 1;
+}
+
+/* Add MMCFG information for host bridges */
+int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+			phys_addr_t addr)
+{
+	struct pci_mmcfg_region *cfg;
+	int rc;
+
+	if (!pci_mmconfig_enabled())
+		return -ENODEV;
+	if (start > end)
+		return -EINVAL;
+
+	mutex_lock(&pci_mmcfg_lock);
+	cfg = pci_mmconfig_lookup(seg, start);
+	if (cfg) {
+		if (cfg->end_bus < end)
+			dev_info(dev, FW_INFO
+				 "MMCONFIG for "
+				 "domain %04x [bus %02x-%02x] "
+				 "only partially covers this bridge\n",
+				  cfg->segment, cfg->start_bus, cfg->end_bus);
+		rc = -EEXIST;
+		goto err;
+	}
+
+	if (!addr) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	cfg = pci_mmconfig_alloc(seg, start, end, addr);
+	if (cfg == NULL) {
+		dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+	rc = pci_mmconfig_map_resource(dev, cfg);
+	if (!rc) {
+		list_add_sorted(cfg);
+		dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
+				 &cfg->res, (unsigned long)addr);
+		return 0;
+	} else {
+		if (cfg->res.parent)
+			release_resource(&cfg->res);
+		kfree(cfg);
+	}
+
+err:
+	mutex_unlock(&pci_mmcfg_lock);
+	return rc;
+}
+
+/* Delete MMCFG information for host bridges */
+int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
+{
+	struct pci_mmcfg_region *cfg;
+
+	mutex_lock(&pci_mmcfg_lock);
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
+		if (cfg->segment == seg && cfg->start_bus == start &&
+		    cfg->end_bus == end) {
+			list_del_rcu(&cfg->list);
+			synchronize_rcu();
+			pci_mmconfig_unmap_resource(cfg);
+			mutex_unlock(&pci_mmcfg_lock);
+			kfree(cfg);
+			return 0;
+		}
+	mutex_unlock(&pci_mmcfg_lock);
+
+	return -ENOENT;
+}
+
+static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+					struct acpi_mcfg_allocation *cfg)
+{
+	int year;
+
+	if (!config_enabled(CONFIG_X86))
+		return 0;
+
+	if (cfg->address < 0xFFFFFFFF)
+		return 0;
+
+	if (!strncmp(mcfg->header.oem_id, "SGI", 3))
+		return 0;
+
+	if (mcfg->header.revision >= 1) {
+		if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
+		    year >= 2010)
+			return 0;
+	}
+
+	pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
+	       "is above 4GB, ignored\n", cfg->pci_segment,
+	       cfg->start_bus_number, cfg->end_bus_number, cfg->address);
+	return -EINVAL;
+}
+
+static int __init pci_parse_mcfg(struct acpi_table_header *header)
+{
+	struct acpi_table_mcfg *mcfg;
+	struct acpi_mcfg_allocation *cfg_table, *cfg;
+	unsigned long i;
+	int entries;
+
+	if (!header)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *)header;
+
+	/* how many config structures do we have */
+	entries = 0;
+	i = header->length - sizeof(struct acpi_table_mcfg);
+	while (i >= sizeof(struct acpi_mcfg_allocation)) {
+		entries++;
+		i -= sizeof(struct acpi_mcfg_allocation);
+	}
+	if (entries == 0) {
+		pr_err(PREFIX "MMCONFIG has no entries\n");
+		return -ENODEV;
+	}
+
+	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
+	for (i = 0; i < entries; i++) {
+		cfg = &cfg_table[i];
+		if (acpi_mcfg_check_entry(mcfg, cfg))
+			return -ENODEV;
+
+		if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
+				   cfg->end_bus_number, cfg->address) == NULL) {
+			pr_warn(PREFIX "no memory for MCFG entries\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int __init pci_mmconfig_parse_table(void)
+{
+	return acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+}
+
+void __weak __init pci_mmcfg_late_init(void)
+{
+	int err, n = 0;
+	struct pci_mmcfg_region *cfg;
+
+	err = pci_mmconfig_parse_table();
+	if (err) {
+		pr_err(PREFIX " Failed to parse MCFG (%d)\n", err);
+		return;
+	}
+
+	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+		pci_mmconfig_map_resource(NULL, cfg);
+		n++;
+	}
+
+	pr_info(PREFIX " MCFG table loaded %d entries\n", n);
+}
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
index 7494dbe..97aa9d3 100644
--- a/drivers/xen/pci.c
+++ b/drivers/xen/pci.c
@@ -27,9 +27,6 @@
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 #include "../pci/pci.h"
-#ifdef CONFIG_PCI_MMCONFIG
-#include <asm/pci_x86.h>
-#endif
 
 static bool __read_mostly pci_seg_supported = true;
 
@@ -221,7 +218,7 @@ static int __init xen_mcfg_late(void)
 	if (!xen_initial_domain())
 		return 0;
 
-	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+	if (!pci_mmconfig_enabled())
 		return 0;
 
 	if (list_empty(&pci_mmcfg_list))
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 89ab057..e9450ef 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -106,6 +106,39 @@ extern const u8 pci_acpi_dsm_uuid[];
 #define RESET_DELAY_DSM		0x08
 #define FUNCTION_DELAY_DSM	0x09
 
+/* common API to maintain list of MCFG regions */
+/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
+#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
+
+struct pci_mmcfg_region {
+	struct list_head list;
+	struct resource res;
+	u64 address;
+	char __iomem *virt;
+	u16 segment;
+	u8 start_bus;
+	u8 end_bus;
+	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
+};
+
+extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+			       phys_addr_t addr);
+extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
+
+extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
+extern struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+							int end, u64 addr);
+extern int pci_mmconfig_map_resource(struct device *dev,
+	struct pci_mmcfg_region *mcfg);
+extern void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg);
+extern int pci_mmconfig_enabled(void);
+extern int __init pci_mmconfig_parse_table(void);
+
+extern struct list_head pci_mmcfg_list;
+
+#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
+#define PCI_MMCFG_OFFSET(bus, devfn)   ((bus) << 20 | (devfn) << 12)
+
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 1/5] APCI: MCFG: Move mmcfg_list management to drivers/acpi
  2016-01-29  9:05 ` Jayachandran C
                   ` (2 preceding siblings ...)
  (?)
@ 2016-01-29  9:05 ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Tomasz Nowicki, Lorenzo Pieralisi, Jayachandran C, xen-devel

Move pci_mmcfg_list handling to a drivers/acpi/pci_mcfg.c. This is
to share the API and code with ARM64 later. The corresponding
declarations are moved from asm/pci_x86.h to linux/pci-acpi.h

As a part of this we introduce three functions that can be
implemented by the arch code: pci_mmconfig_map_resource() to map a
mcfg entry, pci_mmconfig_unmap_resource to do the corresponding
unmap and pci_mmconfig_enabled to see if the arch setup of
mcfg entries was successful. We also provide weak implementations
of these, which will be used from ARM64. On x86, we retain the
old logic by providing platform specific implementation.

This patch is purely rearranging code, it should not have any
impact on the logic of MCFG parsing or list handling.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
[Xen parts:]
Acked-by: David Vrabel <david.vrabel@citrix.com>

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 arch/x86/include/asm/pci_x86.h |  24 +---
 arch/x86/pci/mmconfig-shared.c | 269 +++++------------------------------
 arch/x86/pci/mmconfig_32.c     |   1 +
 arch/x86/pci/mmconfig_64.c     |   1 +
 arch/x86/pci/numachip.c        |   1 +
 drivers/acpi/Makefile          |   1 +
 drivers/acpi/pci_mcfg.c        | 312 +++++++++++++++++++++++++++++++++++++++++
 drivers/xen/pci.c              |   5 +-
 include/linux/pci-acpi.h       |  33 +++++
 9 files changed, 386 insertions(+), 261 deletions(-)
 create mode 100644 drivers/acpi/pci_mcfg.c

diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index 46873fb..7824626 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -122,33 +122,11 @@ extern int pci_legacy_init(void);
 extern void pcibios_fixup_irqs(void);
 
 /* pci-mmconfig.c */
-
-/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
-#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
-
-struct pci_mmcfg_region {
-	struct list_head list;
-	struct resource res;
-	u64 address;
-	char __iomem *virt;
-	u16 segment;
-	u8 start_bus;
-	u8 end_bus;
-	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
-};
-
+struct pci_mmcfg_region;
 extern int __init pci_mmcfg_arch_init(void);
 extern void __init pci_mmcfg_arch_free(void);
 extern int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
 extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
-extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
-			       phys_addr_t addr);
-extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
-extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
-
-extern struct list_head pci_mmcfg_list;
-
-#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
 
 /*
  * On AMD Fam10h CPUs, all PCI MMIO configuration space accesses must use
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index dd30b7e..626710b 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -12,13 +12,12 @@
 
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <linux/sfi_acpi.h>
 #include <linux/bitmap.h>
-#include <linux/dmi.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/rculist.h>
 #include <asm/e820.h>
+#include <linux/pci-acpi.h>
 #include <asm/pci_x86.h>
 #include <asm/acpi.h>
 
@@ -27,9 +26,6 @@
 /* Indicate if the mmcfg resources have been placed into the resource table. */
 static bool pci_mmcfg_running_state;
 static bool pci_mmcfg_arch_init_failed;
-static DEFINE_MUTEX(pci_mmcfg_lock);
-
-LIST_HEAD(pci_mmcfg_list);
 
 static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
 {
@@ -48,83 +44,6 @@ static void __init free_all_mmcfg(void)
 		pci_mmconfig_remove(cfg);
 }
 
-static void list_add_sorted(struct pci_mmcfg_region *new)
-{
-	struct pci_mmcfg_region *cfg;
-
-	/* keep list sorted by segment and starting bus number */
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
-		if (cfg->segment > new->segment ||
-		    (cfg->segment == new->segment &&
-		     cfg->start_bus >= new->start_bus)) {
-			list_add_tail_rcu(&new->list, &cfg->list);
-			return;
-		}
-	}
-	list_add_tail_rcu(&new->list, &pci_mmcfg_list);
-}
-
-static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
-						   int end, u64 addr)
-{
-	struct pci_mmcfg_region *new;
-	struct resource *res;
-
-	if (addr == 0)
-		return NULL;
-
-	new = kzalloc(sizeof(*new), GFP_KERNEL);
-	if (!new)
-		return NULL;
-
-	new->address = addr;
-	new->segment = segment;
-	new->start_bus = start;
-	new->end_bus = end;
-
-	res = &new->res;
-	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
-	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
-	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-	snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
-		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
-	res->name = new->name;
-
-	return new;
-}
-
-static struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
-							int end, u64 addr)
-{
-	struct pci_mmcfg_region *new;
-
-	new = pci_mmconfig_alloc(segment, start, end, addr);
-	if (new) {
-		mutex_lock(&pci_mmcfg_lock);
-		list_add_sorted(new);
-		mutex_unlock(&pci_mmcfg_lock);
-
-		pr_info(PREFIX
-		       "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
-		       "(base %#lx)\n",
-		       segment, start, end, &new->res, (unsigned long)addr);
-	}
-
-	return new;
-}
-
-struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
-{
-	struct pci_mmcfg_region *cfg;
-
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
-		if (cfg->segment == segment &&
-		    cfg->start_bus <= bus && bus <= cfg->end_bus)
-			return cfg;
-
-	return NULL;
-}
-
 static const char *__init pci_mmcfg_e7520(void)
 {
 	u32 win;
@@ -543,73 +462,6 @@ static void __init pci_mmcfg_reject_broken(int early)
 	}
 }
 
-static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
-					struct acpi_mcfg_allocation *cfg)
-{
-	int year;
-
-	if (cfg->address < 0xFFFFFFFF)
-		return 0;
-
-	if (!strncmp(mcfg->header.oem_id, "SGI", 3))
-		return 0;
-
-	if (mcfg->header.revision >= 1) {
-		if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
-		    year >= 2010)
-			return 0;
-	}
-
-	pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
-	       "is above 4GB, ignored\n", cfg->pci_segment,
-	       cfg->start_bus_number, cfg->end_bus_number, cfg->address);
-	return -EINVAL;
-}
-
-static int __init pci_parse_mcfg(struct acpi_table_header *header)
-{
-	struct acpi_table_mcfg *mcfg;
-	struct acpi_mcfg_allocation *cfg_table, *cfg;
-	unsigned long i;
-	int entries;
-
-	if (!header)
-		return -EINVAL;
-
-	mcfg = (struct acpi_table_mcfg *)header;
-
-	/* how many config structures do we have */
-	free_all_mmcfg();
-	entries = 0;
-	i = header->length - sizeof(struct acpi_table_mcfg);
-	while (i >= sizeof(struct acpi_mcfg_allocation)) {
-		entries++;
-		i -= sizeof(struct acpi_mcfg_allocation);
-	}
-	if (entries == 0) {
-		pr_err(PREFIX "MMCONFIG has no entries\n");
-		return -ENODEV;
-	}
-
-	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
-	for (i = 0; i < entries; i++) {
-		cfg = &cfg_table[i];
-		if (acpi_mcfg_check_entry(mcfg, cfg)) {
-			free_all_mmcfg();
-			return -ENODEV;
-		}
-
-		if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
-				   cfg->end_bus_number, cfg->address) == NULL) {
-			pr_warn(PREFIX "no memory for MCFG entries\n");
-			free_all_mmcfg();
-			return -ENOMEM;
-		}
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_ACPI_APEI
 extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,
 				     void *data), void *data);
@@ -662,13 +514,20 @@ static void __init __pci_mmcfg_init(int early)
 
 static int __initdata known_bridge;
 
+static void __init pci_mmcfg_list_setup(void)
+{
+	free_all_mmcfg();
+	if (pci_mmconfig_parse_table())
+		free_all_mmcfg();
+}
+
 void __init pci_mmcfg_early_init(void)
 {
 	if (pci_probe & PCI_PROBE_MMCONF) {
 		if (pci_mmcfg_check_hostbridge())
 			known_bridge = 1;
 		else
-			acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+			pci_mmcfg_list_setup();
 		__pci_mmcfg_init(1);
 
 		set_apei_filter();
@@ -686,7 +545,7 @@ void __init pci_mmcfg_late_init(void)
 
 	/* MMCONFIG hasn't been enabled yet, try again */
 	if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) {
-		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+		pci_mmcfg_list_setup();
 		__pci_mmcfg_init(0);
 	}
 }
@@ -720,99 +579,41 @@ static int __init pci_mmcfg_late_insert_resources(void)
  */
 late_initcall(pci_mmcfg_late_insert_resources);
 
-/* Add MMCFG information for host bridges */
-int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
-			phys_addr_t addr)
+int pci_mmconfig_map_resource(struct device *dev, struct pci_mmcfg_region *cfg)
 {
-	int rc;
-	struct resource *tmp = NULL;
-	struct pci_mmcfg_region *cfg;
+	struct resource *tmp;
 
-	if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
-		return -ENODEV;
-
-	if (start > end)
-		return -EINVAL;
-
-	mutex_lock(&pci_mmcfg_lock);
-	cfg = pci_mmconfig_lookup(seg, start);
-	if (cfg) {
-		if (cfg->end_bus < end)
-			dev_info(dev, FW_INFO
-				 "MMCONFIG for "
-				 "domain %04x [bus %02x-%02x] "
-				 "only partially covers this bridge\n",
-				  cfg->segment, cfg->start_bus, cfg->end_bus);
-		mutex_unlock(&pci_mmcfg_lock);
-		return -EEXIST;
-	}
-
-	if (!addr) {
-		mutex_unlock(&pci_mmcfg_lock);
-		return -EINVAL;
-	}
-
-	rc = -EBUSY;
-	cfg = pci_mmconfig_alloc(seg, start, end, addr);
-	if (cfg == NULL) {
-		dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
-		rc = -ENOMEM;
-	} else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
+	if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
 		dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n",
 			 &cfg->res);
-	} else {
-		/* Insert resource if it's not in boot stage */
-		if (pci_mmcfg_running_state)
-			tmp = insert_resource_conflict(&iomem_resource,
-						       &cfg->res);
-
+		return -EBUSY;
+	}
+	/* Insert resource if it's not in boot stage */
+	if (pci_mmcfg_running_state) {
+		tmp = insert_resource_conflict(&iomem_resource,
+					       &cfg->res);
 		if (tmp) {
-			dev_warn(dev,
-				 "MMCONFIG %pR conflicts with "
-				 "%s %pR\n",
-				 &cfg->res, tmp->name, tmp);
-		} else if (pci_mmcfg_arch_map(cfg)) {
-			dev_warn(dev, "fail to map MMCONFIG %pR.\n",
-				 &cfg->res);
-		} else {
-			list_add_sorted(cfg);
-			dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
-				 &cfg->res, (unsigned long)addr);
-			cfg = NULL;
-			rc = 0;
+			dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
+				&cfg->res, tmp->name, tmp);
+			return -EBUSY;
 		}
 	}
-
-	if (cfg) {
-		if (cfg->res.parent)
-			release_resource(&cfg->res);
-		kfree(cfg);
+	if (pci_mmcfg_arch_map(cfg)) {
+		dev_warn(dev, "fail to map MMCONFIG %pR.\n", &cfg->res);
+		return -EBUSY;
 	}
-
-	mutex_unlock(&pci_mmcfg_lock);
-
-	return rc;
+	return 0;
 }
 
-/* Delete MMCFG information for host bridges */
-int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
+void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *cfg)
 {
-	struct pci_mmcfg_region *cfg;
-
-	mutex_lock(&pci_mmcfg_lock);
-	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
-		if (cfg->segment == seg && cfg->start_bus == start &&
-		    cfg->end_bus == end) {
-			list_del_rcu(&cfg->list);
-			synchronize_rcu();
-			pci_mmcfg_arch_unmap(cfg);
-			if (cfg->res.parent)
-				release_resource(&cfg->res);
-			mutex_unlock(&pci_mmcfg_lock);
-			kfree(cfg);
-			return 0;
-		}
-	mutex_unlock(&pci_mmcfg_lock);
+	pci_mmcfg_arch_unmap(cfg);
+	if (cfg->res.parent)
+		release_resource(&cfg->res);
+	cfg->res.parent = NULL;
+}
 
-	return -ENOENT;
+int pci_mmconfig_enabled(void)
+{
+	return (pci_probe & PCI_PROBE_MMCONF) && !pci_mmcfg_arch_init_failed;
 }
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 43984bc..38a37f8 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -12,6 +12,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/rcupdate.h>
+#include <linux/pci-acpi.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index bea5249..29253ec 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -10,6 +10,7 @@
 #include <linux/acpi.h>
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
+#include <linux/pci-acpi.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
 
diff --git a/arch/x86/pci/numachip.c b/arch/x86/pci/numachip.c
index 2e565e6..c181eeb 100644
--- a/arch/x86/pci/numachip.c
+++ b/arch/x86/pci/numachip.c
@@ -14,6 +14,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <asm/pci_x86.h>
 
 static u8 limit __read_mostly;
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index cb648a4..74976f1 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
 acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
+acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
 acpi-y				+= acpi_lpss.o acpi_apd.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= acpi_pnp.o
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
new file mode 100644
index 0000000..ea84365
--- /dev/null
+++ b/drivers/acpi/pci_mcfg.c
@@ -0,0 +1,312 @@
+/*
+ * pci_mcfg.c
+ *
+ * Common code to maintain the MCFG areas and mappings
+ *
+ * This has been extracted from arch/x86/pci/mmconfig-shared.c
+ * and moved here so that other architectures can use this code.
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/pci-acpi.h>
+#include <linux/sfi_acpi.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/rculist.h>
+
+#define PREFIX	"ACPI: "
+
+static DEFINE_MUTEX(pci_mmcfg_lock);
+LIST_HEAD(pci_mmcfg_list);
+
+static void list_add_sorted(struct pci_mmcfg_region *new)
+{
+	struct pci_mmcfg_region *cfg;
+
+	/* keep list sorted by segment and starting bus number */
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
+		if (cfg->segment > new->segment ||
+		    (cfg->segment == new->segment &&
+		     cfg->start_bus >= new->start_bus)) {
+			list_add_tail_rcu(&new->list, &cfg->list);
+			return;
+		}
+	}
+	list_add_tail_rcu(&new->list, &pci_mmcfg_list);
+}
+
+static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
+						   int end, u64 addr)
+{
+	struct pci_mmcfg_region *new;
+	struct resource *res;
+
+	if (addr == 0)
+		return NULL;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return NULL;
+
+	new->address = addr;
+	new->segment = segment;
+	new->start_bus = start;
+	new->end_bus = end;
+
+	res = &new->res;
+	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
+	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
+	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+	snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
+		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
+	res->name = new->name;
+
+	return new;
+}
+
+struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+							int end, u64 addr)
+{
+	struct pci_mmcfg_region *new;
+
+	new = pci_mmconfig_alloc(segment, start, end, addr);
+	if (new) {
+		mutex_lock(&pci_mmcfg_lock);
+		list_add_sorted(new);
+		mutex_unlock(&pci_mmcfg_lock);
+
+		pr_info(PREFIX
+		       "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
+		       "(base %#lx)\n",
+		       segment, start, end, &new->res, (unsigned long)addr);
+	}
+
+	return new;
+}
+
+struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
+{
+	struct pci_mmcfg_region *cfg;
+
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
+		if (cfg->segment == segment &&
+		    cfg->start_bus <= bus && bus <= cfg->end_bus)
+			return cfg;
+
+	return NULL;
+}
+
+/*
+ * Map a pci_mmcfg_region, can be overrriden by arch
+ */
+int __weak pci_mmconfig_map_resource(struct device *dev,
+	struct pci_mmcfg_region *mcfg)
+{
+	struct resource *tmp;
+	void __iomem *vaddr;
+
+	tmp = insert_resource_conflict(&iomem_resource, &mcfg->res);
+	if (tmp) {
+		dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
+			&mcfg->res, tmp->name, tmp);
+		return -EBUSY;
+	}
+
+	vaddr =  ioremap(mcfg->res.start, resource_size(&mcfg->res));
+	if (!vaddr) {
+		release_resource(&mcfg->res);
+		return -ENOMEM;
+	}
+
+	mcfg->virt = vaddr;
+	return 0;
+}
+
+/*
+ * Unmap a pci_mmcfg_region, can be overrriden by arch
+ */
+void __weak pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg)
+{
+	if (mcfg->virt) {
+		iounmap(mcfg->virt);
+		mcfg->virt = NULL;
+	}
+	if (mcfg->res.parent) {
+		release_resource(&mcfg->res);
+		mcfg->res.parent = NULL;
+	}
+}
+
+/*
+ * check if the mmconfig is enabled and configured
+ */
+int __weak pci_mmconfig_enabled(void)
+{
+	return 1;
+}
+
+/* Add MMCFG information for host bridges */
+int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+			phys_addr_t addr)
+{
+	struct pci_mmcfg_region *cfg;
+	int rc;
+
+	if (!pci_mmconfig_enabled())
+		return -ENODEV;
+	if (start > end)
+		return -EINVAL;
+
+	mutex_lock(&pci_mmcfg_lock);
+	cfg = pci_mmconfig_lookup(seg, start);
+	if (cfg) {
+		if (cfg->end_bus < end)
+			dev_info(dev, FW_INFO
+				 "MMCONFIG for "
+				 "domain %04x [bus %02x-%02x] "
+				 "only partially covers this bridge\n",
+				  cfg->segment, cfg->start_bus, cfg->end_bus);
+		rc = -EEXIST;
+		goto err;
+	}
+
+	if (!addr) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	cfg = pci_mmconfig_alloc(seg, start, end, addr);
+	if (cfg == NULL) {
+		dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+	rc = pci_mmconfig_map_resource(dev, cfg);
+	if (!rc) {
+		list_add_sorted(cfg);
+		dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
+				 &cfg->res, (unsigned long)addr);
+		return 0;
+	} else {
+		if (cfg->res.parent)
+			release_resource(&cfg->res);
+		kfree(cfg);
+	}
+
+err:
+	mutex_unlock(&pci_mmcfg_lock);
+	return rc;
+}
+
+/* Delete MMCFG information for host bridges */
+int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
+{
+	struct pci_mmcfg_region *cfg;
+
+	mutex_lock(&pci_mmcfg_lock);
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
+		if (cfg->segment == seg && cfg->start_bus == start &&
+		    cfg->end_bus == end) {
+			list_del_rcu(&cfg->list);
+			synchronize_rcu();
+			pci_mmconfig_unmap_resource(cfg);
+			mutex_unlock(&pci_mmcfg_lock);
+			kfree(cfg);
+			return 0;
+		}
+	mutex_unlock(&pci_mmcfg_lock);
+
+	return -ENOENT;
+}
+
+static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+					struct acpi_mcfg_allocation *cfg)
+{
+	int year;
+
+	if (!config_enabled(CONFIG_X86))
+		return 0;
+
+	if (cfg->address < 0xFFFFFFFF)
+		return 0;
+
+	if (!strncmp(mcfg->header.oem_id, "SGI", 3))
+		return 0;
+
+	if (mcfg->header.revision >= 1) {
+		if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
+		    year >= 2010)
+			return 0;
+	}
+
+	pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
+	       "is above 4GB, ignored\n", cfg->pci_segment,
+	       cfg->start_bus_number, cfg->end_bus_number, cfg->address);
+	return -EINVAL;
+}
+
+static int __init pci_parse_mcfg(struct acpi_table_header *header)
+{
+	struct acpi_table_mcfg *mcfg;
+	struct acpi_mcfg_allocation *cfg_table, *cfg;
+	unsigned long i;
+	int entries;
+
+	if (!header)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *)header;
+
+	/* how many config structures do we have */
+	entries = 0;
+	i = header->length - sizeof(struct acpi_table_mcfg);
+	while (i >= sizeof(struct acpi_mcfg_allocation)) {
+		entries++;
+		i -= sizeof(struct acpi_mcfg_allocation);
+	}
+	if (entries == 0) {
+		pr_err(PREFIX "MMCONFIG has no entries\n");
+		return -ENODEV;
+	}
+
+	cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
+	for (i = 0; i < entries; i++) {
+		cfg = &cfg_table[i];
+		if (acpi_mcfg_check_entry(mcfg, cfg))
+			return -ENODEV;
+
+		if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
+				   cfg->end_bus_number, cfg->address) == NULL) {
+			pr_warn(PREFIX "no memory for MCFG entries\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int __init pci_mmconfig_parse_table(void)
+{
+	return acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+}
+
+void __weak __init pci_mmcfg_late_init(void)
+{
+	int err, n = 0;
+	struct pci_mmcfg_region *cfg;
+
+	err = pci_mmconfig_parse_table();
+	if (err) {
+		pr_err(PREFIX " Failed to parse MCFG (%d)\n", err);
+		return;
+	}
+
+	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+		pci_mmconfig_map_resource(NULL, cfg);
+		n++;
+	}
+
+	pr_info(PREFIX " MCFG table loaded %d entries\n", n);
+}
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
index 7494dbe..97aa9d3 100644
--- a/drivers/xen/pci.c
+++ b/drivers/xen/pci.c
@@ -27,9 +27,6 @@
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 #include "../pci/pci.h"
-#ifdef CONFIG_PCI_MMCONFIG
-#include <asm/pci_x86.h>
-#endif
 
 static bool __read_mostly pci_seg_supported = true;
 
@@ -221,7 +218,7 @@ static int __init xen_mcfg_late(void)
 	if (!xen_initial_domain())
 		return 0;
 
-	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+	if (!pci_mmconfig_enabled())
 		return 0;
 
 	if (list_empty(&pci_mmcfg_list))
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 89ab057..e9450ef 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -106,6 +106,39 @@ extern const u8 pci_acpi_dsm_uuid[];
 #define RESET_DELAY_DSM		0x08
 #define FUNCTION_DELAY_DSM	0x09
 
+/* common API to maintain list of MCFG regions */
+/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
+#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
+
+struct pci_mmcfg_region {
+	struct list_head list;
+	struct resource res;
+	u64 address;
+	char __iomem *virt;
+	u16 segment;
+	u8 start_bus;
+	u8 end_bus;
+	char name[PCI_MMCFG_RESOURCE_NAME_LEN];
+};
+
+extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+			       phys_addr_t addr);
+extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
+
+extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
+extern struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+							int end, u64 addr);
+extern int pci_mmconfig_map_resource(struct device *dev,
+	struct pci_mmcfg_region *mcfg);
+extern void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg);
+extern int pci_mmconfig_enabled(void);
+extern int __init pci_mmconfig_parse_table(void);
+
+extern struct list_head pci_mmcfg_list;
+
+#define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
+#define PCI_MMCFG_OFFSET(bus, devfn)   ((bus) << 20 | (devfn) << 12)
+
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 2/5] ACPI: PCI: Support platforms that need pci_remap_iospace
  2016-01-29  9:05 ` Jayachandran C
  (?)
@ 2016-01-29  9:05   ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

On some platforms (in this case ARM64), the PCI iospace needs to
be mapped with pci_remap_iospace and the resources have to be
adjusted for the iospace physical address.

This has to be done before acpi_pci_root_validate_resources()
checks and removes resource windows. Handle this by adding
a function acpi_pci_root_remap_iospace that is called in
acpi_pci_probe_root_resources(), before the validate call.

Also fix the address check in acpi_dev_ioresource_flags for
similar platforms.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/acpi/pci_root.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++--
 drivers/acpi/resource.c |  2 ++
 2 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index ae3fe4e..fcaa484 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -720,6 +720,61 @@ next:
 	}
 }
 
+#ifdef PCI_IOBASE
+/*
+ * The IO ports are mapped to a memory range, fixup IO resources to
+ * handle that
+ */
+static int acpi_pci_root_remap_iospace(struct acpi_pci_root_info *ci)
+{
+	struct resource_entry *entry;
+	struct resource iores;
+	resource_size_t iostart;
+	int err;
+
+	iores.flags = IORESOURCE_IO;
+	iores.start = (resource_size_t)-1;
+	iores.end = 0;
+	resource_list_for_each_entry(entry, &ci->resources) {
+		if (entry->res->flags & IORESOURCE_IO) {
+			iores.start = min(entry->res->start, iores.start);
+			iores.end = max(entry->res->end, iores.end);
+		}
+	}
+	if (iores.end == 0)
+		return 0;
+	iostart = iores.start;
+
+	resource_list_for_each_entry(entry, &ci->resources) {
+		if (entry->res->flags & IORESOURCE_IO) {
+			entry->res->start -= iostart;
+			entry->res->end -= iostart;
+			entry->offset -= iostart;
+		}
+	}
+	iores.start -= iostart;
+	iores.end -= iostart;
+
+	err = pci_remap_iospace(&iores, iostart);
+	if (err) {
+		pr_err("PCI: ACPI: err %d mapping IO %pR\n", err, &iores);
+		return -ENODEV;
+	}
+	pr_info(PREFIX "Mapped %pR at %#lx for IO.\n",
+			&iores, (unsigned long)iostart);
+	return 0;
+}
+#else
+/*
+ * The IO ports are mapped to a memory range, fixup IO resources to
+ * handle that
+ */
+static int acpi_pci_root_remap_iospace(struct acpi_pci_root_info *ci)
+{
+	return 0;
+}
+#endif /* PCI_IOBASE */
+
 int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 {
 	int ret;
@@ -745,10 +800,13 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 			else
 				entry->res->name = info->name;
 		}
-		acpi_pci_root_validate_resources(&device->dev, list,
+		ret = acpi_pci_root_remap_iospace(info);
+		if (ret >= 0) {
+			acpi_pci_root_validate_resources(&device->dev, list,
 						 IORESOURCE_MEM);
-		acpi_pci_root_validate_resources(&device->dev, list,
+			acpi_pci_root_validate_resources(&device->dev, list,
 						 IORESOURCE_IO);
+		}
 	}
 
 	return ret;
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index d02fd53..9672070 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -127,8 +127,10 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
 	if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
+#ifndef PCI_IOBASE
 	if (res->end >= 0x10003)
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
+#endif
 
 	if (io_decode == ACPI_DECODE_16)
 		res->flags |= IORESOURCE_IO_16BIT_ADDR;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 2/5] ACPI: PCI: Support platforms that need pci_remap_iospace
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

On some platforms (in this case ARM64), the PCI iospace needs to
be mapped with pci_remap_iospace and the resources have to be
adjusted for the iospace physical address.

This has to be done before acpi_pci_root_validate_resources()
checks and removes resource windows. Handle this by adding
a function acpi_pci_root_remap_iospace that is called in
acpi_pci_probe_root_resources(), before the validate call.

Also fix the address check in acpi_dev_ioresource_flags for
similar platforms.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/acpi/pci_root.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++--
 drivers/acpi/resource.c |  2 ++
 2 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index ae3fe4e..fcaa484 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -720,6 +720,61 @@ next:
 	}
 }
 
+#ifdef PCI_IOBASE
+/*
+ * The IO ports are mapped to a memory range, fixup IO resources to
+ * handle that
+ */
+static int acpi_pci_root_remap_iospace(struct acpi_pci_root_info *ci)
+{
+	struct resource_entry *entry;
+	struct resource iores;
+	resource_size_t iostart;
+	int err;
+
+	iores.flags = IORESOURCE_IO;
+	iores.start = (resource_size_t)-1;
+	iores.end = 0;
+	resource_list_for_each_entry(entry, &ci->resources) {
+		if (entry->res->flags & IORESOURCE_IO) {
+			iores.start = min(entry->res->start, iores.start);
+			iores.end = max(entry->res->end, iores.end);
+		}
+	}
+	if (iores.end == 0)
+		return 0;
+	iostart = iores.start;
+
+	resource_list_for_each_entry(entry, &ci->resources) {
+		if (entry->res->flags & IORESOURCE_IO) {
+			entry->res->start -= iostart;
+			entry->res->end -= iostart;
+			entry->offset -= iostart;
+		}
+	}
+	iores.start -= iostart;
+	iores.end -= iostart;
+
+	err = pci_remap_iospace(&iores, iostart);
+	if (err) {
+		pr_err("PCI: ACPI: err %d mapping IO %pR\n", err, &iores);
+		return -ENODEV;
+	}
+	pr_info(PREFIX "Mapped %pR at %#lx for IO.\n",
+			&iores, (unsigned long)iostart);
+	return 0;
+}
+#else
+/*
+ * The IO ports are mapped to a memory range, fixup IO resources to
+ * handle that
+ */
+static int acpi_pci_root_remap_iospace(struct acpi_pci_root_info *ci)
+{
+	return 0;
+}
+#endif /* PCI_IOBASE */
+
 int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 {
 	int ret;
@@ -745,10 +800,13 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 			else
 				entry->res->name = info->name;
 		}
-		acpi_pci_root_validate_resources(&device->dev, list,
+		ret = acpi_pci_root_remap_iospace(info);
+		if (ret >= 0) {
+			acpi_pci_root_validate_resources(&device->dev, list,
 						 IORESOURCE_MEM);
-		acpi_pci_root_validate_resources(&device->dev, list,
+			acpi_pci_root_validate_resources(&device->dev, list,
 						 IORESOURCE_IO);
+		}
 	}
 
 	return ret;
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index d02fd53..9672070 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -127,8 +127,10 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
 	if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
+#ifndef PCI_IOBASE
 	if (res->end >= 0x10003)
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
+#endif
 
 	if (io_decode == ACPI_DECODE_16)
 		res->flags |= IORESOURCE_IO_16BIT_ADDR;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 2/5] ACPI: PCI: Support platforms that need pci_remap_iospace
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

On some platforms (in this case ARM64), the PCI iospace needs to
be mapped with pci_remap_iospace and the resources have to be
adjusted for the iospace physical address.

This has to be done before acpi_pci_root_validate_resources()
checks and removes resource windows. Handle this by adding
a function acpi_pci_root_remap_iospace that is called in
acpi_pci_probe_root_resources(), before the validate call.

Also fix the address check in acpi_dev_ioresource_flags for
similar platforms.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/acpi/pci_root.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++--
 drivers/acpi/resource.c |  2 ++
 2 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index ae3fe4e..fcaa484 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -720,6 +720,61 @@ next:
 	}
 }
 
+#ifdef PCI_IOBASE
+/*
+ * The IO ports are mapped to a memory range, fixup IO resources to
+ * handle that
+ */
+static int acpi_pci_root_remap_iospace(struct acpi_pci_root_info *ci)
+{
+	struct resource_entry *entry;
+	struct resource iores;
+	resource_size_t iostart;
+	int err;
+
+	iores.flags = IORESOURCE_IO;
+	iores.start = (resource_size_t)-1;
+	iores.end = 0;
+	resource_list_for_each_entry(entry, &ci->resources) {
+		if (entry->res->flags & IORESOURCE_IO) {
+			iores.start = min(entry->res->start, iores.start);
+			iores.end = max(entry->res->end, iores.end);
+		}
+	}
+	if (iores.end == 0)
+		return 0;
+	iostart = iores.start;
+
+	resource_list_for_each_entry(entry, &ci->resources) {
+		if (entry->res->flags & IORESOURCE_IO) {
+			entry->res->start -= iostart;
+			entry->res->end -= iostart;
+			entry->offset -= iostart;
+		}
+	}
+	iores.start -= iostart;
+	iores.end -= iostart;
+
+	err = pci_remap_iospace(&iores, iostart);
+	if (err) {
+		pr_err("PCI: ACPI: err %d mapping IO %pR\n", err, &iores);
+		return -ENODEV;
+	}
+	pr_info(PREFIX "Mapped %pR at %#lx for IO.\n",
+			&iores, (unsigned long)iostart);
+	return 0;
+}
+#else
+/*
+ * The IO ports are mapped to a memory range, fixup IO resources to
+ * handle that
+ */
+static int acpi_pci_root_remap_iospace(struct acpi_pci_root_info *ci)
+{
+	return 0;
+}
+#endif /* PCI_IOBASE */
+
 int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 {
 	int ret;
@@ -745,10 +800,13 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 			else
 				entry->res->name = info->name;
 		}
-		acpi_pci_root_validate_resources(&device->dev, list,
+		ret = acpi_pci_root_remap_iospace(info);
+		if (ret >= 0) {
+			acpi_pci_root_validate_resources(&device->dev, list,
 						 IORESOURCE_MEM);
-		acpi_pci_root_validate_resources(&device->dev, list,
+			acpi_pci_root_validate_resources(&device->dev, list,
 						 IORESOURCE_IO);
+		}
 	}
 
 	return ret;
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index d02fd53..9672070 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -127,8 +127,10 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
 	if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
+#ifndef PCI_IOBASE
 	if (res->end >= 0x10003)
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
+#endif
 
 	if (io_decode == ACPI_DECODE_16)
 		res->flags |= IORESOURCE_IO_16BIT_ADDR;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 2/5] ACPI: PCI: Support platforms that need pci_remap_iospace
  2016-01-29  9:05 ` Jayachandran C
                   ` (3 preceding siblings ...)
  (?)
@ 2016-01-29  9:05 ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Tomasz Nowicki, Lorenzo Pieralisi, Jayachandran C, xen-devel

On some platforms (in this case ARM64), the PCI iospace needs to
be mapped with pci_remap_iospace and the resources have to be
adjusted for the iospace physical address.

This has to be done before acpi_pci_root_validate_resources()
checks and removes resource windows. Handle this by adding
a function acpi_pci_root_remap_iospace that is called in
acpi_pci_probe_root_resources(), before the validate call.

Also fix the address check in acpi_dev_ioresource_flags for
similar platforms.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/acpi/pci_root.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++--
 drivers/acpi/resource.c |  2 ++
 2 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index ae3fe4e..fcaa484 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -720,6 +720,61 @@ next:
 	}
 }
 
+#ifdef PCI_IOBASE
+/*
+ * The IO ports are mapped to a memory range, fixup IO resources to
+ * handle that
+ */
+static int acpi_pci_root_remap_iospace(struct acpi_pci_root_info *ci)
+{
+	struct resource_entry *entry;
+	struct resource iores;
+	resource_size_t iostart;
+	int err;
+
+	iores.flags = IORESOURCE_IO;
+	iores.start = (resource_size_t)-1;
+	iores.end = 0;
+	resource_list_for_each_entry(entry, &ci->resources) {
+		if (entry->res->flags & IORESOURCE_IO) {
+			iores.start = min(entry->res->start, iores.start);
+			iores.end = max(entry->res->end, iores.end);
+		}
+	}
+	if (iores.end == 0)
+		return 0;
+	iostart = iores.start;
+
+	resource_list_for_each_entry(entry, &ci->resources) {
+		if (entry->res->flags & IORESOURCE_IO) {
+			entry->res->start -= iostart;
+			entry->res->end -= iostart;
+			entry->offset -= iostart;
+		}
+	}
+	iores.start -= iostart;
+	iores.end -= iostart;
+
+	err = pci_remap_iospace(&iores, iostart);
+	if (err) {
+		pr_err("PCI: ACPI: err %d mapping IO %pR\n", err, &iores);
+		return -ENODEV;
+	}
+	pr_info(PREFIX "Mapped %pR at %#lx for IO.\n",
+			&iores, (unsigned long)iostart);
+	return 0;
+}
+#else
+/*
+ * The IO ports are mapped to a memory range, fixup IO resources to
+ * handle that
+ */
+static int acpi_pci_root_remap_iospace(struct acpi_pci_root_info *ci)
+{
+	return 0;
+}
+#endif /* PCI_IOBASE */
+
 int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 {
 	int ret;
@@ -745,10 +800,13 @@ int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
 			else
 				entry->res->name = info->name;
 		}
-		acpi_pci_root_validate_resources(&device->dev, list,
+		ret = acpi_pci_root_remap_iospace(info);
+		if (ret >= 0) {
+			acpi_pci_root_validate_resources(&device->dev, list,
 						 IORESOURCE_MEM);
-		acpi_pci_root_validate_resources(&device->dev, list,
+			acpi_pci_root_validate_resources(&device->dev, list,
 						 IORESOURCE_IO);
+		}
 	}
 
 	return ret;
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index d02fd53..9672070 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -127,8 +127,10 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
 	if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
 
+#ifndef PCI_IOBASE
 	if (res->end >= 0x10003)
 		res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
+#endif
 
 	if (io_decode == ACPI_DECODE_16)
 		res->flags |= IORESOURCE_IO_16BIT_ADDR;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 3/5] PCI: Handle ACPI companion and domain number
  2016-01-29  9:05 ` Jayachandran C
  (?)
@ 2016-01-29  9:05   ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

pci_create_root_bus is called with NULL as parent in ACPI. This
ends up calling pci_bus_assign_domain_nr with a NULL parent, which
crashes when dereferencing parent.

Fix this by providing a way to set the ACPI domain number and ACPI
companion in PCI code. We define pci_acpi_set_companion() to set
the ACPI companion pointer and acpi_pci_get_segment() and to get
the PCI domain number. These functions are stubs for now, the
implementation will be done when the ACPI generic PCI controller
is added.

pci_bus_assign_domain_nr is updated to call acpi_pci_get_segment()
to get the domain number to set on the root bus, in case of ACPI.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/pci/pci.c        | 15 ++++++++++++++-
 drivers/pci/probe.c      |  2 ++
 include/linux/pci-acpi.h | 11 ++++++++++-
 3 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 602eb42..5a3222d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <linux/log2.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
@@ -4772,9 +4773,21 @@ int pci_get_new_domain_nr(void)
 void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
 {
 	static int use_dt_domains = -1;
-	int domain = of_get_pci_domain_nr(parent->of_node);
+	int domain;
 
 	/*
+	 * Handle ACPI early
+	 *
+	 * The companion is not set at this point, and ACPI sets parent to
+	 * NULL, we have to try to get the segment from acpi root info.
+	 */
+	if (!parent || !parent->of_node) {
+		bus->domain_nr = acpi_pci_get_segment(bus->sysdata);
+		return;
+	}
+
+	domain = of_get_pci_domain_nr(parent->of_node);
+	/*
 	 * Check DT domain and use_dt_domains values.
 	 *
 	 * If DT domain property is valid (domain >= 0) and
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6d7ab9b..f1faede 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <linux/aer.h>
 #include <linux/acpi.h>
 #include <asm-generic/pci-bridge.h>
@@ -2100,6 +2101,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 	bridge->dev.parent = parent;
 	bridge->dev.release = pci_release_host_bridge_dev;
 	dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
+	pci_acpi_set_companion(bridge);
 	error = pcibios_root_bridge_prepare(bridge);
 	if (error) {
 		kfree(bridge);
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index e9450ef..d410885 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -138,12 +138,21 @@ extern struct list_head pci_mmcfg_list;
 
 #define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
 #define PCI_MMCFG_OFFSET(bus, devfn)   ((bus) << 20 | (devfn) << 12)
-
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
 #endif	/* CONFIG_ACPI */
 
+static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
+{
+	/* leave it to the platform for now */
+}
+
+static inline u16 acpi_pci_get_segment(void *sysdata)
+{
+	return 0;
+}
+
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
 #else
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 3/5] PCI: Handle ACPI companion and domain number
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

pci_create_root_bus is called with NULL as parent in ACPI. This
ends up calling pci_bus_assign_domain_nr with a NULL parent, which
crashes when dereferencing parent.

Fix this by providing a way to set the ACPI domain number and ACPI
companion in PCI code. We define pci_acpi_set_companion() to set
the ACPI companion pointer and acpi_pci_get_segment() and to get
the PCI domain number. These functions are stubs for now, the
implementation will be done when the ACPI generic PCI controller
is added.

pci_bus_assign_domain_nr is updated to call acpi_pci_get_segment()
to get the domain number to set on the root bus, in case of ACPI.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/pci/pci.c        | 15 ++++++++++++++-
 drivers/pci/probe.c      |  2 ++
 include/linux/pci-acpi.h | 11 ++++++++++-
 3 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 602eb42..5a3222d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <linux/log2.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
@@ -4772,9 +4773,21 @@ int pci_get_new_domain_nr(void)
 void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
 {
 	static int use_dt_domains = -1;
-	int domain = of_get_pci_domain_nr(parent->of_node);
+	int domain;
 
 	/*
+	 * Handle ACPI early
+	 *
+	 * The companion is not set at this point, and ACPI sets parent to
+	 * NULL, we have to try to get the segment from acpi root info.
+	 */
+	if (!parent || !parent->of_node) {
+		bus->domain_nr = acpi_pci_get_segment(bus->sysdata);
+		return;
+	}
+
+	domain = of_get_pci_domain_nr(parent->of_node);
+	/*
 	 * Check DT domain and use_dt_domains values.
 	 *
 	 * If DT domain property is valid (domain >= 0) and
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6d7ab9b..f1faede 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <linux/aer.h>
 #include <linux/acpi.h>
 #include <asm-generic/pci-bridge.h>
@@ -2100,6 +2101,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 	bridge->dev.parent = parent;
 	bridge->dev.release = pci_release_host_bridge_dev;
 	dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
+	pci_acpi_set_companion(bridge);
 	error = pcibios_root_bridge_prepare(bridge);
 	if (error) {
 		kfree(bridge);
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index e9450ef..d410885 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -138,12 +138,21 @@ extern struct list_head pci_mmcfg_list;
 
 #define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
 #define PCI_MMCFG_OFFSET(bus, devfn)   ((bus) << 20 | (devfn) << 12)
-
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
 #endif	/* CONFIG_ACPI */
 
+static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
+{
+	/* leave it to the platform for now */
+}
+
+static inline u16 acpi_pci_get_segment(void *sysdata)
+{
+	return 0;
+}
+
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
 #else
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 3/5] PCI: Handle ACPI companion and domain number
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

pci_create_root_bus is called with NULL as parent in ACPI. This
ends up calling pci_bus_assign_domain_nr with a NULL parent, which
crashes when dereferencing parent.

Fix this by providing a way to set the ACPI domain number and ACPI
companion in PCI code. We define pci_acpi_set_companion() to set
the ACPI companion pointer and acpi_pci_get_segment() and to get
the PCI domain number. These functions are stubs for now, the
implementation will be done when the ACPI generic PCI controller
is added.

pci_bus_assign_domain_nr is updated to call acpi_pci_get_segment()
to get the domain number to set on the root bus, in case of ACPI.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/pci/pci.c        | 15 ++++++++++++++-
 drivers/pci/probe.c      |  2 ++
 include/linux/pci-acpi.h | 11 ++++++++++-
 3 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 602eb42..5a3222d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <linux/log2.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
@@ -4772,9 +4773,21 @@ int pci_get_new_domain_nr(void)
 void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
 {
 	static int use_dt_domains = -1;
-	int domain = of_get_pci_domain_nr(parent->of_node);
+	int domain;
 
 	/*
+	 * Handle ACPI early
+	 *
+	 * The companion is not set at this point, and ACPI sets parent to
+	 * NULL, we have to try to get the segment from acpi root info.
+	 */
+	if (!parent || !parent->of_node) {
+		bus->domain_nr = acpi_pci_get_segment(bus->sysdata);
+		return;
+	}
+
+	domain = of_get_pci_domain_nr(parent->of_node);
+	/*
 	 * Check DT domain and use_dt_domains values.
 	 *
 	 * If DT domain property is valid (domain >= 0) and
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6d7ab9b..f1faede 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <linux/aer.h>
 #include <linux/acpi.h>
 #include <asm-generic/pci-bridge.h>
@@ -2100,6 +2101,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 	bridge->dev.parent = parent;
 	bridge->dev.release = pci_release_host_bridge_dev;
 	dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
+	pci_acpi_set_companion(bridge);
 	error = pcibios_root_bridge_prepare(bridge);
 	if (error) {
 		kfree(bridge);
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index e9450ef..d410885 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -138,12 +138,21 @@ extern struct list_head pci_mmcfg_list;
 
 #define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
 #define PCI_MMCFG_OFFSET(bus, devfn)   ((bus) << 20 | (devfn) << 12)
-
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
 #endif	/* CONFIG_ACPI */
 
+static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
+{
+	/* leave it to the platform for now */
+}
+
+static inline u16 acpi_pci_get_segment(void *sysdata)
+{
+	return 0;
+}
+
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
 #else
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 3/5] PCI: Handle ACPI companion and domain number
  2016-01-29  9:05 ` Jayachandran C
                   ` (6 preceding siblings ...)
  (?)
@ 2016-01-29  9:05 ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Tomasz Nowicki, Lorenzo Pieralisi, Jayachandran C, xen-devel

pci_create_root_bus is called with NULL as parent in ACPI. This
ends up calling pci_bus_assign_domain_nr with a NULL parent, which
crashes when dereferencing parent.

Fix this by providing a way to set the ACPI domain number and ACPI
companion in PCI code. We define pci_acpi_set_companion() to set
the ACPI companion pointer and acpi_pci_get_segment() and to get
the PCI domain number. These functions are stubs for now, the
implementation will be done when the ACPI generic PCI controller
is added.

pci_bus_assign_domain_nr is updated to call acpi_pci_get_segment()
to get the domain number to set on the root bus, in case of ACPI.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/pci/pci.c        | 15 ++++++++++++++-
 drivers/pci/probe.c      |  2 ++
 include/linux/pci-acpi.h | 11 ++++++++++-
 3 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 602eb42..5a3222d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <linux/log2.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
@@ -4772,9 +4773,21 @@ int pci_get_new_domain_nr(void)
 void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
 {
 	static int use_dt_domains = -1;
-	int domain = of_get_pci_domain_nr(parent->of_node);
+	int domain;
 
 	/*
+	 * Handle ACPI early
+	 *
+	 * The companion is not set at this point, and ACPI sets parent to
+	 * NULL, we have to try to get the segment from acpi root info.
+	 */
+	if (!parent || !parent->of_node) {
+		bus->domain_nr = acpi_pci_get_segment(bus->sysdata);
+		return;
+	}
+
+	domain = of_get_pci_domain_nr(parent->of_node);
+	/*
 	 * Check DT domain and use_dt_domains values.
 	 *
 	 * If DT domain property is valid (domain >= 0) and
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6d7ab9b..f1faede 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
+#include <linux/pci-acpi.h>
 #include <linux/aer.h>
 #include <linux/acpi.h>
 #include <asm-generic/pci-bridge.h>
@@ -2100,6 +2101,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 	bridge->dev.parent = parent;
 	bridge->dev.release = pci_release_host_bridge_dev;
 	dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
+	pci_acpi_set_companion(bridge);
 	error = pcibios_root_bridge_prepare(bridge);
 	if (error) {
 		kfree(bridge);
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index e9450ef..d410885 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -138,12 +138,21 @@ extern struct list_head pci_mmcfg_list;
 
 #define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
 #define PCI_MMCFG_OFFSET(bus, devfn)   ((bus) << 20 | (devfn) << 12)
-
 #else	/* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
 #endif	/* CONFIG_ACPI */
 
+static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
+{
+	/* leave it to the platform for now */
+}
+
+static inline u16 acpi_pci_get_segment(void *sysdata)
+{
+	return 0;
+}
+
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
 #else
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 4/5] arm64: pci: Add ACPI support
  2016-01-29  9:05 ` Jayachandran C
  (?)
@ 2016-01-29  9:05   ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

Add functions needed for ACPI support and prepare arm64 for using
CONFIG_ACPI_PCI_HOST_GENERIC for the ACPI based PCI controller.

pci_acpi_scan_root(), raw_pci_read() and raw_pci_write() are marked
as weak so that they can be implemented by the generic ACPI PCI
driver.

pcibios_enable_device() and pcibios_disable_device() have been added
to handle acpi irq enable and disable. pcibios_add_bus() and
pcibios_remove_bus() have been added call the corresponding ACPI
functions.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 arch/arm64/Kconfig      |  3 +++
 arch/arm64/kernel/pci.c | 34 +++++++++++++++++++++++++++++-----
 2 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8cc6228..6bb21d8 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -234,6 +234,9 @@ config PCI_DOMAINS_GENERIC
 config PCI_SYSCALL
 	def_bool PCI
 
+config PCI_MMCONFIG
+	def_bool PCI && ACPI
+
 source "drivers/pci/Kconfig"
 source "drivers/pci/pcie/Kconfig"
 source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index b3d098b..db0a6a9 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
+#include <linux/pci-acpi.h>
 #include <linux/slab.h>
 
 #include <asm/pci-bridge.h>
@@ -48,9 +49,22 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 	if (pci_has_flag(PCI_PROBE_ONLY))
 		return 0;
 
+#ifdef CONFIG_ACPI
+	if (acpi_find_root_bridge_handle(dev))
+		acpi_pci_irq_enable(dev);
+#endif
+
 	return pci_enable_resources(dev, mask);
 }
 
+void pcibios_disable_device(struct pci_dev *dev)
+{
+#ifdef CONFIG_ACPI
+	if (acpi_find_root_bridge_handle(dev))
+		acpi_pci_irq_disable(dev);
+#endif
+}
+
 /*
  * Try to assign the IRQ number from DT when adding a new device
  */
@@ -62,15 +76,15 @@ int pcibios_add_device(struct pci_dev *dev)
 }
 
 /*
- * raw_pci_read/write - Platform-specific PCI config space access.
+ * ACPI uses these - leave it to the generic ACPI PCI driver
  */
-int raw_pci_read(unsigned int domain, unsigned int bus,
+int __weak raw_pci_read(unsigned int domain, unsigned int bus,
 		  unsigned int devfn, int reg, int len, u32 *val)
 {
 	return -ENXIO;
 }
 
-int raw_pci_write(unsigned int domain, unsigned int bus,
+int __weak raw_pci_write(unsigned int domain, unsigned int bus,
 		unsigned int devfn, int reg, int len, u32 val)
 {
 	return -ENXIO;
@@ -78,9 +92,19 @@ int raw_pci_write(unsigned int domain, unsigned int bus,
 
 #ifdef CONFIG_ACPI
 /* Root bridge scanning */
-struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+struct pci_bus * __weak pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-	/* TODO: Should be revisited when implementing PCI on ACPI */
 	return NULL;
 }
+
+void pcibios_add_bus(struct pci_bus *bus)
+{
+	acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+	acpi_pci_remove_bus(bus);
+}
+
 #endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 4/5] arm64: pci: Add ACPI support
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

Add functions needed for ACPI support and prepare arm64 for using
CONFIG_ACPI_PCI_HOST_GENERIC for the ACPI based PCI controller.

pci_acpi_scan_root(), raw_pci_read() and raw_pci_write() are marked
as weak so that they can be implemented by the generic ACPI PCI
driver.

pcibios_enable_device() and pcibios_disable_device() have been added
to handle acpi irq enable and disable. pcibios_add_bus() and
pcibios_remove_bus() have been added call the corresponding ACPI
functions.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 arch/arm64/Kconfig      |  3 +++
 arch/arm64/kernel/pci.c | 34 +++++++++++++++++++++++++++++-----
 2 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8cc6228..6bb21d8 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -234,6 +234,9 @@ config PCI_DOMAINS_GENERIC
 config PCI_SYSCALL
 	def_bool PCI
 
+config PCI_MMCONFIG
+	def_bool PCI && ACPI
+
 source "drivers/pci/Kconfig"
 source "drivers/pci/pcie/Kconfig"
 source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index b3d098b..db0a6a9 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
+#include <linux/pci-acpi.h>
 #include <linux/slab.h>
 
 #include <asm/pci-bridge.h>
@@ -48,9 +49,22 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 	if (pci_has_flag(PCI_PROBE_ONLY))
 		return 0;
 
+#ifdef CONFIG_ACPI
+	if (acpi_find_root_bridge_handle(dev))
+		acpi_pci_irq_enable(dev);
+#endif
+
 	return pci_enable_resources(dev, mask);
 }
 
+void pcibios_disable_device(struct pci_dev *dev)
+{
+#ifdef CONFIG_ACPI
+	if (acpi_find_root_bridge_handle(dev))
+		acpi_pci_irq_disable(dev);
+#endif
+}
+
 /*
  * Try to assign the IRQ number from DT when adding a new device
  */
@@ -62,15 +76,15 @@ int pcibios_add_device(struct pci_dev *dev)
 }
 
 /*
- * raw_pci_read/write - Platform-specific PCI config space access.
+ * ACPI uses these - leave it to the generic ACPI PCI driver
  */
-int raw_pci_read(unsigned int domain, unsigned int bus,
+int __weak raw_pci_read(unsigned int domain, unsigned int bus,
 		  unsigned int devfn, int reg, int len, u32 *val)
 {
 	return -ENXIO;
 }
 
-int raw_pci_write(unsigned int domain, unsigned int bus,
+int __weak raw_pci_write(unsigned int domain, unsigned int bus,
 		unsigned int devfn, int reg, int len, u32 val)
 {
 	return -ENXIO;
@@ -78,9 +92,19 @@ int raw_pci_write(unsigned int domain, unsigned int bus,
 
 #ifdef CONFIG_ACPI
 /* Root bridge scanning */
-struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+struct pci_bus * __weak pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-	/* TODO: Should be revisited when implementing PCI on ACPI */
 	return NULL;
 }
+
+void pcibios_add_bus(struct pci_bus *bus)
+{
+	acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+	acpi_pci_remove_bus(bus);
+}
+
 #endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 4/5] arm64: pci: Add ACPI support
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

Add functions needed for ACPI support and prepare arm64 for using
CONFIG_ACPI_PCI_HOST_GENERIC for the ACPI based PCI controller.

pci_acpi_scan_root(), raw_pci_read() and raw_pci_write() are marked
as weak so that they can be implemented by the generic ACPI PCI
driver.

pcibios_enable_device() and pcibios_disable_device() have been added
to handle acpi irq enable and disable. pcibios_add_bus() and
pcibios_remove_bus() have been added call the corresponding ACPI
functions.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 arch/arm64/Kconfig      |  3 +++
 arch/arm64/kernel/pci.c | 34 +++++++++++++++++++++++++++++-----
 2 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8cc6228..6bb21d8 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -234,6 +234,9 @@ config PCI_DOMAINS_GENERIC
 config PCI_SYSCALL
 	def_bool PCI
 
+config PCI_MMCONFIG
+	def_bool PCI && ACPI
+
 source "drivers/pci/Kconfig"
 source "drivers/pci/pcie/Kconfig"
 source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index b3d098b..db0a6a9 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
+#include <linux/pci-acpi.h>
 #include <linux/slab.h>
 
 #include <asm/pci-bridge.h>
@@ -48,9 +49,22 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 	if (pci_has_flag(PCI_PROBE_ONLY))
 		return 0;
 
+#ifdef CONFIG_ACPI
+	if (acpi_find_root_bridge_handle(dev))
+		acpi_pci_irq_enable(dev);
+#endif
+
 	return pci_enable_resources(dev, mask);
 }
 
+void pcibios_disable_device(struct pci_dev *dev)
+{
+#ifdef CONFIG_ACPI
+	if (acpi_find_root_bridge_handle(dev))
+		acpi_pci_irq_disable(dev);
+#endif
+}
+
 /*
  * Try to assign the IRQ number from DT when adding a new device
  */
@@ -62,15 +76,15 @@ int pcibios_add_device(struct pci_dev *dev)
 }
 
 /*
- * raw_pci_read/write - Platform-specific PCI config space access.
+ * ACPI uses these - leave it to the generic ACPI PCI driver
  */
-int raw_pci_read(unsigned int domain, unsigned int bus,
+int __weak raw_pci_read(unsigned int domain, unsigned int bus,
 		  unsigned int devfn, int reg, int len, u32 *val)
 {
 	return -ENXIO;
 }
 
-int raw_pci_write(unsigned int domain, unsigned int bus,
+int __weak raw_pci_write(unsigned int domain, unsigned int bus,
 		unsigned int devfn, int reg, int len, u32 val)
 {
 	return -ENXIO;
@@ -78,9 +92,19 @@ int raw_pci_write(unsigned int domain, unsigned int bus,
 
 #ifdef CONFIG_ACPI
 /* Root bridge scanning */
-struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+struct pci_bus * __weak pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-	/* TODO: Should be revisited when implementing PCI on ACPI */
 	return NULL;
 }
+
+void pcibios_add_bus(struct pci_bus *bus)
+{
+	acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+	acpi_pci_remove_bus(bus);
+}
+
 #endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 4/5] arm64: pci: Add ACPI support
  2016-01-29  9:05 ` Jayachandran C
                   ` (8 preceding siblings ...)
  (?)
@ 2016-01-29  9:05 ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Tomasz Nowicki, Lorenzo Pieralisi, Jayachandran C, xen-devel

Add functions needed for ACPI support and prepare arm64 for using
CONFIG_ACPI_PCI_HOST_GENERIC for the ACPI based PCI controller.

pci_acpi_scan_root(), raw_pci_read() and raw_pci_write() are marked
as weak so that they can be implemented by the generic ACPI PCI
driver.

pcibios_enable_device() and pcibios_disable_device() have been added
to handle acpi irq enable and disable. pcibios_add_bus() and
pcibios_remove_bus() have been added call the corresponding ACPI
functions.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 arch/arm64/Kconfig      |  3 +++
 arch/arm64/kernel/pci.c | 34 +++++++++++++++++++++++++++++-----
 2 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8cc6228..6bb21d8 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -234,6 +234,9 @@ config PCI_DOMAINS_GENERIC
 config PCI_SYSCALL
 	def_bool PCI
 
+config PCI_MMCONFIG
+	def_bool PCI && ACPI
+
 source "drivers/pci/Kconfig"
 source "drivers/pci/pcie/Kconfig"
 source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index b3d098b..db0a6a9 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 #include <linux/of_pci.h>
 #include <linux/of_platform.h>
+#include <linux/pci-acpi.h>
 #include <linux/slab.h>
 
 #include <asm/pci-bridge.h>
@@ -48,9 +49,22 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 	if (pci_has_flag(PCI_PROBE_ONLY))
 		return 0;
 
+#ifdef CONFIG_ACPI
+	if (acpi_find_root_bridge_handle(dev))
+		acpi_pci_irq_enable(dev);
+#endif
+
 	return pci_enable_resources(dev, mask);
 }
 
+void pcibios_disable_device(struct pci_dev *dev)
+{
+#ifdef CONFIG_ACPI
+	if (acpi_find_root_bridge_handle(dev))
+		acpi_pci_irq_disable(dev);
+#endif
+}
+
 /*
  * Try to assign the IRQ number from DT when adding a new device
  */
@@ -62,15 +76,15 @@ int pcibios_add_device(struct pci_dev *dev)
 }
 
 /*
- * raw_pci_read/write - Platform-specific PCI config space access.
+ * ACPI uses these - leave it to the generic ACPI PCI driver
  */
-int raw_pci_read(unsigned int domain, unsigned int bus,
+int __weak raw_pci_read(unsigned int domain, unsigned int bus,
 		  unsigned int devfn, int reg, int len, u32 *val)
 {
 	return -ENXIO;
 }
 
-int raw_pci_write(unsigned int domain, unsigned int bus,
+int __weak raw_pci_write(unsigned int domain, unsigned int bus,
 		unsigned int devfn, int reg, int len, u32 val)
 {
 	return -ENXIO;
@@ -78,9 +92,19 @@ int raw_pci_write(unsigned int domain, unsigned int bus,
 
 #ifdef CONFIG_ACPI
 /* Root bridge scanning */
-struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+struct pci_bus * __weak pci_acpi_scan_root(struct acpi_pci_root *root)
 {
-	/* TODO: Should be revisited when implementing PCI on ACPI */
 	return NULL;
 }
+
+void pcibios_add_bus(struct pci_bus *bus)
+{
+	acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+	acpi_pci_remove_bus(bus);
+}
+
 #endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-01-29  9:05 ` Jayachandran C
  (?)
@ 2016-01-29  9:05   ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

Add a simple ACPI based PCI host controller under config option
ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
of pci_acpi_scan_root().

The pci_mmcfg_list handling is done by the ACPI code, so we keep a
reference to the pci_mmcfg_region in sysdata. The ECAM region will
be already mapped, so map_bus can be implemented by using the
virt pointer for the pci_mmcfg_region. pci_generic_config_read
and pci_generic_config_write are used for config space read/write.

Also, we provide implementations of raw_pci_read and raw_pci_write
hat are needed by ACPI based on the pci_mmcfg_list.

pci_acpi_set_companion() and acpi_pci_get_segment() are defined
using sysdata of generic ACPI host controller so that PCI domain
and ACPI companion are set in PCI code rather than platform code.

This code is currently enabled only for ARM64.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/acpi/Kconfig         |   8 ++
 drivers/acpi/Makefile        |   1 +
 drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-acpi.h     |  17 ++++
 4 files changed, 212 insertions(+)
 create mode 100644 drivers/acpi/pci_host_acpi.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee..65fb483 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -294,6 +294,14 @@ config ACPI_NUMA
 	depends on (X86 || IA64)
 	default y if IA64_GENERIC || IA64_SGI_SN2
 
+config ACPI_PCI_HOST_GENERIC
+	bool "Generic ACPI PCI host controller"
+	depends on ARM64 && ACPI
+	help
+	  Say Y here if you want to support a simple generic ACPI PCI host
+	  controller.
+
+
 config ACPI_CUSTOM_DSDT_FILE
 	string "Custom DSDT Table file to include"
 	default ""
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 74976f1..346101c 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -41,6 +41,7 @@ acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
 acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
+acpi-$(CONFIG_ACPI_PCI_HOST_GENERIC) += pci_host_acpi.o
 acpi-y				+= acpi_lpss.o acpi_apd.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= acpi_pnp.o
diff --git a/drivers/acpi/pci_host_acpi.c b/drivers/acpi/pci_host_acpi.c
new file mode 100644
index 0000000..9dbdd81
--- /dev/null
+++ b/drivers/acpi/pci_host_acpi.c
@@ -0,0 +1,186 @@
+/*
+ * Generic PCI host controller driver for ACPI based systems
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (c) 2015 Broadcom Corporation
+ *
+ * Based on drivers/pci/host/pci-host-generic.c
+ * Copyright (C) 2014 ARM Limited
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/sfi_acpi.h>
+#include <linux/slab.h>
+
+#define PREFIX			"pci-host-acpi:"
+
+/* sysdata pointer is ->root_info */
+struct gen_acpi_root_info {
+	struct acpi_pci_root_info	common;
+	struct pci_mmcfg_region		*mcfg;
+	bool				mcfg_added;
+};
+
+/* find mapping of a MCFG area */
+static void __iomem *gen_acpi_map_cfg_bus(struct pci_bus *bus,
+			unsigned int devfn, int where)
+{
+	struct gen_acpi_root_info *pci = bus->sysdata;
+	struct pci_mmcfg_region *mcfg = pci->mcfg;
+
+	if (bus->number < mcfg->start_bus || bus->number > mcfg->end_bus)
+		return NULL;
+
+	return mcfg->virt +
+		PCI_MMCFG_OFFSET(bus->number - mcfg->start_bus, devfn) +
+		where;
+}
+
+static struct pci_ops gen_acpi_pci_ops = {
+	.map_bus	= gen_acpi_map_cfg_bus,
+	.read		= pci_generic_config_read,
+	.write		= pci_generic_config_write,
+};
+
+/* Insert the ECFG area for a root bus */
+static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
+{
+	struct gen_acpi_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+	struct device *dev = &ci->bridge->dev;
+	int err;
+
+	info = container_of(ci, struct gen_acpi_root_info, common);
+	err = pci_mmconfig_insert(dev, root->segment, root->secondary.start,
+			root->secondary.end, root->mcfg_addr);
+	if (err && err != -EEXIST)
+		return err;
+
+	info->mcfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
+	WARN_ON(info->mcfg == NULL);
+	info->mcfg_added = (err == -EEXIST);
+	return 0;
+}
+
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
+{
+	struct gen_acpi_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+
+	info = container_of(ci, struct gen_acpi_root_info, common);
+	if (info->mcfg_added)
+		pci_mmconfig_delete(root->segment, root->secondary.start,
+					root->secondary.end);
+	info->mcfg = NULL;
+}
+
+static struct acpi_pci_root_ops pci_acpi_root_ops = {
+	.pci_ops = &gen_acpi_pci_ops,
+	.init_info = pci_acpi_root_init_info,
+	.release_info = pci_acpi_root_release_info,
+};
+
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+{
+	struct acpi_device *device = root->device;
+	struct gen_acpi_root_info *ri;
+	struct pci_bus *bus, *child;
+
+	/* allocate acpi_info/sysdata */
+	ri = devm_kzalloc(&device->dev, sizeof(*ri), GFP_KERNEL);
+	if (!ri) {
+		dev_err(&device->dev,
+			"pci_bus %04x:%02x: ignored (out of memory)\n",
+			root->segment, (int)root->secondary.start);
+		return NULL;
+	}
+
+	bus =  acpi_pci_root_create(root, &pci_acpi_root_ops,
+					&ri->common, ri);
+	if (!bus) {
+		dev_err(&device->dev, "Scanning rootbus failed");
+		return NULL;
+	}
+
+	pci_bus_size_bridges(bus);
+	pci_bus_assign_resources(bus);
+	list_for_each_entry(child, &bus->children, node)
+		pcie_bus_configure_settings(child);
+
+	return bus;
+}
+
+int raw_pci_read(unsigned int seg, unsigned int bus,
+		  unsigned int devfn, int reg, int len, u32 *val)
+{
+	struct pci_mmcfg_region *mcfg;
+	void __iomem *addr;
+	int err = -EINVAL;
+
+	rcu_read_lock();
+	mcfg = pci_mmconfig_lookup(seg, bus);
+	if (!mcfg || !mcfg->virt)
+		goto err;
+
+	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
+	switch (len) {
+	case 1:
+		*val = readb(addr + reg);
+		break;
+	case 2:
+		*val = readw(addr + reg);
+		break;
+	case 4:
+		*val = readl(addr + reg);
+		break;
+	}
+	err = 0;
+err:
+	rcu_read_unlock();
+	return err;
+}
+
+int raw_pci_write(unsigned int seg, unsigned int bus,
+		unsigned int devfn, int reg, int len, u32 val)
+{
+	struct pci_mmcfg_region *mcfg;
+	void __iomem *addr;
+	int err = -EINVAL;
+
+	rcu_read_lock();
+	mcfg = pci_mmconfig_lookup(seg, bus);
+	if (!mcfg || !mcfg->virt)
+		goto err;
+
+	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
+	switch (len) {
+	case 1:
+		writeb(val, addr + reg);
+		break;
+	case 2:
+		writew(val, addr + reg);
+		break;
+	case 4:
+		writel(val, addr + reg);
+		break;
+	}
+	err = 0;
+err:
+	rcu_read_unlock();
+	return err;
+}
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index d410885..f8d62e3 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -143,6 +143,22 @@ static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
 #endif	/* CONFIG_ACPI */
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_ACPI_PCI_HOST_GENERIC)
+static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
+{
+	struct pci_bus *b = bridge->bus;
+	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)b->sysdata;
+
+	ACPI_COMPANION_SET(&bridge->dev, ci->bridge);
+}
+
+static inline u16 acpi_pci_get_segment(void *sysdata)
+{
+	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)sysdata;
+
+	return ci->root->segment;
+}
+#else
 static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
 {
 	/* leave it to the platform for now */
@@ -152,6 +168,7 @@ static inline u16 acpi_pci_get_segment(void *sysdata)
 {
 	return 0;
 }
+#endif
 
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Jayachandran C, Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

Add a simple ACPI based PCI host controller under config option
ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
of pci_acpi_scan_root().

The pci_mmcfg_list handling is done by the ACPI code, so we keep a
reference to the pci_mmcfg_region in sysdata. The ECAM region will
be already mapped, so map_bus can be implemented by using the
virt pointer for the pci_mmcfg_region. pci_generic_config_read
and pci_generic_config_write are used for config space read/write.

Also, we provide implementations of raw_pci_read and raw_pci_write
hat are needed by ACPI based on the pci_mmcfg_list.

pci_acpi_set_companion() and acpi_pci_get_segment() are defined
using sysdata of generic ACPI host controller so that PCI domain
and ACPI companion are set in PCI code rather than platform code.

This code is currently enabled only for ARM64.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/acpi/Kconfig         |   8 ++
 drivers/acpi/Makefile        |   1 +
 drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-acpi.h     |  17 ++++
 4 files changed, 212 insertions(+)
 create mode 100644 drivers/acpi/pci_host_acpi.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee..65fb483 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -294,6 +294,14 @@ config ACPI_NUMA
 	depends on (X86 || IA64)
 	default y if IA64_GENERIC || IA64_SGI_SN2
 
+config ACPI_PCI_HOST_GENERIC
+	bool "Generic ACPI PCI host controller"
+	depends on ARM64 && ACPI
+	help
+	  Say Y here if you want to support a simple generic ACPI PCI host
+	  controller.
+
+
 config ACPI_CUSTOM_DSDT_FILE
 	string "Custom DSDT Table file to include"
 	default ""
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 74976f1..346101c 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -41,6 +41,7 @@ acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
 acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
+acpi-$(CONFIG_ACPI_PCI_HOST_GENERIC) += pci_host_acpi.o
 acpi-y				+= acpi_lpss.o acpi_apd.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= acpi_pnp.o
diff --git a/drivers/acpi/pci_host_acpi.c b/drivers/acpi/pci_host_acpi.c
new file mode 100644
index 0000000..9dbdd81
--- /dev/null
+++ b/drivers/acpi/pci_host_acpi.c
@@ -0,0 +1,186 @@
+/*
+ * Generic PCI host controller driver for ACPI based systems
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (c) 2015 Broadcom Corporation
+ *
+ * Based on drivers/pci/host/pci-host-generic.c
+ * Copyright (C) 2014 ARM Limited
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/sfi_acpi.h>
+#include <linux/slab.h>
+
+#define PREFIX			"pci-host-acpi:"
+
+/* sysdata pointer is ->root_info */
+struct gen_acpi_root_info {
+	struct acpi_pci_root_info	common;
+	struct pci_mmcfg_region		*mcfg;
+	bool				mcfg_added;
+};
+
+/* find mapping of a MCFG area */
+static void __iomem *gen_acpi_map_cfg_bus(struct pci_bus *bus,
+			unsigned int devfn, int where)
+{
+	struct gen_acpi_root_info *pci = bus->sysdata;
+	struct pci_mmcfg_region *mcfg = pci->mcfg;
+
+	if (bus->number < mcfg->start_bus || bus->number > mcfg->end_bus)
+		return NULL;
+
+	return mcfg->virt +
+		PCI_MMCFG_OFFSET(bus->number - mcfg->start_bus, devfn) +
+		where;
+}
+
+static struct pci_ops gen_acpi_pci_ops = {
+	.map_bus	= gen_acpi_map_cfg_bus,
+	.read		= pci_generic_config_read,
+	.write		= pci_generic_config_write,
+};
+
+/* Insert the ECFG area for a root bus */
+static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
+{
+	struct gen_acpi_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+	struct device *dev = &ci->bridge->dev;
+	int err;
+
+	info = container_of(ci, struct gen_acpi_root_info, common);
+	err = pci_mmconfig_insert(dev, root->segment, root->secondary.start,
+			root->secondary.end, root->mcfg_addr);
+	if (err && err != -EEXIST)
+		return err;
+
+	info->mcfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
+	WARN_ON(info->mcfg == NULL);
+	info->mcfg_added = (err == -EEXIST);
+	return 0;
+}
+
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
+{
+	struct gen_acpi_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+
+	info = container_of(ci, struct gen_acpi_root_info, common);
+	if (info->mcfg_added)
+		pci_mmconfig_delete(root->segment, root->secondary.start,
+					root->secondary.end);
+	info->mcfg = NULL;
+}
+
+static struct acpi_pci_root_ops pci_acpi_root_ops = {
+	.pci_ops = &gen_acpi_pci_ops,
+	.init_info = pci_acpi_root_init_info,
+	.release_info = pci_acpi_root_release_info,
+};
+
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+{
+	struct acpi_device *device = root->device;
+	struct gen_acpi_root_info *ri;
+	struct pci_bus *bus, *child;
+
+	/* allocate acpi_info/sysdata */
+	ri = devm_kzalloc(&device->dev, sizeof(*ri), GFP_KERNEL);
+	if (!ri) {
+		dev_err(&device->dev,
+			"pci_bus %04x:%02x: ignored (out of memory)\n",
+			root->segment, (int)root->secondary.start);
+		return NULL;
+	}
+
+	bus =  acpi_pci_root_create(root, &pci_acpi_root_ops,
+					&ri->common, ri);
+	if (!bus) {
+		dev_err(&device->dev, "Scanning rootbus failed");
+		return NULL;
+	}
+
+	pci_bus_size_bridges(bus);
+	pci_bus_assign_resources(bus);
+	list_for_each_entry(child, &bus->children, node)
+		pcie_bus_configure_settings(child);
+
+	return bus;
+}
+
+int raw_pci_read(unsigned int seg, unsigned int bus,
+		  unsigned int devfn, int reg, int len, u32 *val)
+{
+	struct pci_mmcfg_region *mcfg;
+	void __iomem *addr;
+	int err = -EINVAL;
+
+	rcu_read_lock();
+	mcfg = pci_mmconfig_lookup(seg, bus);
+	if (!mcfg || !mcfg->virt)
+		goto err;
+
+	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
+	switch (len) {
+	case 1:
+		*val = readb(addr + reg);
+		break;
+	case 2:
+		*val = readw(addr + reg);
+		break;
+	case 4:
+		*val = readl(addr + reg);
+		break;
+	}
+	err = 0;
+err:
+	rcu_read_unlock();
+	return err;
+}
+
+int raw_pci_write(unsigned int seg, unsigned int bus,
+		unsigned int devfn, int reg, int len, u32 val)
+{
+	struct pci_mmcfg_region *mcfg;
+	void __iomem *addr;
+	int err = -EINVAL;
+
+	rcu_read_lock();
+	mcfg = pci_mmconfig_lookup(seg, bus);
+	if (!mcfg || !mcfg->virt)
+		goto err;
+
+	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
+	switch (len) {
+	case 1:
+		writeb(val, addr + reg);
+		break;
+	case 2:
+		writew(val, addr + reg);
+		break;
+	case 4:
+		writel(val, addr + reg);
+		break;
+	}
+	err = 0;
+err:
+	rcu_read_unlock();
+	return err;
+}
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index d410885..f8d62e3 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -143,6 +143,22 @@ static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
 #endif	/* CONFIG_ACPI */
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_ACPI_PCI_HOST_GENERIC)
+static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
+{
+	struct pci_bus *b = bridge->bus;
+	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)b->sysdata;
+
+	ACPI_COMPANION_SET(&bridge->dev, ci->bridge);
+}
+
+static inline u16 acpi_pci_get_segment(void *sysdata)
+{
+	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)sysdata;
+
+	return ci->root->segment;
+}
+#else
 static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
 {
 	/* leave it to the platform for now */
@@ -152,6 +168,7 @@ static inline u16 acpi_pci_get_segment(void *sysdata)
 {
 	return 0;
 }
+#endif
 
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-01-29  9:05   ` Jayachandran C
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

Add a simple ACPI based PCI host controller under config option
ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
of pci_acpi_scan_root().

The pci_mmcfg_list handling is done by the ACPI code, so we keep a
reference to the pci_mmcfg_region in sysdata. The ECAM region will
be already mapped, so map_bus can be implemented by using the
virt pointer for the pci_mmcfg_region. pci_generic_config_read
and pci_generic_config_write are used for config space read/write.

Also, we provide implementations of raw_pci_read and raw_pci_write
hat are needed by ACPI based on the pci_mmcfg_list.

pci_acpi_set_companion() and acpi_pci_get_segment() are defined
using sysdata of generic ACPI host controller so that PCI domain
and ACPI companion are set in PCI code rather than platform code.

This code is currently enabled only for ARM64.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/acpi/Kconfig         |   8 ++
 drivers/acpi/Makefile        |   1 +
 drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-acpi.h     |  17 ++++
 4 files changed, 212 insertions(+)
 create mode 100644 drivers/acpi/pci_host_acpi.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee..65fb483 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -294,6 +294,14 @@ config ACPI_NUMA
 	depends on (X86 || IA64)
 	default y if IA64_GENERIC || IA64_SGI_SN2
 
+config ACPI_PCI_HOST_GENERIC
+	bool "Generic ACPI PCI host controller"
+	depends on ARM64 && ACPI
+	help
+	  Say Y here if you want to support a simple generic ACPI PCI host
+	  controller.
+
+
 config ACPI_CUSTOM_DSDT_FILE
 	string "Custom DSDT Table file to include"
 	default ""
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 74976f1..346101c 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -41,6 +41,7 @@ acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
 acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
+acpi-$(CONFIG_ACPI_PCI_HOST_GENERIC) += pci_host_acpi.o
 acpi-y				+= acpi_lpss.o acpi_apd.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= acpi_pnp.o
diff --git a/drivers/acpi/pci_host_acpi.c b/drivers/acpi/pci_host_acpi.c
new file mode 100644
index 0000000..9dbdd81
--- /dev/null
+++ b/drivers/acpi/pci_host_acpi.c
@@ -0,0 +1,186 @@
+/*
+ * Generic PCI host controller driver for ACPI based systems
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (c) 2015 Broadcom Corporation
+ *
+ * Based on drivers/pci/host/pci-host-generic.c
+ * Copyright (C) 2014 ARM Limited
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/sfi_acpi.h>
+#include <linux/slab.h>
+
+#define PREFIX			"pci-host-acpi:"
+
+/* sysdata pointer is ->root_info */
+struct gen_acpi_root_info {
+	struct acpi_pci_root_info	common;
+	struct pci_mmcfg_region		*mcfg;
+	bool				mcfg_added;
+};
+
+/* find mapping of a MCFG area */
+static void __iomem *gen_acpi_map_cfg_bus(struct pci_bus *bus,
+			unsigned int devfn, int where)
+{
+	struct gen_acpi_root_info *pci = bus->sysdata;
+	struct pci_mmcfg_region *mcfg = pci->mcfg;
+
+	if (bus->number < mcfg->start_bus || bus->number > mcfg->end_bus)
+		return NULL;
+
+	return mcfg->virt +
+		PCI_MMCFG_OFFSET(bus->number - mcfg->start_bus, devfn) +
+		where;
+}
+
+static struct pci_ops gen_acpi_pci_ops = {
+	.map_bus	= gen_acpi_map_cfg_bus,
+	.read		= pci_generic_config_read,
+	.write		= pci_generic_config_write,
+};
+
+/* Insert the ECFG area for a root bus */
+static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
+{
+	struct gen_acpi_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+	struct device *dev = &ci->bridge->dev;
+	int err;
+
+	info = container_of(ci, struct gen_acpi_root_info, common);
+	err = pci_mmconfig_insert(dev, root->segment, root->secondary.start,
+			root->secondary.end, root->mcfg_addr);
+	if (err && err != -EEXIST)
+		return err;
+
+	info->mcfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
+	WARN_ON(info->mcfg == NULL);
+	info->mcfg_added = (err == -EEXIST);
+	return 0;
+}
+
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
+{
+	struct gen_acpi_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+
+	info = container_of(ci, struct gen_acpi_root_info, common);
+	if (info->mcfg_added)
+		pci_mmconfig_delete(root->segment, root->secondary.start,
+					root->secondary.end);
+	info->mcfg = NULL;
+}
+
+static struct acpi_pci_root_ops pci_acpi_root_ops = {
+	.pci_ops = &gen_acpi_pci_ops,
+	.init_info = pci_acpi_root_init_info,
+	.release_info = pci_acpi_root_release_info,
+};
+
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+{
+	struct acpi_device *device = root->device;
+	struct gen_acpi_root_info *ri;
+	struct pci_bus *bus, *child;
+
+	/* allocate acpi_info/sysdata */
+	ri = devm_kzalloc(&device->dev, sizeof(*ri), GFP_KERNEL);
+	if (!ri) {
+		dev_err(&device->dev,
+			"pci_bus %04x:%02x: ignored (out of memory)\n",
+			root->segment, (int)root->secondary.start);
+		return NULL;
+	}
+
+	bus =  acpi_pci_root_create(root, &pci_acpi_root_ops,
+					&ri->common, ri);
+	if (!bus) {
+		dev_err(&device->dev, "Scanning rootbus failed");
+		return NULL;
+	}
+
+	pci_bus_size_bridges(bus);
+	pci_bus_assign_resources(bus);
+	list_for_each_entry(child, &bus->children, node)
+		pcie_bus_configure_settings(child);
+
+	return bus;
+}
+
+int raw_pci_read(unsigned int seg, unsigned int bus,
+		  unsigned int devfn, int reg, int len, u32 *val)
+{
+	struct pci_mmcfg_region *mcfg;
+	void __iomem *addr;
+	int err = -EINVAL;
+
+	rcu_read_lock();
+	mcfg = pci_mmconfig_lookup(seg, bus);
+	if (!mcfg || !mcfg->virt)
+		goto err;
+
+	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
+	switch (len) {
+	case 1:
+		*val = readb(addr + reg);
+		break;
+	case 2:
+		*val = readw(addr + reg);
+		break;
+	case 4:
+		*val = readl(addr + reg);
+		break;
+	}
+	err = 0;
+err:
+	rcu_read_unlock();
+	return err;
+}
+
+int raw_pci_write(unsigned int seg, unsigned int bus,
+		unsigned int devfn, int reg, int len, u32 val)
+{
+	struct pci_mmcfg_region *mcfg;
+	void __iomem *addr;
+	int err = -EINVAL;
+
+	rcu_read_lock();
+	mcfg = pci_mmconfig_lookup(seg, bus);
+	if (!mcfg || !mcfg->virt)
+		goto err;
+
+	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
+	switch (len) {
+	case 1:
+		writeb(val, addr + reg);
+		break;
+	case 2:
+		writew(val, addr + reg);
+		break;
+	case 4:
+		writel(val, addr + reg);
+		break;
+	}
+	err = 0;
+err:
+	rcu_read_unlock();
+	return err;
+}
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index d410885..f8d62e3 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -143,6 +143,22 @@ static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
 #endif	/* CONFIG_ACPI */
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_ACPI_PCI_HOST_GENERIC)
+static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
+{
+	struct pci_bus *b = bridge->bus;
+	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)b->sysdata;
+
+	ACPI_COMPANION_SET(&bridge->dev, ci->bridge);
+}
+
+static inline u16 acpi_pci_get_segment(void *sysdata)
+{
+	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)sysdata;
+
+	return ci->root->segment;
+}
+#else
 static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
 {
 	/* leave it to the platform for now */
@@ -152,6 +168,7 @@ static inline u16 acpi_pci_get_segment(void *sysdata)
 {
 	return 0;
 }
+#endif
 
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-01-29  9:05 ` Jayachandran C
                   ` (9 preceding siblings ...)
  (?)
@ 2016-01-29  9:05 ` Jayachandran C
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran C @ 2016-01-29  9:05 UTC (permalink / raw)
  To: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki
  Cc: Tomasz Nowicki, Lorenzo Pieralisi, Jayachandran C, xen-devel

Add a simple ACPI based PCI host controller under config option
ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
of pci_acpi_scan_root().

The pci_mmcfg_list handling is done by the ACPI code, so we keep a
reference to the pci_mmcfg_region in sysdata. The ECAM region will
be already mapped, so map_bus can be implemented by using the
virt pointer for the pci_mmcfg_region. pci_generic_config_read
and pci_generic_config_write are used for config space read/write.

Also, we provide implementations of raw_pci_read and raw_pci_write
hat are needed by ACPI based on the pci_mmcfg_list.

pci_acpi_set_companion() and acpi_pci_get_segment() are defined
using sysdata of generic ACPI host controller so that PCI domain
and ACPI companion are set in PCI code rather than platform code.

This code is currently enabled only for ARM64.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
---
 drivers/acpi/Kconfig         |   8 ++
 drivers/acpi/Makefile        |   1 +
 drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci-acpi.h     |  17 ++++
 4 files changed, 212 insertions(+)
 create mode 100644 drivers/acpi/pci_host_acpi.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 82b96ee..65fb483 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -294,6 +294,14 @@ config ACPI_NUMA
 	depends on (X86 || IA64)
 	default y if IA64_GENERIC || IA64_SGI_SN2
 
+config ACPI_PCI_HOST_GENERIC
+	bool "Generic ACPI PCI host controller"
+	depends on ARM64 && ACPI
+	help
+	  Say Y here if you want to support a simple generic ACPI PCI host
+	  controller.
+
+
 config ACPI_CUSTOM_DSDT_FILE
 	string "Custom DSDT Table file to include"
 	default ""
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 74976f1..346101c 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -41,6 +41,7 @@ acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o
 acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
+acpi-$(CONFIG_ACPI_PCI_HOST_GENERIC) += pci_host_acpi.o
 acpi-y				+= acpi_lpss.o acpi_apd.o
 acpi-y				+= acpi_platform.o
 acpi-y				+= acpi_pnp.o
diff --git a/drivers/acpi/pci_host_acpi.c b/drivers/acpi/pci_host_acpi.c
new file mode 100644
index 0000000..9dbdd81
--- /dev/null
+++ b/drivers/acpi/pci_host_acpi.c
@@ -0,0 +1,186 @@
+/*
+ * Generic PCI host controller driver for ACPI based systems
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (c) 2015 Broadcom Corporation
+ *
+ * Based on drivers/pci/host/pci-host-generic.c
+ * Copyright (C) 2014 ARM Limited
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/sfi_acpi.h>
+#include <linux/slab.h>
+
+#define PREFIX			"pci-host-acpi:"
+
+/* sysdata pointer is ->root_info */
+struct gen_acpi_root_info {
+	struct acpi_pci_root_info	common;
+	struct pci_mmcfg_region		*mcfg;
+	bool				mcfg_added;
+};
+
+/* find mapping of a MCFG area */
+static void __iomem *gen_acpi_map_cfg_bus(struct pci_bus *bus,
+			unsigned int devfn, int where)
+{
+	struct gen_acpi_root_info *pci = bus->sysdata;
+	struct pci_mmcfg_region *mcfg = pci->mcfg;
+
+	if (bus->number < mcfg->start_bus || bus->number > mcfg->end_bus)
+		return NULL;
+
+	return mcfg->virt +
+		PCI_MMCFG_OFFSET(bus->number - mcfg->start_bus, devfn) +
+		where;
+}
+
+static struct pci_ops gen_acpi_pci_ops = {
+	.map_bus	= gen_acpi_map_cfg_bus,
+	.read		= pci_generic_config_read,
+	.write		= pci_generic_config_write,
+};
+
+/* Insert the ECFG area for a root bus */
+static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
+{
+	struct gen_acpi_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+	struct device *dev = &ci->bridge->dev;
+	int err;
+
+	info = container_of(ci, struct gen_acpi_root_info, common);
+	err = pci_mmconfig_insert(dev, root->segment, root->secondary.start,
+			root->secondary.end, root->mcfg_addr);
+	if (err && err != -EEXIST)
+		return err;
+
+	info->mcfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
+	WARN_ON(info->mcfg == NULL);
+	info->mcfg_added = (err == -EEXIST);
+	return 0;
+}
+
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
+{
+	struct gen_acpi_root_info *info;
+	struct acpi_pci_root *root = ci->root;
+
+	info = container_of(ci, struct gen_acpi_root_info, common);
+	if (info->mcfg_added)
+		pci_mmconfig_delete(root->segment, root->secondary.start,
+					root->secondary.end);
+	info->mcfg = NULL;
+}
+
+static struct acpi_pci_root_ops pci_acpi_root_ops = {
+	.pci_ops = &gen_acpi_pci_ops,
+	.init_info = pci_acpi_root_init_info,
+	.release_info = pci_acpi_root_release_info,
+};
+
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+{
+	struct acpi_device *device = root->device;
+	struct gen_acpi_root_info *ri;
+	struct pci_bus *bus, *child;
+
+	/* allocate acpi_info/sysdata */
+	ri = devm_kzalloc(&device->dev, sizeof(*ri), GFP_KERNEL);
+	if (!ri) {
+		dev_err(&device->dev,
+			"pci_bus %04x:%02x: ignored (out of memory)\n",
+			root->segment, (int)root->secondary.start);
+		return NULL;
+	}
+
+	bus =  acpi_pci_root_create(root, &pci_acpi_root_ops,
+					&ri->common, ri);
+	if (!bus) {
+		dev_err(&device->dev, "Scanning rootbus failed");
+		return NULL;
+	}
+
+	pci_bus_size_bridges(bus);
+	pci_bus_assign_resources(bus);
+	list_for_each_entry(child, &bus->children, node)
+		pcie_bus_configure_settings(child);
+
+	return bus;
+}
+
+int raw_pci_read(unsigned int seg, unsigned int bus,
+		  unsigned int devfn, int reg, int len, u32 *val)
+{
+	struct pci_mmcfg_region *mcfg;
+	void __iomem *addr;
+	int err = -EINVAL;
+
+	rcu_read_lock();
+	mcfg = pci_mmconfig_lookup(seg, bus);
+	if (!mcfg || !mcfg->virt)
+		goto err;
+
+	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
+	switch (len) {
+	case 1:
+		*val = readb(addr + reg);
+		break;
+	case 2:
+		*val = readw(addr + reg);
+		break;
+	case 4:
+		*val = readl(addr + reg);
+		break;
+	}
+	err = 0;
+err:
+	rcu_read_unlock();
+	return err;
+}
+
+int raw_pci_write(unsigned int seg, unsigned int bus,
+		unsigned int devfn, int reg, int len, u32 val)
+{
+	struct pci_mmcfg_region *mcfg;
+	void __iomem *addr;
+	int err = -EINVAL;
+
+	rcu_read_lock();
+	mcfg = pci_mmconfig_lookup(seg, bus);
+	if (!mcfg || !mcfg->virt)
+		goto err;
+
+	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
+	switch (len) {
+	case 1:
+		writeb(val, addr + reg);
+		break;
+	case 2:
+		writew(val, addr + reg);
+		break;
+	case 4:
+		writel(val, addr + reg);
+		break;
+	}
+	err = 0;
+err:
+	rcu_read_unlock();
+	return err;
+}
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index d410885..f8d62e3 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -143,6 +143,22 @@ static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
 #endif	/* CONFIG_ACPI */
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_ACPI_PCI_HOST_GENERIC)
+static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
+{
+	struct pci_bus *b = bridge->bus;
+	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)b->sysdata;
+
+	ACPI_COMPANION_SET(&bridge->dev, ci->bridge);
+}
+
+static inline u16 acpi_pci_get_segment(void *sysdata)
+{
+	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)sysdata;
+
+	return ci->root->segment;
+}
+#else
 static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
 {
 	/* leave it to the platform for now */
@@ -152,6 +168,7 @@ static inline u16 acpi_pci_get_segment(void *sysdata)
 {
 	return 0;
 }
+#endif
 
 #ifdef CONFIG_ACPI_APEI
 extern bool aer_acpi_firmware_first(void);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-01-29  9:05   ` Jayachandran C
@ 2016-02-05  0:19     ` Bjorn Helgaas
  -1 siblings, 0 replies; 45+ messages in thread
From: Bjorn Helgaas @ 2016-02-05  0:19 UTC (permalink / raw)
  To: Jayachandran C
  Cc: linux-pci, Bjorn Helgaas, linux-acpi, Arnd Bergmann,
	linux-arm-kernel, Rafael J. Wysocki, Lorenzo Pieralisi,
	Tomasz Nowicki, xen-devel

Hi Jayachandran,

On Fri, Jan 29, 2016 at 02:35:40PM +0530, Jayachandran C wrote:
> Add a simple ACPI based PCI host controller under config option
> ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
> of pci_acpi_scan_root().
> 
> The pci_mmcfg_list handling is done by the ACPI code, so we keep a
> reference to the pci_mmcfg_region in sysdata. The ECAM region will
> be already mapped, so map_bus can be implemented by using the
> virt pointer for the pci_mmcfg_region. pci_generic_config_read
> and pci_generic_config_write are used for config space read/write.
> 
> Also, we provide implementations of raw_pci_read and raw_pci_write
> hat are needed by ACPI based on the pci_mmcfg_list.
> 
> pci_acpi_set_companion() and acpi_pci_get_segment() are defined
> using sysdata of generic ACPI host controller so that PCI domain
> and ACPI companion are set in PCI code rather than platform code.
> 
> This code is currently enabled only for ARM64.
> 
> Signed-off-by: Jayachandran C <jchandra@broadcom.com>
> ---
>  drivers/acpi/Kconfig         |   8 ++
>  drivers/acpi/Makefile        |   1 +
>  drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci-acpi.h     |  17 ++++
>  4 files changed, 212 insertions(+)
>  create mode 100644 drivers/acpi/pci_host_acpi.c

I'm speaking a little bit out of turn here, because this is ACPI code,
but I'm confused about pci_host_acpi.c.  We already have pci_root.c,
which is *supposed* to be arch-independent.  I know pci_root.c is
crufty and could be improved, but it does work today on x86 and ia64,
and it handles some generic things that pci_host_acpi.c does not,
e.g., _OSC, NUMA, host bridge hotplug, etc.

I'd really like to see pci_root.c improved so it could work on x86,
ia64, and arm64.  I'm sure that was probably the first thing you
tried, so likely there are issues there.  Are they insurmountable?

Bjorn

> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index 82b96ee..65fb483 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -294,6 +294,14 @@ config ACPI_NUMA
>  	depends on (X86 || IA64)
>  	default y if IA64_GENERIC || IA64_SGI_SN2
>  
> +config ACPI_PCI_HOST_GENERIC
> +	bool "Generic ACPI PCI host controller"
> +	depends on ARM64 && ACPI
> +	help
> +	  Say Y here if you want to support a simple generic ACPI PCI host
> +	  controller.
> +
> +
>  config ACPI_CUSTOM_DSDT_FILE
>  	string "Custom DSDT Table file to include"
>  	default ""
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 74976f1..346101c 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -41,6 +41,7 @@ acpi-y				+= ec.o
>  acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
>  acpi-y				+= pci_root.o pci_link.o pci_irq.o
>  acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
> +acpi-$(CONFIG_ACPI_PCI_HOST_GENERIC) += pci_host_acpi.o
>  acpi-y				+= acpi_lpss.o acpi_apd.o
>  acpi-y				+= acpi_platform.o
>  acpi-y				+= acpi_pnp.o
> diff --git a/drivers/acpi/pci_host_acpi.c b/drivers/acpi/pci_host_acpi.c
> new file mode 100644
> index 0000000..9dbdd81
> --- /dev/null
> +++ b/drivers/acpi/pci_host_acpi.c
> @@ -0,0 +1,186 @@
> +/*
> + * Generic PCI host controller driver for ACPI based systems
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Copyright (c) 2015 Broadcom Corporation
> + *
> + * Based on drivers/pci/host/pci-host-generic.c
> + * Copyright (C) 2014 ARM Limited
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/acpi.h>
> +#include <linux/pci-acpi.h>
> +#include <linux/sfi_acpi.h>
> +#include <linux/slab.h>
> +
> +#define PREFIX			"pci-host-acpi:"
> +
> +/* sysdata pointer is ->root_info */
> +struct gen_acpi_root_info {
> +	struct acpi_pci_root_info	common;
> +	struct pci_mmcfg_region		*mcfg;
> +	bool				mcfg_added;
> +};
> +
> +/* find mapping of a MCFG area */
> +static void __iomem *gen_acpi_map_cfg_bus(struct pci_bus *bus,
> +			unsigned int devfn, int where)
> +{
> +	struct gen_acpi_root_info *pci = bus->sysdata;
> +	struct pci_mmcfg_region *mcfg = pci->mcfg;
> +
> +	if (bus->number < mcfg->start_bus || bus->number > mcfg->end_bus)
> +		return NULL;
> +
> +	return mcfg->virt +
> +		PCI_MMCFG_OFFSET(bus->number - mcfg->start_bus, devfn) +
> +		where;
> +}
> +
> +static struct pci_ops gen_acpi_pci_ops = {
> +	.map_bus	= gen_acpi_map_cfg_bus,
> +	.read		= pci_generic_config_read,
> +	.write		= pci_generic_config_write,
> +};
> +
> +/* Insert the ECFG area for a root bus */
> +static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
> +{
> +	struct gen_acpi_root_info *info;
> +	struct acpi_pci_root *root = ci->root;
> +	struct device *dev = &ci->bridge->dev;
> +	int err;
> +
> +	info = container_of(ci, struct gen_acpi_root_info, common);
> +	err = pci_mmconfig_insert(dev, root->segment, root->secondary.start,
> +			root->secondary.end, root->mcfg_addr);
> +	if (err && err != -EEXIST)
> +		return err;
> +
> +	info->mcfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
> +	WARN_ON(info->mcfg == NULL);
> +	info->mcfg_added = (err == -EEXIST);
> +	return 0;
> +}
> +
> +static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
> +{
> +	struct gen_acpi_root_info *info;
> +	struct acpi_pci_root *root = ci->root;
> +
> +	info = container_of(ci, struct gen_acpi_root_info, common);
> +	if (info->mcfg_added)
> +		pci_mmconfig_delete(root->segment, root->secondary.start,
> +					root->secondary.end);
> +	info->mcfg = NULL;
> +}
> +
> +static struct acpi_pci_root_ops pci_acpi_root_ops = {
> +	.pci_ops = &gen_acpi_pci_ops,
> +	.init_info = pci_acpi_root_init_info,
> +	.release_info = pci_acpi_root_release_info,
> +};
> +
> +struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
> +{
> +	struct acpi_device *device = root->device;
> +	struct gen_acpi_root_info *ri;
> +	struct pci_bus *bus, *child;
> +
> +	/* allocate acpi_info/sysdata */
> +	ri = devm_kzalloc(&device->dev, sizeof(*ri), GFP_KERNEL);
> +	if (!ri) {
> +		dev_err(&device->dev,
> +			"pci_bus %04x:%02x: ignored (out of memory)\n",
> +			root->segment, (int)root->secondary.start);
> +		return NULL;
> +	}
> +
> +	bus =  acpi_pci_root_create(root, &pci_acpi_root_ops,
> +					&ri->common, ri);
> +	if (!bus) {
> +		dev_err(&device->dev, "Scanning rootbus failed");
> +		return NULL;
> +	}
> +
> +	pci_bus_size_bridges(bus);
> +	pci_bus_assign_resources(bus);
> +	list_for_each_entry(child, &bus->children, node)
> +		pcie_bus_configure_settings(child);
> +
> +	return bus;
> +}
> +
> +int raw_pci_read(unsigned int seg, unsigned int bus,
> +		  unsigned int devfn, int reg, int len, u32 *val)
> +{
> +	struct pci_mmcfg_region *mcfg;
> +	void __iomem *addr;
> +	int err = -EINVAL;
> +
> +	rcu_read_lock();
> +	mcfg = pci_mmconfig_lookup(seg, bus);
> +	if (!mcfg || !mcfg->virt)
> +		goto err;
> +
> +	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
> +	switch (len) {
> +	case 1:
> +		*val = readb(addr + reg);
> +		break;
> +	case 2:
> +		*val = readw(addr + reg);
> +		break;
> +	case 4:
> +		*val = readl(addr + reg);
> +		break;
> +	}
> +	err = 0;
> +err:
> +	rcu_read_unlock();
> +	return err;
> +}
> +
> +int raw_pci_write(unsigned int seg, unsigned int bus,
> +		unsigned int devfn, int reg, int len, u32 val)
> +{
> +	struct pci_mmcfg_region *mcfg;
> +	void __iomem *addr;
> +	int err = -EINVAL;
> +
> +	rcu_read_lock();
> +	mcfg = pci_mmconfig_lookup(seg, bus);
> +	if (!mcfg || !mcfg->virt)
> +		goto err;
> +
> +	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
> +	switch (len) {
> +	case 1:
> +		writeb(val, addr + reg);
> +		break;
> +	case 2:
> +		writew(val, addr + reg);
> +		break;
> +	case 4:
> +		writel(val, addr + reg);
> +		break;
> +	}
> +	err = 0;
> +err:
> +	rcu_read_unlock();
> +	return err;
> +}
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index d410885..f8d62e3 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -143,6 +143,22 @@ static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>  static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>  #endif	/* CONFIG_ACPI */
>  
> +#if defined(CONFIG_ACPI) && defined(CONFIG_ACPI_PCI_HOST_GENERIC)
> +static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
> +{
> +	struct pci_bus *b = bridge->bus;
> +	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)b->sysdata;
> +
> +	ACPI_COMPANION_SET(&bridge->dev, ci->bridge);
> +}
> +
> +static inline u16 acpi_pci_get_segment(void *sysdata)
> +{
> +	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)sysdata;
> +
> +	return ci->root->segment;
> +}
> +#else
>  static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
>  {
>  	/* leave it to the platform for now */
> @@ -152,6 +168,7 @@ static inline u16 acpi_pci_get_segment(void *sysdata)
>  {
>  	return 0;
>  }
> +#endif
>  
>  #ifdef CONFIG_ACPI_APEI
>  extern bool aer_acpi_firmware_first(void);
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-02-05  0:19     ` Bjorn Helgaas
  0 siblings, 0 replies; 45+ messages in thread
From: Bjorn Helgaas @ 2016-02-05  0:19 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jayachandran,

On Fri, Jan 29, 2016 at 02:35:40PM +0530, Jayachandran C wrote:
> Add a simple ACPI based PCI host controller under config option
> ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
> of pci_acpi_scan_root().
> 
> The pci_mmcfg_list handling is done by the ACPI code, so we keep a
> reference to the pci_mmcfg_region in sysdata. The ECAM region will
> be already mapped, so map_bus can be implemented by using the
> virt pointer for the pci_mmcfg_region. pci_generic_config_read
> and pci_generic_config_write are used for config space read/write.
> 
> Also, we provide implementations of raw_pci_read and raw_pci_write
> hat are needed by ACPI based on the pci_mmcfg_list.
> 
> pci_acpi_set_companion() and acpi_pci_get_segment() are defined
> using sysdata of generic ACPI host controller so that PCI domain
> and ACPI companion are set in PCI code rather than platform code.
> 
> This code is currently enabled only for ARM64.
> 
> Signed-off-by: Jayachandran C <jchandra@broadcom.com>
> ---
>  drivers/acpi/Kconfig         |   8 ++
>  drivers/acpi/Makefile        |   1 +
>  drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci-acpi.h     |  17 ++++
>  4 files changed, 212 insertions(+)
>  create mode 100644 drivers/acpi/pci_host_acpi.c

I'm speaking a little bit out of turn here, because this is ACPI code,
but I'm confused about pci_host_acpi.c.  We already have pci_root.c,
which is *supposed* to be arch-independent.  I know pci_root.c is
crufty and could be improved, but it does work today on x86 and ia64,
and it handles some generic things that pci_host_acpi.c does not,
e.g., _OSC, NUMA, host bridge hotplug, etc.

I'd really like to see pci_root.c improved so it could work on x86,
ia64, and arm64.  I'm sure that was probably the first thing you
tried, so likely there are issues there.  Are they insurmountable?

Bjorn

> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index 82b96ee..65fb483 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -294,6 +294,14 @@ config ACPI_NUMA
>  	depends on (X86 || IA64)
>  	default y if IA64_GENERIC || IA64_SGI_SN2
>  
> +config ACPI_PCI_HOST_GENERIC
> +	bool "Generic ACPI PCI host controller"
> +	depends on ARM64 && ACPI
> +	help
> +	  Say Y here if you want to support a simple generic ACPI PCI host
> +	  controller.
> +
> +
>  config ACPI_CUSTOM_DSDT_FILE
>  	string "Custom DSDT Table file to include"
>  	default ""
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 74976f1..346101c 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -41,6 +41,7 @@ acpi-y				+= ec.o
>  acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
>  acpi-y				+= pci_root.o pci_link.o pci_irq.o
>  acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
> +acpi-$(CONFIG_ACPI_PCI_HOST_GENERIC) += pci_host_acpi.o
>  acpi-y				+= acpi_lpss.o acpi_apd.o
>  acpi-y				+= acpi_platform.o
>  acpi-y				+= acpi_pnp.o
> diff --git a/drivers/acpi/pci_host_acpi.c b/drivers/acpi/pci_host_acpi.c
> new file mode 100644
> index 0000000..9dbdd81
> --- /dev/null
> +++ b/drivers/acpi/pci_host_acpi.c
> @@ -0,0 +1,186 @@
> +/*
> + * Generic PCI host controller driver for ACPI based systems
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Copyright (c) 2015 Broadcom Corporation
> + *
> + * Based on drivers/pci/host/pci-host-generic.c
> + * Copyright (C) 2014 ARM Limited
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/acpi.h>
> +#include <linux/pci-acpi.h>
> +#include <linux/sfi_acpi.h>
> +#include <linux/slab.h>
> +
> +#define PREFIX			"pci-host-acpi:"
> +
> +/* sysdata pointer is ->root_info */
> +struct gen_acpi_root_info {
> +	struct acpi_pci_root_info	common;
> +	struct pci_mmcfg_region		*mcfg;
> +	bool				mcfg_added;
> +};
> +
> +/* find mapping of a MCFG area */
> +static void __iomem *gen_acpi_map_cfg_bus(struct pci_bus *bus,
> +			unsigned int devfn, int where)
> +{
> +	struct gen_acpi_root_info *pci = bus->sysdata;
> +	struct pci_mmcfg_region *mcfg = pci->mcfg;
> +
> +	if (bus->number < mcfg->start_bus || bus->number > mcfg->end_bus)
> +		return NULL;
> +
> +	return mcfg->virt +
> +		PCI_MMCFG_OFFSET(bus->number - mcfg->start_bus, devfn) +
> +		where;
> +}
> +
> +static struct pci_ops gen_acpi_pci_ops = {
> +	.map_bus	= gen_acpi_map_cfg_bus,
> +	.read		= pci_generic_config_read,
> +	.write		= pci_generic_config_write,
> +};
> +
> +/* Insert the ECFG area for a root bus */
> +static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
> +{
> +	struct gen_acpi_root_info *info;
> +	struct acpi_pci_root *root = ci->root;
> +	struct device *dev = &ci->bridge->dev;
> +	int err;
> +
> +	info = container_of(ci, struct gen_acpi_root_info, common);
> +	err = pci_mmconfig_insert(dev, root->segment, root->secondary.start,
> +			root->secondary.end, root->mcfg_addr);
> +	if (err && err != -EEXIST)
> +		return err;
> +
> +	info->mcfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
> +	WARN_ON(info->mcfg == NULL);
> +	info->mcfg_added = (err == -EEXIST);
> +	return 0;
> +}
> +
> +static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
> +{
> +	struct gen_acpi_root_info *info;
> +	struct acpi_pci_root *root = ci->root;
> +
> +	info = container_of(ci, struct gen_acpi_root_info, common);
> +	if (info->mcfg_added)
> +		pci_mmconfig_delete(root->segment, root->secondary.start,
> +					root->secondary.end);
> +	info->mcfg = NULL;
> +}
> +
> +static struct acpi_pci_root_ops pci_acpi_root_ops = {
> +	.pci_ops = &gen_acpi_pci_ops,
> +	.init_info = pci_acpi_root_init_info,
> +	.release_info = pci_acpi_root_release_info,
> +};
> +
> +struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
> +{
> +	struct acpi_device *device = root->device;
> +	struct gen_acpi_root_info *ri;
> +	struct pci_bus *bus, *child;
> +
> +	/* allocate acpi_info/sysdata */
> +	ri = devm_kzalloc(&device->dev, sizeof(*ri), GFP_KERNEL);
> +	if (!ri) {
> +		dev_err(&device->dev,
> +			"pci_bus %04x:%02x: ignored (out of memory)\n",
> +			root->segment, (int)root->secondary.start);
> +		return NULL;
> +	}
> +
> +	bus =  acpi_pci_root_create(root, &pci_acpi_root_ops,
> +					&ri->common, ri);
> +	if (!bus) {
> +		dev_err(&device->dev, "Scanning rootbus failed");
> +		return NULL;
> +	}
> +
> +	pci_bus_size_bridges(bus);
> +	pci_bus_assign_resources(bus);
> +	list_for_each_entry(child, &bus->children, node)
> +		pcie_bus_configure_settings(child);
> +
> +	return bus;
> +}
> +
> +int raw_pci_read(unsigned int seg, unsigned int bus,
> +		  unsigned int devfn, int reg, int len, u32 *val)
> +{
> +	struct pci_mmcfg_region *mcfg;
> +	void __iomem *addr;
> +	int err = -EINVAL;
> +
> +	rcu_read_lock();
> +	mcfg = pci_mmconfig_lookup(seg, bus);
> +	if (!mcfg || !mcfg->virt)
> +		goto err;
> +
> +	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
> +	switch (len) {
> +	case 1:
> +		*val = readb(addr + reg);
> +		break;
> +	case 2:
> +		*val = readw(addr + reg);
> +		break;
> +	case 4:
> +		*val = readl(addr + reg);
> +		break;
> +	}
> +	err = 0;
> +err:
> +	rcu_read_unlock();
> +	return err;
> +}
> +
> +int raw_pci_write(unsigned int seg, unsigned int bus,
> +		unsigned int devfn, int reg, int len, u32 val)
> +{
> +	struct pci_mmcfg_region *mcfg;
> +	void __iomem *addr;
> +	int err = -EINVAL;
> +
> +	rcu_read_lock();
> +	mcfg = pci_mmconfig_lookup(seg, bus);
> +	if (!mcfg || !mcfg->virt)
> +		goto err;
> +
> +	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
> +	switch (len) {
> +	case 1:
> +		writeb(val, addr + reg);
> +		break;
> +	case 2:
> +		writew(val, addr + reg);
> +		break;
> +	case 4:
> +		writel(val, addr + reg);
> +		break;
> +	}
> +	err = 0;
> +err:
> +	rcu_read_unlock();
> +	return err;
> +}
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index d410885..f8d62e3 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -143,6 +143,22 @@ static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>  static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>  #endif	/* CONFIG_ACPI */
>  
> +#if defined(CONFIG_ACPI) && defined(CONFIG_ACPI_PCI_HOST_GENERIC)
> +static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
> +{
> +	struct pci_bus *b = bridge->bus;
> +	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)b->sysdata;
> +
> +	ACPI_COMPANION_SET(&bridge->dev, ci->bridge);
> +}
> +
> +static inline u16 acpi_pci_get_segment(void *sysdata)
> +{
> +	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)sysdata;
> +
> +	return ci->root->segment;
> +}
> +#else
>  static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
>  {
>  	/* leave it to the platform for now */
> @@ -152,6 +168,7 @@ static inline u16 acpi_pci_get_segment(void *sysdata)
>  {
>  	return 0;
>  }
> +#endif
>  
>  #ifdef CONFIG_ACPI_APEI
>  extern bool aer_acpi_firmware_first(void);
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-01-29  9:05   ` Jayachandran C
  (?)
  (?)
@ 2016-02-05  0:19   ` Bjorn Helgaas
  -1 siblings, 0 replies; 45+ messages in thread
From: Bjorn Helgaas @ 2016-02-05  0:19 UTC (permalink / raw)
  To: Jayachandran C
  Cc: Lorenzo Pieralisi, Arnd Bergmann, linux-pci, Rafael J. Wysocki,
	linux-acpi, Tomasz Nowicki, Bjorn Helgaas, xen-devel,
	linux-arm-kernel

Hi Jayachandran,

On Fri, Jan 29, 2016 at 02:35:40PM +0530, Jayachandran C wrote:
> Add a simple ACPI based PCI host controller under config option
> ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
> of pci_acpi_scan_root().
> 
> The pci_mmcfg_list handling is done by the ACPI code, so we keep a
> reference to the pci_mmcfg_region in sysdata. The ECAM region will
> be already mapped, so map_bus can be implemented by using the
> virt pointer for the pci_mmcfg_region. pci_generic_config_read
> and pci_generic_config_write are used for config space read/write.
> 
> Also, we provide implementations of raw_pci_read and raw_pci_write
> hat are needed by ACPI based on the pci_mmcfg_list.
> 
> pci_acpi_set_companion() and acpi_pci_get_segment() are defined
> using sysdata of generic ACPI host controller so that PCI domain
> and ACPI companion are set in PCI code rather than platform code.
> 
> This code is currently enabled only for ARM64.
> 
> Signed-off-by: Jayachandran C <jchandra@broadcom.com>
> ---
>  drivers/acpi/Kconfig         |   8 ++
>  drivers/acpi/Makefile        |   1 +
>  drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci-acpi.h     |  17 ++++
>  4 files changed, 212 insertions(+)
>  create mode 100644 drivers/acpi/pci_host_acpi.c

I'm speaking a little bit out of turn here, because this is ACPI code,
but I'm confused about pci_host_acpi.c.  We already have pci_root.c,
which is *supposed* to be arch-independent.  I know pci_root.c is
crufty and could be improved, but it does work today on x86 and ia64,
and it handles some generic things that pci_host_acpi.c does not,
e.g., _OSC, NUMA, host bridge hotplug, etc.

I'd really like to see pci_root.c improved so it could work on x86,
ia64, and arm64.  I'm sure that was probably the first thing you
tried, so likely there are issues there.  Are they insurmountable?

Bjorn

> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index 82b96ee..65fb483 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -294,6 +294,14 @@ config ACPI_NUMA
>  	depends on (X86 || IA64)
>  	default y if IA64_GENERIC || IA64_SGI_SN2
>  
> +config ACPI_PCI_HOST_GENERIC
> +	bool "Generic ACPI PCI host controller"
> +	depends on ARM64 && ACPI
> +	help
> +	  Say Y here if you want to support a simple generic ACPI PCI host
> +	  controller.
> +
> +
>  config ACPI_CUSTOM_DSDT_FILE
>  	string "Custom DSDT Table file to include"
>  	default ""
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 74976f1..346101c 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -41,6 +41,7 @@ acpi-y				+= ec.o
>  acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
>  acpi-y				+= pci_root.o pci_link.o pci_irq.o
>  acpi-$(CONFIG_PCI_MMCONFIG)	+= pci_mcfg.o
> +acpi-$(CONFIG_ACPI_PCI_HOST_GENERIC) += pci_host_acpi.o
>  acpi-y				+= acpi_lpss.o acpi_apd.o
>  acpi-y				+= acpi_platform.o
>  acpi-y				+= acpi_pnp.o
> diff --git a/drivers/acpi/pci_host_acpi.c b/drivers/acpi/pci_host_acpi.c
> new file mode 100644
> index 0000000..9dbdd81
> --- /dev/null
> +++ b/drivers/acpi/pci_host_acpi.c
> @@ -0,0 +1,186 @@
> +/*
> + * Generic PCI host controller driver for ACPI based systems
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Copyright (c) 2015 Broadcom Corporation
> + *
> + * Based on drivers/pci/host/pci-host-generic.c
> + * Copyright (C) 2014 ARM Limited
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/acpi.h>
> +#include <linux/pci-acpi.h>
> +#include <linux/sfi_acpi.h>
> +#include <linux/slab.h>
> +
> +#define PREFIX			"pci-host-acpi:"
> +
> +/* sysdata pointer is ->root_info */
> +struct gen_acpi_root_info {
> +	struct acpi_pci_root_info	common;
> +	struct pci_mmcfg_region		*mcfg;
> +	bool				mcfg_added;
> +};
> +
> +/* find mapping of a MCFG area */
> +static void __iomem *gen_acpi_map_cfg_bus(struct pci_bus *bus,
> +			unsigned int devfn, int where)
> +{
> +	struct gen_acpi_root_info *pci = bus->sysdata;
> +	struct pci_mmcfg_region *mcfg = pci->mcfg;
> +
> +	if (bus->number < mcfg->start_bus || bus->number > mcfg->end_bus)
> +		return NULL;
> +
> +	return mcfg->virt +
> +		PCI_MMCFG_OFFSET(bus->number - mcfg->start_bus, devfn) +
> +		where;
> +}
> +
> +static struct pci_ops gen_acpi_pci_ops = {
> +	.map_bus	= gen_acpi_map_cfg_bus,
> +	.read		= pci_generic_config_read,
> +	.write		= pci_generic_config_write,
> +};
> +
> +/* Insert the ECFG area for a root bus */
> +static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
> +{
> +	struct gen_acpi_root_info *info;
> +	struct acpi_pci_root *root = ci->root;
> +	struct device *dev = &ci->bridge->dev;
> +	int err;
> +
> +	info = container_of(ci, struct gen_acpi_root_info, common);
> +	err = pci_mmconfig_insert(dev, root->segment, root->secondary.start,
> +			root->secondary.end, root->mcfg_addr);
> +	if (err && err != -EEXIST)
> +		return err;
> +
> +	info->mcfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
> +	WARN_ON(info->mcfg == NULL);
> +	info->mcfg_added = (err == -EEXIST);
> +	return 0;
> +}
> +
> +static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
> +{
> +	struct gen_acpi_root_info *info;
> +	struct acpi_pci_root *root = ci->root;
> +
> +	info = container_of(ci, struct gen_acpi_root_info, common);
> +	if (info->mcfg_added)
> +		pci_mmconfig_delete(root->segment, root->secondary.start,
> +					root->secondary.end);
> +	info->mcfg = NULL;
> +}
> +
> +static struct acpi_pci_root_ops pci_acpi_root_ops = {
> +	.pci_ops = &gen_acpi_pci_ops,
> +	.init_info = pci_acpi_root_init_info,
> +	.release_info = pci_acpi_root_release_info,
> +};
> +
> +struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
> +{
> +	struct acpi_device *device = root->device;
> +	struct gen_acpi_root_info *ri;
> +	struct pci_bus *bus, *child;
> +
> +	/* allocate acpi_info/sysdata */
> +	ri = devm_kzalloc(&device->dev, sizeof(*ri), GFP_KERNEL);
> +	if (!ri) {
> +		dev_err(&device->dev,
> +			"pci_bus %04x:%02x: ignored (out of memory)\n",
> +			root->segment, (int)root->secondary.start);
> +		return NULL;
> +	}
> +
> +	bus =  acpi_pci_root_create(root, &pci_acpi_root_ops,
> +					&ri->common, ri);
> +	if (!bus) {
> +		dev_err(&device->dev, "Scanning rootbus failed");
> +		return NULL;
> +	}
> +
> +	pci_bus_size_bridges(bus);
> +	pci_bus_assign_resources(bus);
> +	list_for_each_entry(child, &bus->children, node)
> +		pcie_bus_configure_settings(child);
> +
> +	return bus;
> +}
> +
> +int raw_pci_read(unsigned int seg, unsigned int bus,
> +		  unsigned int devfn, int reg, int len, u32 *val)
> +{
> +	struct pci_mmcfg_region *mcfg;
> +	void __iomem *addr;
> +	int err = -EINVAL;
> +
> +	rcu_read_lock();
> +	mcfg = pci_mmconfig_lookup(seg, bus);
> +	if (!mcfg || !mcfg->virt)
> +		goto err;
> +
> +	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
> +	switch (len) {
> +	case 1:
> +		*val = readb(addr + reg);
> +		break;
> +	case 2:
> +		*val = readw(addr + reg);
> +		break;
> +	case 4:
> +		*val = readl(addr + reg);
> +		break;
> +	}
> +	err = 0;
> +err:
> +	rcu_read_unlock();
> +	return err;
> +}
> +
> +int raw_pci_write(unsigned int seg, unsigned int bus,
> +		unsigned int devfn, int reg, int len, u32 val)
> +{
> +	struct pci_mmcfg_region *mcfg;
> +	void __iomem *addr;
> +	int err = -EINVAL;
> +
> +	rcu_read_lock();
> +	mcfg = pci_mmconfig_lookup(seg, bus);
> +	if (!mcfg || !mcfg->virt)
> +		goto err;
> +
> +	addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn);
> +	switch (len) {
> +	case 1:
> +		writeb(val, addr + reg);
> +		break;
> +	case 2:
> +		writew(val, addr + reg);
> +		break;
> +	case 4:
> +		writel(val, addr + reg);
> +		break;
> +	}
> +	err = 0;
> +err:
> +	rcu_read_unlock();
> +	return err;
> +}
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index d410885..f8d62e3 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -143,6 +143,22 @@ static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>  static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>  #endif	/* CONFIG_ACPI */
>  
> +#if defined(CONFIG_ACPI) && defined(CONFIG_ACPI_PCI_HOST_GENERIC)
> +static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
> +{
> +	struct pci_bus *b = bridge->bus;
> +	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)b->sysdata;
> +
> +	ACPI_COMPANION_SET(&bridge->dev, ci->bridge);
> +}
> +
> +static inline u16 acpi_pci_get_segment(void *sysdata)
> +{
> +	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)sysdata;
> +
> +	return ci->root->segment;
> +}
> +#else
>  static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
>  {
>  	/* leave it to the platform for now */
> @@ -152,6 +168,7 @@ static inline u16 acpi_pci_get_segment(void *sysdata)
>  {
>  	return 0;
>  }
> +#endif
>  
>  #ifdef CONFIG_ACPI_APEI
>  extern bool aer_acpi_firmware_first(void);
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05  0:19     ` Bjorn Helgaas
  (?)
@ 2016-02-05  8:35       ` Jayachandran Chandrashekaran Nair
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-05  8:35 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Lorenzo Pieralisi, Jayachandran C, Arnd Bergmann, linux-pci,
	Rafael J. Wysocki, linux-acpi, Tomasz Nowicki, Bjorn Helgaas,
	xen-devel, linux-arm-kernel

Hi Bjorn,

On Fri, Feb 5, 2016 at 5:49 AM, Bjorn Helgaas <helgaas@kernel.org> wrote:
> Hi Jayachandran,
>
> On Fri, Jan 29, 2016 at 02:35:40PM +0530, Jayachandran C wrote:
>> Add a simple ACPI based PCI host controller under config option
>> ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
>> of pci_acpi_scan_root().
>>
>> The pci_mmcfg_list handling is done by the ACPI code, so we keep a
>> reference to the pci_mmcfg_region in sysdata. The ECAM region will
>> be already mapped, so map_bus can be implemented by using the
>> virt pointer for the pci_mmcfg_region. pci_generic_config_read
>> and pci_generic_config_write are used for config space read/write.
>>
>> Also, we provide implementations of raw_pci_read and raw_pci_write
>> hat are needed by ACPI based on the pci_mmcfg_list.
>>
>> pci_acpi_set_companion() and acpi_pci_get_segment() are defined
>> using sysdata of generic ACPI host controller so that PCI domain
>> and ACPI companion are set in PCI code rather than platform code.
>>
>> This code is currently enabled only for ARM64.
>>
>> Signed-off-by: Jayachandran C <jchandra@broadcom.com>
>> ---
>>  drivers/acpi/Kconfig         |   8 ++
>>  drivers/acpi/Makefile        |   1 +
>>  drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/pci-acpi.h     |  17 ++++
>>  4 files changed, 212 insertions(+)
>>  create mode 100644 drivers/acpi/pci_host_acpi.c
>
> I'm speaking a little bit out of turn here, because this is ACPI code,
> but I'm confused about pci_host_acpi.c.  We already have pci_root.c,
> which is *supposed* to be arch-independent.  I know pci_root.c is
> crufty and could be improved, but it does work today on x86 and ia64,
> and it handles some generic things that pci_host_acpi.c does not,
> e.g., _OSC, NUMA, host bridge hotplug, etc.
>
> I'd really like to see pci_root.c improved so it could work on x86,
> ia64, and arm64.  I'm sure that was probably the first thing you
> tried, so likely there are issues there.  Are they insurmountable?

pci_root.c leaves the implementation of pci_acpi_scan_root() to the
architecture. Implementing pci_acpi_scan_root needs a
pci_acpi_root_ops instance and a pci_ops instance and related functions.
The architecture is also expected to implement raw_pci_read and
raw_pci_write.

pci_host_acpi.c is a generic implementation of these using a sysdata
pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
to access ECAM area, Maybe I can rename this file to
pci_acpi_host_generic.c to reflect this better.

arm64 is the only user of this generic implementation now. The config
option CONFIG_ACPI_PCI_HOST_GENERIC has to be set on the
architecture that chooses to use this generic code instead of its own
implementation.

JC.
{Sorry if the formatting is wrong, using webmail due to internal IT changes]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-02-05  8:35       ` Jayachandran Chandrashekaran Nair
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-05  8:35 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Jayachandran C, linux-pci, Bjorn Helgaas, linux-acpi,
	Arnd Bergmann, linux-arm-kernel, Rafael J. Wysocki,
	Lorenzo Pieralisi, Tomasz Nowicki, xen-devel

Hi Bjorn,

On Fri, Feb 5, 2016 at 5:49 AM, Bjorn Helgaas <helgaas@kernel.org> wrote:
> Hi Jayachandran,
>
> On Fri, Jan 29, 2016 at 02:35:40PM +0530, Jayachandran C wrote:
>> Add a simple ACPI based PCI host controller under config option
>> ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
>> of pci_acpi_scan_root().
>>
>> The pci_mmcfg_list handling is done by the ACPI code, so we keep a
>> reference to the pci_mmcfg_region in sysdata. The ECAM region will
>> be already mapped, so map_bus can be implemented by using the
>> virt pointer for the pci_mmcfg_region. pci_generic_config_read
>> and pci_generic_config_write are used for config space read/write.
>>
>> Also, we provide implementations of raw_pci_read and raw_pci_write
>> hat are needed by ACPI based on the pci_mmcfg_list.
>>
>> pci_acpi_set_companion() and acpi_pci_get_segment() are defined
>> using sysdata of generic ACPI host controller so that PCI domain
>> and ACPI companion are set in PCI code rather than platform code.
>>
>> This code is currently enabled only for ARM64.
>>
>> Signed-off-by: Jayachandran C <jchandra@broadcom.com>
>> ---
>>  drivers/acpi/Kconfig         |   8 ++
>>  drivers/acpi/Makefile        |   1 +
>>  drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/pci-acpi.h     |  17 ++++
>>  4 files changed, 212 insertions(+)
>>  create mode 100644 drivers/acpi/pci_host_acpi.c
>
> I'm speaking a little bit out of turn here, because this is ACPI code,
> but I'm confused about pci_host_acpi.c.  We already have pci_root.c,
> which is *supposed* to be arch-independent.  I know pci_root.c is
> crufty and could be improved, but it does work today on x86 and ia64,
> and it handles some generic things that pci_host_acpi.c does not,
> e.g., _OSC, NUMA, host bridge hotplug, etc.
>
> I'd really like to see pci_root.c improved so it could work on x86,
> ia64, and arm64.  I'm sure that was probably the first thing you
> tried, so likely there are issues there.  Are they insurmountable?

pci_root.c leaves the implementation of pci_acpi_scan_root() to the
architecture. Implementing pci_acpi_scan_root needs a
pci_acpi_root_ops instance and a pci_ops instance and related functions.
The architecture is also expected to implement raw_pci_read and
raw_pci_write.

pci_host_acpi.c is a generic implementation of these using a sysdata
pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
to access ECAM area, Maybe I can rename this file to
pci_acpi_host_generic.c to reflect this better.

arm64 is the only user of this generic implementation now. The config
option CONFIG_ACPI_PCI_HOST_GENERIC has to be set on the
architecture that chooses to use this generic code instead of its own
implementation.

JC.
{Sorry if the formatting is wrong, using webmail due to internal IT changes]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-02-05  8:35       ` Jayachandran Chandrashekaran Nair
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-05  8:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Bjorn,

On Fri, Feb 5, 2016 at 5:49 AM, Bjorn Helgaas <helgaas@kernel.org> wrote:
> Hi Jayachandran,
>
> On Fri, Jan 29, 2016 at 02:35:40PM +0530, Jayachandran C wrote:
>> Add a simple ACPI based PCI host controller under config option
>> ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
>> of pci_acpi_scan_root().
>>
>> The pci_mmcfg_list handling is done by the ACPI code, so we keep a
>> reference to the pci_mmcfg_region in sysdata. The ECAM region will
>> be already mapped, so map_bus can be implemented by using the
>> virt pointer for the pci_mmcfg_region. pci_generic_config_read
>> and pci_generic_config_write are used for config space read/write.
>>
>> Also, we provide implementations of raw_pci_read and raw_pci_write
>> hat are needed by ACPI based on the pci_mmcfg_list.
>>
>> pci_acpi_set_companion() and acpi_pci_get_segment() are defined
>> using sysdata of generic ACPI host controller so that PCI domain
>> and ACPI companion are set in PCI code rather than platform code.
>>
>> This code is currently enabled only for ARM64.
>>
>> Signed-off-by: Jayachandran C <jchandra@broadcom.com>
>> ---
>>  drivers/acpi/Kconfig         |   8 ++
>>  drivers/acpi/Makefile        |   1 +
>>  drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/pci-acpi.h     |  17 ++++
>>  4 files changed, 212 insertions(+)
>>  create mode 100644 drivers/acpi/pci_host_acpi.c
>
> I'm speaking a little bit out of turn here, because this is ACPI code,
> but I'm confused about pci_host_acpi.c.  We already have pci_root.c,
> which is *supposed* to be arch-independent.  I know pci_root.c is
> crufty and could be improved, but it does work today on x86 and ia64,
> and it handles some generic things that pci_host_acpi.c does not,
> e.g., _OSC, NUMA, host bridge hotplug, etc.
>
> I'd really like to see pci_root.c improved so it could work on x86,
> ia64, and arm64.  I'm sure that was probably the first thing you
> tried, so likely there are issues there.  Are they insurmountable?

pci_root.c leaves the implementation of pci_acpi_scan_root() to the
architecture. Implementing pci_acpi_scan_root needs a
pci_acpi_root_ops instance and a pci_ops instance and related functions.
The architecture is also expected to implement raw_pci_read and
raw_pci_write.

pci_host_acpi.c is a generic implementation of these using a sysdata
pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
to access ECAM area, Maybe I can rename this file to
pci_acpi_host_generic.c to reflect this better.

arm64 is the only user of this generic implementation now. The config
option CONFIG_ACPI_PCI_HOST_GENERIC has to be set on the
architecture that chooses to use this generic code instead of its own
implementation.

JC.
{Sorry if the formatting is wrong, using webmail due to internal IT changes]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05  0:19     ` Bjorn Helgaas
  (?)
@ 2016-02-05  8:35     ` Jayachandran Chandrashekaran Nair
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-05  8:35 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Lorenzo Pieralisi, Jayachandran C, Arnd Bergmann, linux-pci,
	Rafael J. Wysocki, linux-acpi, Tomasz Nowicki, Bjorn Helgaas,
	xen-devel, linux-arm-kernel

Hi Bjorn,

On Fri, Feb 5, 2016 at 5:49 AM, Bjorn Helgaas <helgaas@kernel.org> wrote:
> Hi Jayachandran,
>
> On Fri, Jan 29, 2016 at 02:35:40PM +0530, Jayachandran C wrote:
>> Add a simple ACPI based PCI host controller under config option
>> ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
>> of pci_acpi_scan_root().
>>
>> The pci_mmcfg_list handling is done by the ACPI code, so we keep a
>> reference to the pci_mmcfg_region in sysdata. The ECAM region will
>> be already mapped, so map_bus can be implemented by using the
>> virt pointer for the pci_mmcfg_region. pci_generic_config_read
>> and pci_generic_config_write are used for config space read/write.
>>
>> Also, we provide implementations of raw_pci_read and raw_pci_write
>> hat are needed by ACPI based on the pci_mmcfg_list.
>>
>> pci_acpi_set_companion() and acpi_pci_get_segment() are defined
>> using sysdata of generic ACPI host controller so that PCI domain
>> and ACPI companion are set in PCI code rather than platform code.
>>
>> This code is currently enabled only for ARM64.
>>
>> Signed-off-by: Jayachandran C <jchandra@broadcom.com>
>> ---
>>  drivers/acpi/Kconfig         |   8 ++
>>  drivers/acpi/Makefile        |   1 +
>>  drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/pci-acpi.h     |  17 ++++
>>  4 files changed, 212 insertions(+)
>>  create mode 100644 drivers/acpi/pci_host_acpi.c
>
> I'm speaking a little bit out of turn here, because this is ACPI code,
> but I'm confused about pci_host_acpi.c.  We already have pci_root.c,
> which is *supposed* to be arch-independent.  I know pci_root.c is
> crufty and could be improved, but it does work today on x86 and ia64,
> and it handles some generic things that pci_host_acpi.c does not,
> e.g., _OSC, NUMA, host bridge hotplug, etc.
>
> I'd really like to see pci_root.c improved so it could work on x86,
> ia64, and arm64.  I'm sure that was probably the first thing you
> tried, so likely there are issues there.  Are they insurmountable?

pci_root.c leaves the implementation of pci_acpi_scan_root() to the
architecture. Implementing pci_acpi_scan_root needs a
pci_acpi_root_ops instance and a pci_ops instance and related functions.
The architecture is also expected to implement raw_pci_read and
raw_pci_write.

pci_host_acpi.c is a generic implementation of these using a sysdata
pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
to access ECAM area, Maybe I can rename this file to
pci_acpi_host_generic.c to reflect this better.

arm64 is the only user of this generic implementation now. The config
option CONFIG_ACPI_PCI_HOST_GENERIC has to be set on the
architecture that chooses to use this generic code instead of its own
implementation.

JC.
{Sorry if the formatting is wrong, using webmail due to internal IT changes]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05  8:35       ` Jayachandran Chandrashekaran Nair
@ 2016-02-05  9:47         ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 45+ messages in thread
From: Lorenzo Pieralisi @ 2016-02-05  9:47 UTC (permalink / raw)
  To: Jayachandran Chandrashekaran Nair
  Cc: Bjorn Helgaas, Jayachandran C, linux-pci, Bjorn Helgaas,
	linux-acpi, Arnd Bergmann, linux-arm-kernel, Rafael J. Wysocki,
	Tomasz Nowicki, xen-devel

On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:

[...]

> pci_host_acpi.c is a generic implementation of these using a sysdata
> pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
> to access ECAM area, Maybe I can rename this file to
> pci_acpi_host_generic.c to reflect this better.

Maybe you should stop sending this series and work with Tomasz to
get this done, you are confusing everyone and I am really really
annoyed about this.

Do you realize there is no point in having two patch series doing
the same thing and wasting everyone's review time ?

Do you realize he started this work long before you and went through
several rounds of review already (I told you before but in case you
forgot) ?

Tomasz posted a version yesterday, integrating comments following months
of review and testing and I think it is ready to get upstream:

https://lkml.org/lkml/2016/2/4/646

Did you even consider reviewing his code or helping him instead of
churning out more patches doing the *SAME* thing ?

Do you want all of us to go through your code and re-fix what has
already been fixed in Tomasz's series with the end result of missing
yet another merge window ?

This is really annoying, stop it please, really.

Thank you,
Lorenzo

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-02-05  9:47         ` Lorenzo Pieralisi
  0 siblings, 0 replies; 45+ messages in thread
From: Lorenzo Pieralisi @ 2016-02-05  9:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:

[...]

> pci_host_acpi.c is a generic implementation of these using a sysdata
> pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
> to access ECAM area, Maybe I can rename this file to
> pci_acpi_host_generic.c to reflect this better.

Maybe you should stop sending this series and work with Tomasz to
get this done, you are confusing everyone and I am really really
annoyed about this.

Do you realize there is no point in having two patch series doing
the same thing and wasting everyone's review time ?

Do you realize he started this work long before you and went through
several rounds of review already (I told you before but in case you
forgot) ?

Tomasz posted a version yesterday, integrating comments following months
of review and testing and I think it is ready to get upstream:

https://lkml.org/lkml/2016/2/4/646

Did you even consider reviewing his code or helping him instead of
churning out more patches doing the *SAME* thing ?

Do you want all of us to go through your code and re-fix what has
already been fixed in Tomasz's series with the end result of missing
yet another merge window ?

This is really annoying, stop it please, really.

Thank you,
Lorenzo

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05  8:35       ` Jayachandran Chandrashekaran Nair
  (?)
  (?)
@ 2016-02-05  9:47       ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 45+ messages in thread
From: Lorenzo Pieralisi @ 2016-02-05  9:47 UTC (permalink / raw)
  To: Jayachandran Chandrashekaran Nair
  Cc: Jayachandran C, Arnd Bergmann, linux-pci, Rafael J. Wysocki,
	linux-acpi, Bjorn Helgaas, Tomasz Nowicki, Bjorn Helgaas,
	xen-devel, linux-arm-kernel

On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:

[...]

> pci_host_acpi.c is a generic implementation of these using a sysdata
> pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
> to access ECAM area, Maybe I can rename this file to
> pci_acpi_host_generic.c to reflect this better.

Maybe you should stop sending this series and work with Tomasz to
get this done, you are confusing everyone and I am really really
annoyed about this.

Do you realize there is no point in having two patch series doing
the same thing and wasting everyone's review time ?

Do you realize he started this work long before you and went through
several rounds of review already (I told you before but in case you
forgot) ?

Tomasz posted a version yesterday, integrating comments following months
of review and testing and I think it is ready to get upstream:

https://lkml.org/lkml/2016/2/4/646

Did you even consider reviewing his code or helping him instead of
churning out more patches doing the *SAME* thing ?

Do you want all of us to go through your code and re-fix what has
already been fixed in Tomasz's series with the end result of missing
yet another merge window ?

This is really annoying, stop it please, really.

Thank you,
Lorenzo

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05  9:47         ` Lorenzo Pieralisi
@ 2016-02-05 23:26           ` Rafael J. Wysocki
  -1 siblings, 0 replies; 45+ messages in thread
From: Rafael J. Wysocki @ 2016-02-05 23:26 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Jayachandran Chandrashekaran Nair
  Cc: Bjorn Helgaas, Jayachandran C, linux-pci, Bjorn Helgaas,
	linux-acpi, Arnd Bergmann, linux-arm-kernel, Tomasz Nowicki,
	xen-devel

On Friday, February 05, 2016 09:47:40 AM Lorenzo Pieralisi wrote:
> On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
> 
> [...]
> 
> > pci_host_acpi.c is a generic implementation of these using a sysdata
> > pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
> > to access ECAM area, Maybe I can rename this file to
> > pci_acpi_host_generic.c to reflect this better.
> 
> Maybe you should stop sending this series and work with Tomasz to
> get this done, you are confusing everyone and I am really really
> annoyed about this.
> 
> Do you realize there is no point in having two patch series doing
> the same thing and wasting everyone's review time ?
> 
> Do you realize he started this work long before you and went through
> several rounds of review already (I told you before but in case you
> forgot) ?
> 
> Tomasz posted a version yesterday, integrating comments following months
> of review and testing and I think it is ready to get upstream:
> 
> https://lkml.org/lkml/2016/2/4/646
> 
> Did you even consider reviewing his code or helping him instead of
> churning out more patches doing the *SAME* thing ?
> 
> Do you want all of us to go through your code and re-fix what has
> already been fixed in Tomasz's series with the end result of missing
> yet another merge window ?
> 
> This is really annoying, stop it please, really.

OK, so to be crystal clear here.

I'm going to ignore the series the $subject patch belongs to going forward.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-02-05 23:26           ` Rafael J. Wysocki
  0 siblings, 0 replies; 45+ messages in thread
From: Rafael J. Wysocki @ 2016-02-05 23:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday, February 05, 2016 09:47:40 AM Lorenzo Pieralisi wrote:
> On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
> 
> [...]
> 
> > pci_host_acpi.c is a generic implementation of these using a sysdata
> > pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
> > to access ECAM area, Maybe I can rename this file to
> > pci_acpi_host_generic.c to reflect this better.
> 
> Maybe you should stop sending this series and work with Tomasz to
> get this done, you are confusing everyone and I am really really
> annoyed about this.
> 
> Do you realize there is no point in having two patch series doing
> the same thing and wasting everyone's review time ?
> 
> Do you realize he started this work long before you and went through
> several rounds of review already (I told you before but in case you
> forgot) ?
> 
> Tomasz posted a version yesterday, integrating comments following months
> of review and testing and I think it is ready to get upstream:
> 
> https://lkml.org/lkml/2016/2/4/646
> 
> Did you even consider reviewing his code or helping him instead of
> churning out more patches doing the *SAME* thing ?
> 
> Do you want all of us to go through your code and re-fix what has
> already been fixed in Tomasz's series with the end result of missing
> yet another merge window ?
> 
> This is really annoying, stop it please, really.

OK, so to be crystal clear here.

I'm going to ignore the series the $subject patch belongs to going forward.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05  9:47         ` Lorenzo Pieralisi
  (?)
@ 2016-02-05 23:26         ` Rafael J. Wysocki
  -1 siblings, 0 replies; 45+ messages in thread
From: Rafael J. Wysocki @ 2016-02-05 23:26 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Jayachandran Chandrashekaran Nair
  Cc: Jayachandran C, Arnd Bergmann, linux-pci, linux-acpi,
	Bjorn Helgaas, Tomasz Nowicki, Bjorn Helgaas, xen-devel,
	linux-arm-kernel

On Friday, February 05, 2016 09:47:40 AM Lorenzo Pieralisi wrote:
> On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
> 
> [...]
> 
> > pci_host_acpi.c is a generic implementation of these using a sysdata
> > pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
> > to access ECAM area, Maybe I can rename this file to
> > pci_acpi_host_generic.c to reflect this better.
> 
> Maybe you should stop sending this series and work with Tomasz to
> get this done, you are confusing everyone and I am really really
> annoyed about this.
> 
> Do you realize there is no point in having two patch series doing
> the same thing and wasting everyone's review time ?
> 
> Do you realize he started this work long before you and went through
> several rounds of review already (I told you before but in case you
> forgot) ?
> 
> Tomasz posted a version yesterday, integrating comments following months
> of review and testing and I think it is ready to get upstream:
> 
> https://lkml.org/lkml/2016/2/4/646
> 
> Did you even consider reviewing his code or helping him instead of
> churning out more patches doing the *SAME* thing ?
> 
> Do you want all of us to go through your code and re-fix what has
> already been fixed in Tomasz's series with the end result of missing
> yet another merge window ?
> 
> This is really annoying, stop it please, really.

OK, so to be crystal clear here.

I'm going to ignore the series the $subject patch belongs to going forward.

Thanks,
Rafael

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05 23:26           ` Rafael J. Wysocki
@ 2016-02-06  9:58             ` Jayachandran Chandrashekaran Nair
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-06  9:58 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Lorenzo Pieralisi, Bjorn Helgaas, Jayachandran C, linux-pci,
	Bjorn Helgaas, linux-acpi, Arnd Bergmann, linux-arm-kernel,
	Tomasz Nowicki, xen-devel

Hi Rafael,

On Sat, Feb 6, 2016 at 4:56 AM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Friday, February 05, 2016 09:47:40 AM Lorenzo Pieralisi wrote:
>> On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
>>
>> [...]
>>
>> > pci_host_acpi.c is a generic implementation of these using a sysdata
>> > pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
>> > to access ECAM area, Maybe I can rename this file to
>> > pci_acpi_host_generic.c to reflect this better.
>>
>> Maybe you should stop sending this series and work with Tomasz to
>> get this done, you are confusing everyone and I am really really
>> annoyed about this.
>>
>> Do you realize there is no point in having two patch series doing
>> the same thing and wasting everyone's review time ?
>>
>> Do you realize he started this work long before you and went through
>> several rounds of review already (I told you before but in case you
>> forgot) ?
>>
>> Tomasz posted a version yesterday, integrating comments following months
>> of review and testing and I think it is ready to get upstream:
>>
>> https://lkml.org/lkml/2016/2/4/646
>>
>> Did you even consider reviewing his code or helping him instead of
>> churning out more patches doing the *SAME* thing ?
>>
>> Do you want all of us to go through your code and re-fix what has
>> already been fixed in Tomasz's series with the end result of missing
>> yet another merge window ?
>>
>> This is really annoying, stop it please, really.
>
> OK, so to be crystal clear here.
>
> I'm going to ignore the series the $subject patch belongs to going forward.

It looks like you can already reviewed Tomasz's patchset and as Lorenzo
says thinks that it can be merged.

When I first posted the patchset the state of arm64 ACPI/PCI was not that
clear - and I thought an alternative will help. Ideally I would expect
maintainers to look at technical merit, but in this case any working solution
merged will be great news.

Thanks,
JC.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-02-06  9:58             ` Jayachandran Chandrashekaran Nair
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-06  9:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rafael,

On Sat, Feb 6, 2016 at 4:56 AM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Friday, February 05, 2016 09:47:40 AM Lorenzo Pieralisi wrote:
>> On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
>>
>> [...]
>>
>> > pci_host_acpi.c is a generic implementation of these using a sysdata
>> > pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
>> > to access ECAM area, Maybe I can rename this file to
>> > pci_acpi_host_generic.c to reflect this better.
>>
>> Maybe you should stop sending this series and work with Tomasz to
>> get this done, you are confusing everyone and I am really really
>> annoyed about this.
>>
>> Do you realize there is no point in having two patch series doing
>> the same thing and wasting everyone's review time ?
>>
>> Do you realize he started this work long before you and went through
>> several rounds of review already (I told you before but in case you
>> forgot) ?
>>
>> Tomasz posted a version yesterday, integrating comments following months
>> of review and testing and I think it is ready to get upstream:
>>
>> https://lkml.org/lkml/2016/2/4/646
>>
>> Did you even consider reviewing his code or helping him instead of
>> churning out more patches doing the *SAME* thing ?
>>
>> Do you want all of us to go through your code and re-fix what has
>> already been fixed in Tomasz's series with the end result of missing
>> yet another merge window ?
>>
>> This is really annoying, stop it please, really.
>
> OK, so to be crystal clear here.
>
> I'm going to ignore the series the $subject patch belongs to going forward.

It looks like you can already reviewed Tomasz's patchset and as Lorenzo
says thinks that it can be merged.

When I first posted the patchset the state of arm64 ACPI/PCI was not that
clear - and I thought an alternative will help. Ideally I would expect
maintainers to look at technical merit, but in this case any working solution
merged will be great news.

Thanks,
JC.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05 23:26           ` Rafael J. Wysocki
  (?)
  (?)
@ 2016-02-06  9:58           ` Jayachandran Chandrashekaran Nair
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-06  9:58 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Lorenzo Pieralisi, Jayachandran C, Arnd Bergmann, linux-pci,
	linux-acpi, Bjorn Helgaas, Tomasz Nowicki, Bjorn Helgaas,
	xen-devel, linux-arm-kernel

Hi Rafael,

On Sat, Feb 6, 2016 at 4:56 AM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Friday, February 05, 2016 09:47:40 AM Lorenzo Pieralisi wrote:
>> On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
>>
>> [...]
>>
>> > pci_host_acpi.c is a generic implementation of these using a sysdata
>> > pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
>> > to access ECAM area, Maybe I can rename this file to
>> > pci_acpi_host_generic.c to reflect this better.
>>
>> Maybe you should stop sending this series and work with Tomasz to
>> get this done, you are confusing everyone and I am really really
>> annoyed about this.
>>
>> Do you realize there is no point in having two patch series doing
>> the same thing and wasting everyone's review time ?
>>
>> Do you realize he started this work long before you and went through
>> several rounds of review already (I told you before but in case you
>> forgot) ?
>>
>> Tomasz posted a version yesterday, integrating comments following months
>> of review and testing and I think it is ready to get upstream:
>>
>> https://lkml.org/lkml/2016/2/4/646
>>
>> Did you even consider reviewing his code or helping him instead of
>> churning out more patches doing the *SAME* thing ?
>>
>> Do you want all of us to go through your code and re-fix what has
>> already been fixed in Tomasz's series with the end result of missing
>> yet another merge window ?
>>
>> This is really annoying, stop it please, really.
>
> OK, so to be crystal clear here.
>
> I'm going to ignore the series the $subject patch belongs to going forward.

It looks like you can already reviewed Tomasz's patchset and as Lorenzo
says thinks that it can be merged.

When I first posted the patchset the state of arm64 ACPI/PCI was not that
clear - and I thought an alternative will help. Ideally I would expect
maintainers to look at technical merit, but in this case any working solution
merged will be great news.

Thanks,
JC.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05  9:47         ` Lorenzo Pieralisi
@ 2016-02-08 11:27           ` Jayachandran Chandrashekaran Nair
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-08 11:27 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: Bjorn Helgaas, Jayachandran C, linux-pci, Bjorn Helgaas,
	linux-acpi, Arnd Bergmann, linux-arm-kernel, Rafael J. Wysocki,
	Tomasz Nowicki, xen-devel

Lorenzo,

On Fri, Feb 5, 2016 at 3:17 PM, Lorenzo Pieralisi
<lorenzo.pieralisi@arm.com> wrote:
> On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
>
> [...]
>
>> pci_host_acpi.c is a generic implementation of these using a sysdata
>> pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
>> to access ECAM area, Maybe I can rename this file to
>> pci_acpi_host_generic.c to reflect this better.
>
> Maybe you should stop sending this series and work with Tomasz to
> get this done, you are confusing everyone and I am really really
> annoyed about this.
>
> Do you realize there is no point in having two patch series doing
> the same thing and wasting everyone's review time ?
>
> Do you realize he started this work long before you and went through
> several rounds of review already (I told you before but in case you
> forgot) ?
>
> Tomasz posted a version yesterday, integrating comments following months
> of review and testing and I think it is ready to get upstream:
>
> https://lkml.org/lkml/2016/2/4/646
>
> Did you even consider reviewing his code or helping him instead of
> churning out more patches doing the *SAME* thing ?

This is getting ridiculous, I had replied to your earlier mails on why
my patchset is NOT doing the exact same thing. I had also explained
why helping was not feasible.

The basic point again: I am trying to give a much simpler patchset
to solve the same problem, I take it that you haven't reviewed my
patchset before writing this mail. I would have appreciated
a technical discussion rather than this pointless flamefest.

If you have reviewed it, you can see that there are just 5 patches
instead of 23, and that overall it is a much simpler approach.

> Do you want all of us to go through your code and re-fix what has
> already been fixed in Tomasz's series with the end result of missing
> yet another merge window ?

Again, as I said, the whole point of my patchset is that is much  easier
to go thru and validate and merge or drop as needed.

Anyway, if you are on target to hit this merge window, I really hope
that happens and there will no need for me to spend further time on
this.

Regards,
JC.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-02-08 11:27           ` Jayachandran Chandrashekaran Nair
  0 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-08 11:27 UTC (permalink / raw)
  To: linux-arm-kernel

Lorenzo,

On Fri, Feb 5, 2016 at 3:17 PM, Lorenzo Pieralisi
<lorenzo.pieralisi@arm.com> wrote:
> On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
>
> [...]
>
>> pci_host_acpi.c is a generic implementation of these using a sysdata
>> pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
>> to access ECAM area, Maybe I can rename this file to
>> pci_acpi_host_generic.c to reflect this better.
>
> Maybe you should stop sending this series and work with Tomasz to
> get this done, you are confusing everyone and I am really really
> annoyed about this.
>
> Do you realize there is no point in having two patch series doing
> the same thing and wasting everyone's review time ?
>
> Do you realize he started this work long before you and went through
> several rounds of review already (I told you before but in case you
> forgot) ?
>
> Tomasz posted a version yesterday, integrating comments following months
> of review and testing and I think it is ready to get upstream:
>
> https://lkml.org/lkml/2016/2/4/646
>
> Did you even consider reviewing his code or helping him instead of
> churning out more patches doing the *SAME* thing ?

This is getting ridiculous, I had replied to your earlier mails on why
my patchset is NOT doing the exact same thing. I had also explained
why helping was not feasible.

The basic point again: I am trying to give a much simpler patchset
to solve the same problem, I take it that you haven't reviewed my
patchset before writing this mail. I would have appreciated
a technical discussion rather than this pointless flamefest.

If you have reviewed it, you can see that there are just 5 patches
instead of 23, and that overall it is a much simpler approach.

> Do you want all of us to go through your code and re-fix what has
> already been fixed in Tomasz's series with the end result of missing
> yet another merge window ?

Again, as I said, the whole point of my patchset is that is much  easier
to go thru and validate and merge or drop as needed.

Anyway, if you are on target to hit this merge window, I really hope
that happens and there will no need for me to spend further time on
this.

Regards,
JC.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-05  9:47         ` Lorenzo Pieralisi
                           ` (3 preceding siblings ...)
  (?)
@ 2016-02-08 11:27         ` Jayachandran Chandrashekaran Nair
  -1 siblings, 0 replies; 45+ messages in thread
From: Jayachandran Chandrashekaran Nair @ 2016-02-08 11:27 UTC (permalink / raw)
  To: Lorenzo Pieralisi
  Cc: Jayachandran C, Arnd Bergmann, linux-pci, Rafael J. Wysocki,
	linux-acpi, Bjorn Helgaas, Tomasz Nowicki, Bjorn Helgaas,
	xen-devel, linux-arm-kernel

Lorenzo,

On Fri, Feb 5, 2016 at 3:17 PM, Lorenzo Pieralisi
<lorenzo.pieralisi@arm.com> wrote:
> On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
>
> [...]
>
>> pci_host_acpi.c is a generic implementation of these using a sysdata
>> pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
>> to access ECAM area, Maybe I can rename this file to
>> pci_acpi_host_generic.c to reflect this better.
>
> Maybe you should stop sending this series and work with Tomasz to
> get this done, you are confusing everyone and I am really really
> annoyed about this.
>
> Do you realize there is no point in having two patch series doing
> the same thing and wasting everyone's review time ?
>
> Do you realize he started this work long before you and went through
> several rounds of review already (I told you before but in case you
> forgot) ?
>
> Tomasz posted a version yesterday, integrating comments following months
> of review and testing and I think it is ready to get upstream:
>
> https://lkml.org/lkml/2016/2/4/646
>
> Did you even consider reviewing his code or helping him instead of
> churning out more patches doing the *SAME* thing ?

This is getting ridiculous, I had replied to your earlier mails on why
my patchset is NOT doing the exact same thing. I had also explained
why helping was not feasible.

The basic point again: I am trying to give a much simpler patchset
to solve the same problem, I take it that you haven't reviewed my
patchset before writing this mail. I would have appreciated
a technical discussion rather than this pointless flamefest.

If you have reviewed it, you can see that there are just 5 patches
instead of 23, and that overall it is a much simpler approach.

> Do you want all of us to go through your code and re-fix what has
> already been fixed in Tomasz's series with the end result of missing
> yet another merge window ?

Again, as I said, the whole point of my patchset is that is much  easier
to go thru and validate and merge or drop as needed.

Anyway, if you are on target to hit this merge window, I really hope
that happens and there will no need for me to spend further time on
this.

Regards,
JC.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-08 11:27           ` Jayachandran Chandrashekaran Nair
@ 2016-02-10 13:30             ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 45+ messages in thread
From: Lorenzo Pieralisi @ 2016-02-10 13:30 UTC (permalink / raw)
  To: Jayachandran Chandrashekaran Nair
  Cc: Bjorn Helgaas, Jayachandran C, linux-pci, Bjorn Helgaas,
	linux-acpi, Arnd Bergmann, linux-arm-kernel, Rafael J. Wysocki,
	Tomasz Nowicki, xen-devel

On Mon, Feb 08, 2016 at 04:57:46PM +0530, Jayachandran Chandrashekaran Nair wrote:
> Lorenzo,
> 
> On Fri, Feb 5, 2016 at 3:17 PM, Lorenzo Pieralisi
> <lorenzo.pieralisi@arm.com> wrote:
> > On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
> >
> > [...]
> >
> >> pci_host_acpi.c is a generic implementation of these using a sysdata
> >> pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
> >> to access ECAM area, Maybe I can rename this file to
> >> pci_acpi_host_generic.c to reflect this better.
> >
> > Maybe you should stop sending this series and work with Tomasz to
> > get this done, you are confusing everyone and I am really really
> > annoyed about this.
> >
> > Do you realize there is no point in having two patch series doing
> > the same thing and wasting everyone's review time ?
> >
> > Do you realize he started this work long before you and went through
> > several rounds of review already (I told you before but in case you
> > forgot) ?
> >
> > Tomasz posted a version yesterday, integrating comments following months
> > of review and testing and I think it is ready to get upstream:
> >
> > https://lkml.org/lkml/2016/2/4/646
> >
> > Did you even consider reviewing his code or helping him instead of
> > churning out more patches doing the *SAME* thing ?
> 
> This is getting ridiculous, I had replied to your earlier mails on why
> my patchset is NOT doing the exact same thing. I had also explained
> why helping was not feasible.
> 
> The basic point again: I am trying to give a much simpler patchset
> to solve the same problem, I take it that you haven't reviewed my
> patchset before writing this mail. I would have appreciated
> a technical discussion rather than this pointless flamefest.
> 
> If you have reviewed it, you can see that there are just 5 patches
> instead of 23, and that overall it is a much simpler approach.

Ok, let's make it constructive. I think there is part of your
implementation that definitely makes sense (in particular the way you
cleaned-up the x86 MCFG unadulterated mess - patch 1), I will ask
Tomasz to integrate it, please work together on this.

I have nothing against your patchset, my point is that we can't keep
reviewing and testing two series (and I mean on ARM64 AND x86), please
understand my point, it is very time consuming to understand the
differences and make sure we don't break x86 in the process and I would
have to ask you to add all the code that I already reviewed in Tomasz's
set, I just do not want to do that.

I will reply to Tomasz, let's work together to have a single final
implementation please, I do not think I am asking too much here and
yes, by integrating part of your code I think Tomasz's patchset is
ready to go, obviously subject to Bjorn's review and opinion.

Thanks,
Lorenzo

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
@ 2016-02-10 13:30             ` Lorenzo Pieralisi
  0 siblings, 0 replies; 45+ messages in thread
From: Lorenzo Pieralisi @ 2016-02-10 13:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 08, 2016 at 04:57:46PM +0530, Jayachandran Chandrashekaran Nair wrote:
> Lorenzo,
> 
> On Fri, Feb 5, 2016 at 3:17 PM, Lorenzo Pieralisi
> <lorenzo.pieralisi@arm.com> wrote:
> > On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
> >
> > [...]
> >
> >> pci_host_acpi.c is a generic implementation of these using a sysdata
> >> pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
> >> to access ECAM area, Maybe I can rename this file to
> >> pci_acpi_host_generic.c to reflect this better.
> >
> > Maybe you should stop sending this series and work with Tomasz to
> > get this done, you are confusing everyone and I am really really
> > annoyed about this.
> >
> > Do you realize there is no point in having two patch series doing
> > the same thing and wasting everyone's review time ?
> >
> > Do you realize he started this work long before you and went through
> > several rounds of review already (I told you before but in case you
> > forgot) ?
> >
> > Tomasz posted a version yesterday, integrating comments following months
> > of review and testing and I think it is ready to get upstream:
> >
> > https://lkml.org/lkml/2016/2/4/646
> >
> > Did you even consider reviewing his code or helping him instead of
> > churning out more patches doing the *SAME* thing ?
> 
> This is getting ridiculous, I had replied to your earlier mails on why
> my patchset is NOT doing the exact same thing. I had also explained
> why helping was not feasible.
> 
> The basic point again: I am trying to give a much simpler patchset
> to solve the same problem, I take it that you haven't reviewed my
> patchset before writing this mail. I would have appreciated
> a technical discussion rather than this pointless flamefest.
> 
> If you have reviewed it, you can see that there are just 5 patches
> instead of 23, and that overall it is a much simpler approach.

Ok, let's make it constructive. I think there is part of your
implementation that definitely makes sense (in particular the way you
cleaned-up the x86 MCFG unadulterated mess - patch 1), I will ask
Tomasz to integrate it, please work together on this.

I have nothing against your patchset, my point is that we can't keep
reviewing and testing two series (and I mean on ARM64 AND x86), please
understand my point, it is very time consuming to understand the
differences and make sure we don't break x86 in the process and I would
have to ask you to add all the code that I already reviewed in Tomasz's
set, I just do not want to do that.

I will reply to Tomasz, let's work together to have a single final
implementation please, I do not think I am asking too much here and
yes, by integrating part of your code I think Tomasz's patchset is
ready to go, obviously subject to Bjorn's review and opinion.

Thanks,
Lorenzo

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
  2016-02-08 11:27           ` Jayachandran Chandrashekaran Nair
  (?)
  (?)
@ 2016-02-10 13:30           ` Lorenzo Pieralisi
  -1 siblings, 0 replies; 45+ messages in thread
From: Lorenzo Pieralisi @ 2016-02-10 13:30 UTC (permalink / raw)
  To: Jayachandran Chandrashekaran Nair
  Cc: Jayachandran C, Arnd Bergmann, linux-pci, Rafael J. Wysocki,
	linux-acpi, Bjorn Helgaas, Tomasz Nowicki, Bjorn Helgaas,
	xen-devel, linux-arm-kernel

On Mon, Feb 08, 2016 at 04:57:46PM +0530, Jayachandran Chandrashekaran Nair wrote:
> Lorenzo,
> 
> On Fri, Feb 5, 2016 at 3:17 PM, Lorenzo Pieralisi
> <lorenzo.pieralisi@arm.com> wrote:
> > On Fri, Feb 05, 2016 at 02:05:37PM +0530, Jayachandran Chandrashekaran Nair wrote:
> >
> > [...]
> >
> >> pci_host_acpi.c is a generic implementation of these using a sysdata
> >> pointing to acpi_pci_root_info, and using a pointer to the pci_mmcfg_region
> >> to access ECAM area, Maybe I can rename this file to
> >> pci_acpi_host_generic.c to reflect this better.
> >
> > Maybe you should stop sending this series and work with Tomasz to
> > get this done, you are confusing everyone and I am really really
> > annoyed about this.
> >
> > Do you realize there is no point in having two patch series doing
> > the same thing and wasting everyone's review time ?
> >
> > Do you realize he started this work long before you and went through
> > several rounds of review already (I told you before but in case you
> > forgot) ?
> >
> > Tomasz posted a version yesterday, integrating comments following months
> > of review and testing and I think it is ready to get upstream:
> >
> > https://lkml.org/lkml/2016/2/4/646
> >
> > Did you even consider reviewing his code or helping him instead of
> > churning out more patches doing the *SAME* thing ?
> 
> This is getting ridiculous, I had replied to your earlier mails on why
> my patchset is NOT doing the exact same thing. I had also explained
> why helping was not feasible.
> 
> The basic point again: I am trying to give a much simpler patchset
> to solve the same problem, I take it that you haven't reviewed my
> patchset before writing this mail. I would have appreciated
> a technical discussion rather than this pointless flamefest.
> 
> If you have reviewed it, you can see that there are just 5 patches
> instead of 23, and that overall it is a much simpler approach.

Ok, let's make it constructive. I think there is part of your
implementation that definitely makes sense (in particular the way you
cleaned-up the x86 MCFG unadulterated mess - patch 1), I will ask
Tomasz to integrate it, please work together on this.

I have nothing against your patchset, my point is that we can't keep
reviewing and testing two series (and I mean on ARM64 AND x86), please
understand my point, it is very time consuming to understand the
differences and make sure we don't break x86 in the process and I would
have to ask you to add all the code that I already reviewed in Tomasz's
set, I just do not want to do that.

I will reply to Tomasz, let's work together to have a single final
implementation please, I do not think I am asking too much here and
yes, by integrating part of your code I think Tomasz's patchset is
ready to go, obviously subject to Bjorn's review and opinion.

Thanks,
Lorenzo

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2016-02-10 13:30 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-29  9:05 [PATCH v7 0/5] ACPI based PCI support for arm64 Jayachandran C
2016-01-29  9:05 ` Jayachandran C
2016-01-29  9:05 ` Jayachandran C
2016-01-29  9:05 ` [PATCH v7 1/5] APCI: MCFG: Move mmcfg_list management to drivers/acpi Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-01-29  9:05 ` Jayachandran C
2016-01-29  9:05 ` [PATCH v7 2/5] ACPI: PCI: Support platforms that need pci_remap_iospace Jayachandran C
2016-01-29  9:05 ` Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-01-29  9:05 ` [PATCH v7 3/5] PCI: Handle ACPI companion and domain number Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-01-29  9:05 ` Jayachandran C
2016-01-29  9:05 ` [PATCH v7 4/5] arm64: pci: Add ACPI support Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-01-29  9:05 ` Jayachandran C
2016-01-29  9:05 ` [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller Jayachandran C
2016-01-29  9:05 ` Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-01-29  9:05   ` Jayachandran C
2016-02-05  0:19   ` Bjorn Helgaas
2016-02-05  0:19   ` Bjorn Helgaas
2016-02-05  0:19     ` Bjorn Helgaas
2016-02-05  8:35     ` Jayachandran Chandrashekaran Nair
2016-02-05  8:35     ` Jayachandran Chandrashekaran Nair
2016-02-05  8:35       ` Jayachandran Chandrashekaran Nair
2016-02-05  8:35       ` Jayachandran Chandrashekaran Nair
2016-02-05  9:47       ` Lorenzo Pieralisi
2016-02-05  9:47       ` Lorenzo Pieralisi
2016-02-05  9:47         ` Lorenzo Pieralisi
2016-02-05 23:26         ` Rafael J. Wysocki
2016-02-05 23:26         ` Rafael J. Wysocki
2016-02-05 23:26           ` Rafael J. Wysocki
2016-02-06  9:58           ` Jayachandran Chandrashekaran Nair
2016-02-06  9:58             ` Jayachandran Chandrashekaran Nair
2016-02-06  9:58           ` Jayachandran Chandrashekaran Nair
2016-02-08 11:27         ` Jayachandran Chandrashekaran Nair
2016-02-08 11:27           ` Jayachandran Chandrashekaran Nair
2016-02-10 13:30           ` Lorenzo Pieralisi
2016-02-10 13:30             ` Lorenzo Pieralisi
2016-02-10 13:30           ` Lorenzo Pieralisi
2016-02-08 11:27         ` Jayachandran Chandrashekaran Nair

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.