Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1256927 > unrolled thread
| Started by | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| First post | 2015-10-27 17:40 +0100 |
| Last post | 2015-10-30 09:30 +0100 |
| Articles | 17 — 5 participants |
Back to article view | Back to linux.kernel
[PATCH V1 00/11] MMCONFIG refactoring and ARM64 PCI hostbridge init based on ACPI Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:40 +0100
[PATCH V1 09/11] x86, pci: Use previously added ECAM hot_added flag to remove ECAM regions. Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:50 +0100
[PATCH V1 06/11] pci, acpi, mcfg: Provide default RAW ACPI PCI config space accessors. Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:50 +0100
[PATCH V1 02/11] x86, pci, acpi: Move arch-agnostic MMCONFIG (aka ECAM) and ACPI code out of arch/x86/ directory Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:50 +0100
[PATCH V1 03/11] pci, acpi, mcfg: Provide generic implementation of MCFG code initialization. Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:50 +0100
[PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:50 +0100
Re: [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init Liviu.Dudau@arm.com - 2015-10-28 12:50 +0100
Re: [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init Tomasz Nowicki <tn@semihalf.com> - 2015-10-28 14:50 +0100
Re: [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init Liviu.Dudau@arm.com - 2015-10-28 15:00 +0100
Re: [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init Sinan Kaya <okaya@codeaurora.org> - 2015-10-28 19:50 +0100
[PATCH V1 05/11] x86, pci, ecam: mmconfig_64.c becomes default implementation for ECAM driver. Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:50 +0100
[PATCH V1 08/11] pci, acpi, ecam: Add flag to indicate whether ECAM region was hot added or not. Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:50 +0100
[PATCH V1 01/11] x86, pci: Reorder logic of pci_mmconfig_insert() function Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:50 +0100
[PATCH V1 04/11] x86, pci: mmconfig_{32,64}.c code refactoring - remove code duplication. Tomasz Nowicki <tn@semihalf.com> - 2015-10-27 17:50 +0100
Re: [PATCH V1 00/11] MMCONFIG refactoring and ARM64 PCI hostbridge init based on ACPI Jon Masters <jcm@redhat.com> - 2015-10-30 05:10 +0100
Re: [PATCH V1 00/11] MMCONFIG refactoring and ARM64 PCI hostbridge init based on ACPI Hanjun Guo <guohanjun@huawei.com> - 2015-10-30 06:00 +0100
Re: [PATCH V1 00/11] MMCONFIG refactoring and ARM64 PCI hostbridge init based on ACPI Tomasz Nowicki <tn@semihalf.com> - 2015-10-30 09:30 +0100
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:40 +0100 |
| Subject | [PATCH V1 00/11] MMCONFIG refactoring and ARM64 PCI hostbridge init based on ACPI |
| Message-ID | <qofrY-7ty-5@gated-at.bofh.it> |
From the functionality point of view this series might be split into two logic parts:
1. Making MMCONFIG code arch-agnostic which allows all architectures to collect
PCI config regions and used when necessary.
2. Using generic MMCONFIG code and introducing ACPI based PCI hostbridge
initialization for ARM64
Patches has been built on top of:
[Patch v7 0/7] Consolidate ACPI PCI root common code into ACPI core
https://lkml.org/lkml/2015/10/14/31
Git branch can be found here:
https://git.linaro.org/leg/acpi/acpi.git/shortlog/refs/heads/pci-acpi-upstream
This has been tested on Cavium ThunderX 1 socket server.
Any help in reviewing and testing is very appreciated.
Hanjun Guo (1):
XEN / PCI: Remove the dependence on arch x86 when PCI_MMCONFIG=y
Tomasz Nowicki (10):
x86, pci: Reorder logic of pci_mmconfig_insert() function
x86, pci, acpi: Move arch-agnostic MMCONFIG (aka ECAM) and ACPI code
out of arch/x86/ directory
pci, acpi, mcfg: Provide generic implementation of MCFG code
initialization.
x86, pci: mmconfig_{32,64}.c code refactoring - remove code
duplication.
x86, pci, ecam: mmconfig_64.c becomes default implementation for ECAM
driver.
pci, acpi, mcfg: Provide default RAW ACPI PCI config space accessors.
pci, acpi, ecam: Add flag to indicate whether ECAM region was hot
added or not.
x86, pci: Use previously added ECAM hot_added flag to remove ECAM
regions.
pci, acpi: Provide generic way to assign bus domain number.
arm64, pci, acpi: Support for ACPI based PCI hostbridge init
arch/arm64/Kconfig | 6 +
arch/arm64/kernel/pci.c | 208 ++++++++++++++++++++++++++++++++--
arch/x86/Kconfig | 4 +
arch/x86/include/asm/pci_x86.h | 28 +----
arch/x86/pci/acpi.c | 17 +--
arch/x86/pci/mmconfig-shared.c | 250 +++++++----------------------------------
arch/x86/pci/mmconfig_32.c | 11 +-
arch/x86/pci/mmconfig_64.c | 67 +----------
arch/x86/pci/numachip.c | 1 +
drivers/acpi/Makefile | 1 +
drivers/acpi/mcfg.c | 104 +++++++++++++++++
drivers/acpi/pci_root.c | 2 +-
drivers/pci/Kconfig | 10 ++
drivers/pci/Makefile | 5 +
drivers/pci/ecam.c | 234 ++++++++++++++++++++++++++++++++++++++
drivers/pci/pci.c | 30 ++++-
drivers/xen/pci.c | 7 +-
include/linux/acpi.h | 2 +
include/linux/ecam.h | 44 ++++++++
19 files changed, 691 insertions(+), 340 deletions(-)
create mode 100644 drivers/acpi/mcfg.c
create mode 100644 drivers/pci/ecam.c
create mode 100644 include/linux/ecam.h
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:50 +0100 |
| Subject | [PATCH V1 09/11] x86, pci: Use previously added ECAM hot_added flag to remove ECAM regions. |
| Message-ID | <qofBE-7xc-3@gated-at.bofh.it> |
| In reply to | #1256927 |
Now that we have hot_added flag we can get rid of arch specific mcfg_added.
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
---
arch/x86/pci/acpi.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 28c9cd6..b4ef761 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -13,7 +13,6 @@ struct pci_root_info {
struct acpi_pci_root_info common;
struct pci_sysdata sd;
#ifdef CONFIG_PCI_MMCONFIG
- bool mcfg_added;
u8 start_bus;
u8 end_bus;
#endif
@@ -188,7 +187,6 @@ static int setup_mcfg_map(struct acpi_pci_root_info *ci)
info = container_of(ci, struct pci_root_info, common);
info->start_bus = (u8)root->secondary.start;
info->end_bus = (u8)root->secondary.end;
- info->mcfg_added = false;
seg = info->sd.domain;
/* return success if MMCFG is not in use */
@@ -204,7 +202,6 @@ static int setup_mcfg_map(struct acpi_pci_root_info *ci)
/* enable MMCFG if it hasn't been enabled yet */
if (raw_pci_ext_ops == NULL)
raw_pci_ext_ops = &pci_mmcfg;
- info->mcfg_added = true;
} else if (result != -EEXIST)
return check_segment(seg, dev,
"fail to add MMCONFIG information,");
@@ -214,14 +211,17 @@ static int setup_mcfg_map(struct acpi_pci_root_info *ci)
static void teardown_mcfg_map(struct acpi_pci_root_info *ci)
{
+ struct pci_mmcfg_region *cfg;
struct pci_root_info *info;
info = container_of(ci, struct pci_root_info, common);
- if (info->mcfg_added) {
- pci_mmconfig_delete(info->sd.domain,
- info->start_bus, info->end_bus);
- info->mcfg_added = false;
- }
+ cfg = pci_mmconfig_lookup(info->sd.domain, info->start_bus);
+ if (!cfg)
+ return;
+
+ if (cfg->hot_added)
+ pci_mmconfig_delete(info->sd.domain, info->start_bus,
+ info->end_bus);
}
#else
static int setup_mcfg_map(struct acpi_pci_root_info *ci)
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:50 +0100 |
| Subject | [PATCH V1 06/11] pci, acpi, mcfg: Provide default RAW ACPI PCI config space accessors. |
| Message-ID | <qofBE-7xc-11@gated-at.bofh.it> |
| In reply to | #1256927 |
Lets keep RAW ACPI PCI config space accessors empty by default,
since we are note sure if they are necessary accross all archs.
Once we sort this out, we can provide generic version or let
architectures to overwrite, like now x86.
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
---
drivers/acpi/mcfg.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/acpi/mcfg.c b/drivers/acpi/mcfg.c
index 745b83e..3e1e7be 100644
--- a/drivers/acpi/mcfg.c
+++ b/drivers/acpi/mcfg.c
@@ -9,9 +9,30 @@
#include <linux/acpi.h>
#include <linux/ecam.h>
+#include <linux/pci.h>
#define PREFIX "MCFG: "
+/*
+ * raw_pci_read/write - raw ACPI PCI config space accessors.
+ *
+ * By defauly (__weak) these accessors are empty and should be overwritten
+ * by architectures which support operations on ACPI PCI_Config regions,
+ * see osl.c file.
+ */
+
+int __weak raw_pci_read(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 *val)
+{
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int __weak raw_pci_write(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 val)
+{
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
int __init acpi_parse_mcfg(struct acpi_table_header *header)
{
struct acpi_table_mcfg *mcfg;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:50 +0100 |
| Subject | [PATCH V1 02/11] x86, pci, acpi: Move arch-agnostic MMCONFIG (aka ECAM) and ACPI code out of arch/x86/ directory |
| Message-ID | <qofBE-7xc-19@gated-at.bofh.it> |
| In reply to | #1256927 |
ECAM standard and MCFG table are architecture independent and it makes
sense to share common code across all architectures. Both are going to
corresponding files - ecam.c and mcfg.c
While we are here, rename pci_parse_mcfg to acpi_parse_mcfg.
We already have acpi_parse_mcfg prototype which is used nowhere.
At the same time, we need pci_parse_mcfg been global so acpi_parse_mcfg
can be used perfectly here.
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
---
arch/x86/Kconfig | 3 +
arch/x86/include/asm/pci_x86.h | 21 -----
arch/x86/pci/acpi.c | 1 +
arch/x86/pci/mmconfig-shared.c | 205 +----------------------------------------
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/mcfg.c | 59 ++++++++++++
drivers/pci/Kconfig | 7 ++
drivers/pci/Makefile | 5 +
drivers/pci/ecam.c | 175 +++++++++++++++++++++++++++++++++++
drivers/xen/pci.c | 1 +
include/linux/acpi.h | 2 +
include/linux/ecam.h | 37 ++++++++
15 files changed, 299 insertions(+), 221 deletions(-)
create mode 100644 drivers/acpi/mcfg.c
create mode 100644 drivers/pci/ecam.c
create mode 100644 include/linux/ecam.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 96d058a..4ca8134 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -128,6 +128,7 @@ config X86
select HAVE_MIXED_BREAKPOINTS_REGS
select HAVE_OPROFILE
select HAVE_OPTPROBES
+ select HAVE_PCI_ECAM
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
select HAVE_PERF_EVENTS_NMI
@@ -2332,6 +2333,7 @@ config PCI_DIRECT
config PCI_MMCONFIG
def_bool y
+ select PCI_ECAM
depends on X86_32 && PCI && (ACPI || SFI) && (PCI_GOMMCONFIG || PCI_GOANY)
config PCI_OLPC
@@ -2349,6 +2351,7 @@ config PCI_DOMAINS
config PCI_MMCONFIG
bool "Support mmconfig PCI config space access"
+ select PCI_ECAM
depends on X86_64 && PCI && ACPI
config PCI_CNB20LE_QUIRK
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index fa1195d..64cb514 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -122,33 +122,12 @@ 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];
-};
-
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)
/*
* AMD Fam10h CPUs are buggy, and cannot access MMIO config space
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 3cd6983..28c9cd6 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -5,6 +5,7 @@
#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/pci-acpi.h>
+#include <linux/ecam.h>
#include <asm/numa.h>
#include <asm/pci_x86.h>
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index c8bb9b0..ce2c2e4 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/rculist.h>
+#include <linux/ecam.h>
#include <asm/e820.h>
#include <asm/pci_x86.h>
#include <asm/acpi.h>
@@ -27,103 +28,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)
-{
- if (cfg->res.parent)
- release_resource(&cfg->res);
- list_del(&cfg->list);
- kfree(cfg);
-}
-
-static void __init free_all_mmcfg(void)
-{
- struct pci_mmcfg_region *cfg, *tmp;
-
- pci_mmcfg_arch_free();
- list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list)
- 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)
{
@@ -543,8 +447,8 @@ 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 __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+ struct acpi_mcfg_allocation *cfg)
{
int year;
@@ -566,50 +470,6 @@ static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
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);
@@ -668,7 +528,7 @@ void __init pci_mmcfg_early_init(void)
if (pci_mmcfg_check_hostbridge())
known_bridge = 1;
else
- acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
+ acpi_sfi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
__pci_mmcfg_init(1);
set_apei_filter();
@@ -686,7 +546,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);
+ acpi_sfi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
__pci_mmcfg_init(0);
}
}
@@ -720,38 +580,6 @@ static int __init pci_mmcfg_late_insert_resources(void)
*/
late_initcall(pci_mmcfg_late_insert_resources);
-static int pci_mmconfig_inject(struct pci_mmcfg_region *cfg)
-{
- struct pci_mmcfg_region *cfg_conflict;
- int err = 0;
-
- mutex_lock(&pci_mmcfg_lock);
- cfg_conflict = pci_mmconfig_lookup(cfg->segment, cfg->start_bus);
- if (cfg_conflict) {
- if (cfg_conflict->end_bus < cfg->end_bus)
- pr_info(FW_INFO "MMCONFIG for "
- "domain %04x [bus %02x-%02x] "
- "only partially covers this bridge\n",
- cfg_conflict->segment, cfg_conflict->start_bus,
- cfg_conflict->end_bus);
- err = -EEXIST;
- goto out;
- }
-
- if (pci_mmcfg_arch_map(cfg)) {
- pr_warn("fail to map MMCONFIG %pR.\n", &cfg->res);
- err = -ENOMEM;
- goto out;
- } else {
- list_add_sorted(cfg);
- pr_info("MMCONFIG at %pR (base %#lx)\n",
- &cfg->res, (unsigned long)cfg->address);
- }
-out:
- mutex_unlock(&pci_mmcfg_lock);
- return err;
-}
-
/* Add MMCFG information for host bridges */
int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
phys_addr_t addr)
@@ -808,26 +636,3 @@ error:
kfree(cfg);
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_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);
-
- return -ENOENT;
-}
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 43984bc..246f135 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/ecam.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..b14fcd3 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/ecam.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..55fbd18 100644
--- a/arch/x86/pci/numachip.c
+++ b/arch/x86/pci/numachip.c
@@ -13,6 +13,7 @@
*
*/
+#include <linux/ecam.h>
#include <linux/pci.h>
#include <asm/pci_x86.h>
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 962f98e..607a879 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
+obj-$(CONFIG_PCI_MMCONFIG) += mcfg.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
obj-y += container.o
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
diff --git a/drivers/acpi/mcfg.c b/drivers/acpi/mcfg.c
new file mode 100644
index 0000000..5ecef20
--- /dev/null
+++ b/drivers/acpi/mcfg.c
@@ -0,0 +1,59 @@
+/*
+ * MCFG ACPI table parser.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/ecam.h>
+
+#include <asm/pci_x86.h> /* Temp hack before refactoring arch-specific calls */
+
+#define PREFIX "MCFG: "
+
+int __init acpi_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 "MCFG table 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;
+}
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 73de4ef..9950248 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -26,6 +26,13 @@ config PCI_MSI_IRQ_DOMAIN
depends on PCI_MSI
select GENERIC_MSI_IRQ_DOMAIN
+config PCI_ECAM
+ bool "Enhanced Configuration Access Mechanism (ECAM)"
+ depends on PCI && HAVE_PCI_ECAM
+
+config HAVE_PCI_ECAM
+ bool
+
config PCI_DEBUG
bool "PCI Debugging"
depends on PCI && DEBUG_KERNEL
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index be3f631..eb574f8 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -42,6 +42,11 @@ obj-$(CONFIG_SPARC_LEON) += setup-irq.o
obj-$(CONFIG_M68K) += setup-irq.o
#
+# Enhanced Configuration Access Mechanism (ECAM)
+#
+obj-$(CONFIG_PCI_ECAM) += ecam.o
+
+#
# ACPI Related PCI FW Functions
# ACPI _DSM provided firmware instance and string name
#
diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c
new file mode 100644
index 0000000..d221dba
--- /dev/null
+++ b/drivers/pci/ecam.c
@@ -0,0 +1,175 @@
+/*
+ * Arch agnostic direct PCI config space access via
+ * ECAM (Enhanced Configuration Access Mechanism)
+ *
+ * Per-architecture code takes care of the mappings, region validation and
+ * accesses themselves.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/mutex.h>
+#include <linux/rculist.h>
+#include <linux/ecam.h>
+
+#include <asm/io.h>
+#include <asm/pci_x86.h> /* Temp hack before refactoring arch-specific calls */
+
+#define PREFIX "PCI: "
+
+static DEFINE_MUTEX(pci_mmcfg_lock);
+
+LIST_HEAD(pci_mmcfg_list);
+
+static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
+{
+ if (cfg->res.parent)
+ release_resource(&cfg->res);
+ list_del(&cfg->list);
+ kfree(cfg);
+}
+
+void __init free_all_mmcfg(void)
+{
+ struct pci_mmcfg_region *cfg, *tmp;
+
+ pci_mmcfg_arch_free();
+ list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list)
+ pci_mmconfig_remove(cfg);
+}
+
+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);
+}
+
+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;
+}
+
+/* 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_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);
+
+ return -ENOENT;
+}
+
+int pci_mmconfig_inject(struct pci_mmcfg_region *cfg)
+{
+ struct pci_mmcfg_region *cfg_conflict;
+ int err = 0;
+
+ mutex_lock(&pci_mmcfg_lock);
+ cfg_conflict = pci_mmconfig_lookup(cfg->segment, cfg->start_bus);
+ if (cfg_conflict) {
+ if (cfg_conflict->end_bus < cfg->end_bus)
+ pr_info(FW_INFO "MMCONFIG for "
+ "domain %04x [bus %02x-%02x] "
+ "only partially covers this bridge\n",
+ cfg_conflict->segment, cfg_conflict->start_bus,
+ cfg_conflict->end_bus);
+ err = -EEXIST;
+ goto out;
+ }
+
+ if (pci_mmcfg_arch_map(cfg)) {
+ pr_warn("fail to map MMCONFIG %pR.\n", &cfg->res);
+ err = -ENOMEM;
+ goto out;
+ } else {
+ list_add_sorted(cfg);
+ pr_info("MMCONFIG at %pR (base %#lx)\n",
+ &cfg->res, (unsigned long)cfg->address);
+
+ }
+out:
+ mutex_unlock(&pci_mmcfg_lock);
+ return err;
+}
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
index 7494dbe..6785ebb 100644
--- a/drivers/xen/pci.c
+++ b/drivers/xen/pci.c
@@ -20,6 +20,7 @@
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/pci-acpi.h>
+#include <linux/ecam.h>
#include <xen/xen.h>
#include <xen/interface/physdev.h>
#include <xen/interface/xen.h>
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 127d68b..98f2ce4 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -162,6 +162,8 @@ int acpi_table_parse_madt(enum acpi_madt_type id,
acpi_tbl_entry_handler handler,
unsigned int max_entries);
int acpi_parse_mcfg (struct acpi_table_header *header);
+int acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+ struct acpi_mcfg_allocation *cfg);
void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
/* the following four functions are architecture-dependent */
diff --git a/include/linux/ecam.h b/include/linux/ecam.h
new file mode 100644
index 0000000..dec3b52
--- /dev/null
+++ b/include/linux/ecam.h
@@ -0,0 +1,37 @@
+#ifndef __ECAM_H
+#define __ECAM_H
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/acpi.h>
+
+/* "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 *pci_mmconfig_lookup(int segment, int bus);
+struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
+ int end, u64 addr);
+int pci_mmconfig_inject(struct pci_mmcfg_region *cfg);
+struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
+ int end, u64 addr);
+void list_add_sorted(struct pci_mmcfg_region *new);
+void free_all_mmcfg(void);
+int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
+
+extern struct list_head pci_mmcfg_list;
+
+#define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20)
+
+#endif /* __KERNEL__ */
+#endif /* __ECAM_H */
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:50 +0100 |
| Subject | [PATCH V1 03/11] pci, acpi, mcfg: Provide generic implementation of MCFG code initialization. |
| Message-ID | <qofBF-7xc-27@gated-at.bofh.it> |
| In reply to | #1256927 |
First function acpi_mcfg_check_entry() does not apply any quirks by default.
Last two functions are required by ACPI subsystem to make PCI config
space accessible. Generic code assume to do nothing for early init call but
late init call does as follow:
- parse MCFG table and add regions to ECAM resource list
- map regions
- add regions to iomem_resource
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
---
drivers/acpi/mcfg.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/acpi/mcfg.c b/drivers/acpi/mcfg.c
index 5ecef20..fad9917 100644
--- a/drivers/acpi/mcfg.c
+++ b/drivers/acpi/mcfg.c
@@ -57,3 +57,29 @@ int __init acpi_parse_mcfg(struct acpi_table_header *header)
return 0;
}
+
+int __init __weak acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
+ struct acpi_mcfg_allocation *cfg)
+{
+ return 0;
+}
+
+void __init __weak pci_mmcfg_early_init(void)
+{
+
+}
+
+void __init __weak pci_mmcfg_late_init(void)
+{
+ struct pci_mmcfg_region *cfg;
+
+ acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
+
+ if (list_empty(&pci_mmcfg_list))
+ return;
+ if (!pci_mmcfg_arch_init())
+ free_all_mmcfg();
+
+ list_for_each_entry(cfg, &pci_mmcfg_list, list)
+ insert_resource(&iomem_resource, &cfg->res);
+}
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:50 +0100 |
| Subject | [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init |
| Message-ID | <qofBE-7xc-23@gated-at.bofh.it> |
| In reply to | #1256927 |
Because of two patch series:
1. Jiang Liu's common interface to support PCI host bridge init
2. Refactoring of MMCONFIG, part of this patch set
now we can think about PCI buses enumeration for ARM64 and ACPI tables.
This patch introduce ACPI based PCI hostbridge init calls which
use information from MCFG table (PCI config space regions) and
_CRS (IO/irq resources) to initialize PCI hostbridge.
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Catalin Marinas <catalin.marinas@arm.com>
CC: Liviu Dudau <Liviu.Dudau@arm.com>
CC: Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com>
CC: Will Deacon <will.deacon@arm.com>
---
arch/arm64/Kconfig | 6 ++
arch/arm64/kernel/pci.c | 208 +++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 202 insertions(+), 12 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 07d1811..bbcc6b1 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -89,6 +89,7 @@ config ARM64
select SPARSE_IRQ
select SYSCTL_EXCEPTION_TRACE
select HAVE_CONTEXT_TRACKING
+ select HAVE_PCI_ECAM
help
ARM 64-bit (AArch64) Linux support.
@@ -202,6 +203,11 @@ source "drivers/pci/Kconfig"
source "drivers/pci/pcie/Kconfig"
source "drivers/pci/hotplug/Kconfig"
+config PCI_MMCONFIG
+ def_bool y
+ select PCI_ECAM
+ depends on ACPI
+
endmenu
menu "Kernel Features"
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index b3d098b..66cc1ae 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -11,12 +11,15 @@
*/
#include <linux/acpi.h>
+#include <linux/ecam.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/of_address.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>
@@ -52,35 +55,216 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
}
/*
- * Try to assign the IRQ number from DT when adding a new device
+ * Try to assign the IRQ number from DT/ACPI when adding a new device
*/
int pcibios_add_device(struct pci_dev *dev)
{
- dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+ if (acpi_disabled)
+ dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
+#ifdef CONFIG_ACPI
+ else
+ acpi_pci_irq_enable(dev);
+#endif
return 0;
}
+#ifdef CONFIG_ACPI
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ struct acpi_pci_root *root = bridge->bus->sysdata;
+
+ ACPI_COMPANION_SET(&bridge->dev, root->device);
+ return 0;
+}
+
+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);
+}
+
+static int __init pcibios_assign_resources(void)
+{
+ if (acpi_disabled)
+ return 0;
+
+ pci_assign_unassigned_resources();
+ return 0;
+}
/*
- * raw_pci_read/write - Platform-specific PCI config space access.
+ * rootfs_initcall comes after subsys_initcall and fs_initcall_sync,
+ * so we know acpi scan and PCI_FIXUP_FINAL quirks have both run.
*/
-int raw_pci_read(unsigned int domain, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 *val)
+rootfs_initcall(pcibios_assign_resources);
+
+static void __iomem *
+pci_mcfg_dev_base(struct pci_bus *bus, unsigned int devfn, int offset)
{
- return -ENXIO;
+ struct pci_mmcfg_region *cfg;
+
+ cfg = pci_mmconfig_lookup(pci_domain_nr(bus), bus->number);
+ if (cfg && cfg->virt)
+ return cfg->virt +
+ (PCI_MMCFG_BUS_OFFSET(bus->number) | (devfn << 12)) +
+ offset;
+ return NULL;
}
-int raw_pci_write(unsigned int domain, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 val)
+struct pci_ops pci_root_ops = {
+ .map_bus = pci_mcfg_dev_base,
+ .read = pci_generic_config_read,
+ .write = pci_generic_config_write,
+};
+
+#ifdef CONFIG_PCI_MMCONFIG
+static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
{
- return -ENXIO;
+ struct pci_mmcfg_region *cfg;
+ struct acpi_pci_root *root;
+ int seg, start, end, err;
+
+ root = ci->root;
+ seg = root->segment;
+ start = root->secondary.start;
+ end = root->secondary.end;
+
+ cfg = pci_mmconfig_lookup(seg, start);
+ if (cfg)
+ return 0;
+
+ cfg = pci_mmconfig_alloc(seg, start, end, root->mcfg_addr);
+ if (!cfg)
+ return -ENOMEM;
+
+ err = pci_mmconfig_inject(cfg);
+ return err;
}
-#ifdef CONFIG_ACPI
+static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci)
+{
+ struct acpi_pci_root *root = ci->root;
+ struct pci_mmcfg_region *cfg;
+
+ cfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
+ if (cfg)
+ return;
+
+ if (cfg->hot_added)
+ pci_mmconfig_delete(root->segment, root->secondary.start,
+ root->secondary.end);
+}
+#else
+static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
+{
+ return 0;
+}
+
+static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci) { }
+#endif
+
+static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
+{
+ return pci_add_mmconfig_region(ci);
+}
+
+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
+{
+ pci_remove_mmconfig_region(ci);
+ kfree(ci);
+}
+
+static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
+{
+ struct resource_entry *entry, *tmp;
+ int ret;
+
+ ret = acpi_pci_probe_root_resources(ci);
+ if (ret < 0)
+ return ret;
+
+ resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
+ struct resource *res = entry->res;
+
+ /*
+ * Special handling for ARM IO range
+ * TODO: need to move pci_register_io_range() function out
+ * of drivers/of/address.c for both used by DT and ACPI
+ */
+ if (res->flags & IORESOURCE_IO) {
+ unsigned long port;
+ int err;
+ resource_size_t length = res->end - res->start;
+
+ err = pci_register_io_range(res->start, length);
+ if (err) {
+ resource_list_destroy_entry(entry);
+ continue;
+ }
+
+ port = pci_address_to_pio(res->start);
+ if (port == (unsigned long)-1) {
+ resource_list_destroy_entry(entry);
+ continue;
+ }
+
+ res->start = port;
+ res->end = res->start + length - 1;
+
+ if (pci_remap_iospace(res, res->start) < 0)
+ resource_list_destroy_entry(entry);
+ }
+ }
+
+ return 0;
+}
+
+static struct acpi_pci_root_ops acpi_pci_root_ops = {
+ .pci_ops = &pci_root_ops,
+ .init_info = pci_acpi_root_init_info,
+ .release_info = pci_acpi_root_release_info,
+ .prepare_resources = pci_acpi_root_prepare_resources,
+};
+
/* Root bridge scanning */
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
- /* TODO: Should be revisited when implementing PCI on ACPI */
- return NULL;
+ int node = acpi_get_node(root->device->handle);
+ int domain = root->segment;
+ int busnum = root->secondary.start;
+ struct acpi_pci_root_info *info;
+ struct pci_bus *bus;
+
+ if (domain && !pci_domains_supported) {
+ pr_warn("PCI %04x:%02x: multiple domains not supported.\n",
+ domain, busnum);
+ return NULL;
+ }
+
+ info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
+ if (!info) {
+ dev_err(&root->device->dev,
+ "pci_bus %04x:%02x: ignored (out of memory)\n",
+ domain, busnum);
+ return NULL;
+ }
+
+ bus = acpi_pci_root_create(root, &acpi_pci_root_ops, info, root);
+
+ /* After the PCI-E bus has been walked and all devices discovered,
+ * configure any settings of the fabric that might be necessary.
+ */
+ if (bus) {
+ struct pci_bus *child;
+
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
+ }
+
+ return bus;
}
#endif
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Liviu.Dudau@arm.com |
|---|---|
| Date | 2015-10-28 12:50 +0100 |
| Subject | Re: [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init |
| Message-ID | <qoxoS-255-19@gated-at.bofh.it> |
| In reply to | #1256937 |
On Tue, Oct 27, 2015 at 05:38:42PM +0100, Tomasz Nowicki wrote:
> Because of two patch series:
> 1. Jiang Liu's common interface to support PCI host bridge init
> 2. Refactoring of MMCONFIG, part of this patch set
> now we can think about PCI buses enumeration for ARM64 and ACPI tables.
>
> This patch introduce ACPI based PCI hostbridge init calls which
> use information from MCFG table (PCI config space regions) and
> _CRS (IO/irq resources) to initialize PCI hostbridge.
>
> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Catalin Marinas <catalin.marinas@arm.com>
> CC: Liviu Dudau <Liviu.Dudau@arm.com>
> CC: Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com>
> CC: Will Deacon <will.deacon@arm.com>
> ---
> arch/arm64/Kconfig | 6 ++
> arch/arm64/kernel/pci.c | 208 +++++++++++++++++++++++++++++++++++++++++++++---
> 2 files changed, 202 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 07d1811..bbcc6b1 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -89,6 +89,7 @@ config ARM64
> select SPARSE_IRQ
> select SYSCTL_EXCEPTION_TRACE
> select HAVE_CONTEXT_TRACKING
> + select HAVE_PCI_ECAM
> help
> ARM 64-bit (AArch64) Linux support.
>
> @@ -202,6 +203,11 @@ source "drivers/pci/Kconfig"
> source "drivers/pci/pcie/Kconfig"
> source "drivers/pci/hotplug/Kconfig"
>
> +config PCI_MMCONFIG
> + def_bool y
> + select PCI_ECAM
> + depends on ACPI
> +
> endmenu
>
> menu "Kernel Features"
> diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
> index b3d098b..66cc1ae 100644
> --- a/arch/arm64/kernel/pci.c
> +++ b/arch/arm64/kernel/pci.c
> @@ -11,12 +11,15 @@
> */
>
> #include <linux/acpi.h>
> +#include <linux/ecam.h>
> #include <linux/init.h>
> #include <linux/io.h>
> #include <linux/kernel.h>
> #include <linux/mm.h>
> +#include <linux/of_address.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>
> @@ -52,35 +55,216 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
> }
>
> /*
> - * Try to assign the IRQ number from DT when adding a new device
> + * Try to assign the IRQ number from DT/ACPI when adding a new device
> */
> int pcibios_add_device(struct pci_dev *dev)
> {
> - dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
> + if (acpi_disabled)
> + dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
> +#ifdef CONFIG_ACPI
> + else
> + acpi_pci_irq_enable(dev);
> +#endif
>
> return 0;
> }
>
> +#ifdef CONFIG_ACPI
> +int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
> +{
> + struct acpi_pci_root *root = bridge->bus->sysdata;
> +
> + ACPI_COMPANION_SET(&bridge->dev, root->device);
> + return 0;
> +}
> +
> +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);
> +}
> +
> +static int __init pcibios_assign_resources(void)
> +{
> + if (acpi_disabled)
> + return 0;
> +
> + pci_assign_unassigned_resources();
> + return 0;
You can change this function into:
{
if (!acpi_disabled)
pci_assign_unassigned_resources();
return 0;
}
as the equivalent but shorter form.
> +}
> /*
> - * raw_pci_read/write - Platform-specific PCI config space access.
> + * rootfs_initcall comes after subsys_initcall and fs_initcall_sync,
> + * so we know acpi scan and PCI_FIXUP_FINAL quirks have both run.
> */
> -int raw_pci_read(unsigned int domain, unsigned int bus,
> - unsigned int devfn, int reg, int len, u32 *val)
What happened with raw_pci_{read,write} ? Why do you remove them?
> +rootfs_initcall(pcibios_assign_resources);
Would you be so kind and explain to me why you need this initcall?
Can you not set the PCI_REASSIGN_ALL_RSRC flag before calling
pci_scan_root_bus() ?
I haven't focused on ACPI before so I'm a bit hazy on the init order when
that is enabled. That being said, I don't like adding in the architecture
code initcall hooks just to fix up some dependency orders that could / should
be fixed some other way.
> +
> +static void __iomem *
> +pci_mcfg_dev_base(struct pci_bus *bus, unsigned int devfn, int offset)
> {
> - return -ENXIO;
> + struct pci_mmcfg_region *cfg;
> +
> + cfg = pci_mmconfig_lookup(pci_domain_nr(bus), bus->number);
> + if (cfg && cfg->virt)
> + return cfg->virt +
> + (PCI_MMCFG_BUS_OFFSET(bus->number) | (devfn << 12)) +
> + offset;
> + return NULL;
> }
>
> -int raw_pci_write(unsigned int domain, unsigned int bus,
> - unsigned int devfn, int reg, int len, u32 val)
> +struct pci_ops pci_root_ops = {
> + .map_bus = pci_mcfg_dev_base,
> + .read = pci_generic_config_read,
> + .write = pci_generic_config_write,
> +};
> +
> +#ifdef CONFIG_PCI_MMCONFIG
> +static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
> {
> - return -ENXIO;
> + struct pci_mmcfg_region *cfg;
> + struct acpi_pci_root *root;
> + int seg, start, end, err;
> +
> + root = ci->root;
> + seg = root->segment;
> + start = root->secondary.start;
> + end = root->secondary.end;
> +
> + cfg = pci_mmconfig_lookup(seg, start);
> + if (cfg)
> + return 0;
> +
> + cfg = pci_mmconfig_alloc(seg, start, end, root->mcfg_addr);
> + if (!cfg)
> + return -ENOMEM;
> +
> + err = pci_mmconfig_inject(cfg);
> + return err;
> }
>
> -#ifdef CONFIG_ACPI
> +static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci)
> +{
> + struct acpi_pci_root *root = ci->root;
> + struct pci_mmcfg_region *cfg;
> +
> + cfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
> + if (cfg)
> + return;
> +
> + if (cfg->hot_added)
> + pci_mmconfig_delete(root->segment, root->secondary.start,
> + root->secondary.end);
> +}
> +#else
> +static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
> +{
> + return 0;
> +}
> +
> +static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci) { }
> +#endif
> +
> +static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
> +{
> + return pci_add_mmconfig_region(ci);
> +}
> +
> +static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
> +{
> + pci_remove_mmconfig_region(ci);
> + kfree(ci);
> +}
> +
> +static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
> +{
> + struct resource_entry *entry, *tmp;
> + int ret;
> +
> + ret = acpi_pci_probe_root_resources(ci);
> + if (ret < 0)
> + return ret;
> +
> + resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
> + struct resource *res = entry->res;
> +
> + /*
> + * Special handling for ARM IO range
There is nothing ARM specific here. It should apply to any memory mapped IO range.
> + * TODO: need to move pci_register_io_range() function out
> + * of drivers/of/address.c for both used by DT and ACPI
> + */
> + if (res->flags & IORESOURCE_IO) {
> + unsigned long port;
> + int err;
> + resource_size_t length = res->end - res->start;
> +
> + err = pci_register_io_range(res->start, length);
> + if (err) {
> + resource_list_destroy_entry(entry);
> + continue;
> + }
> +
> + port = pci_address_to_pio(res->start);
> + if (port == (unsigned long)-1) {
> + resource_list_destroy_entry(entry);
> + continue;
> + }
> +
> + res->start = port;
> + res->end = res->start + length - 1;
> +
> + if (pci_remap_iospace(res, res->start) < 0)
> + resource_list_destroy_entry(entry);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static struct acpi_pci_root_ops acpi_pci_root_ops = {
> + .pci_ops = &pci_root_ops,
> + .init_info = pci_acpi_root_init_info,
> + .release_info = pci_acpi_root_release_info,
> + .prepare_resources = pci_acpi_root_prepare_resources,
> +};
> +
> /* Root bridge scanning */
> struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
> {
> - /* TODO: Should be revisited when implementing PCI on ACPI */
> - return NULL;
> + int node = acpi_get_node(root->device->handle);
> + int domain = root->segment;
> + int busnum = root->secondary.start;
> + struct acpi_pci_root_info *info;
> + struct pci_bus *bus;
> +
> + if (domain && !pci_domains_supported) {
> + pr_warn("PCI %04x:%02x: multiple domains not supported.\n",
> + domain, busnum);
> + return NULL;
> + }
> +
> + info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
> + if (!info) {
> + dev_err(&root->device->dev,
> + "pci_bus %04x:%02x: ignored (out of memory)\n",
> + domain, busnum);
> + return NULL;
> + }
> +
> + bus = acpi_pci_root_create(root, &acpi_pci_root_ops, info, root);
> +
> + /* After the PCI-E bus has been walked and all devices discovered,
> + * configure any settings of the fabric that might be necessary.
> + */
> + if (bus) {
> + struct pci_bus *child;
> +
> + list_for_each_entry(child, &bus->children, node)
> + pcie_bus_configure_settings(child);
> + }
> +
> + return bus;
> }
> #endif
> --
> 1.9.1
>
--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-28 14:50 +0100 |
| Subject | Re: [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init |
| Message-ID | <qozgZ-3gf-5@gated-at.bofh.it> |
| In reply to | #1257938 |
On 28.10.2015 12:49, Liviu.Dudau@arm.com wrote:
> On Tue, Oct 27, 2015 at 05:38:42PM +0100, Tomasz Nowicki wrote:
>> Because of two patch series:
>> 1. Jiang Liu's common interface to support PCI host bridge init
>> 2. Refactoring of MMCONFIG, part of this patch set
>> now we can think about PCI buses enumeration for ARM64 and ACPI tables.
>>
>> This patch introduce ACPI based PCI hostbridge init calls which
>> use information from MCFG table (PCI config space regions) and
>> _CRS (IO/irq resources) to initialize PCI hostbridge.
>>
>> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
>> CC: Arnd Bergmann <arnd@arndb.de>
>> CC: Catalin Marinas <catalin.marinas@arm.com>
>> CC: Liviu Dudau <Liviu.Dudau@arm.com>
>> CC: Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com>
>> CC: Will Deacon <will.deacon@arm.com>
>> ---
>> arch/arm64/Kconfig | 6 ++
>> arch/arm64/kernel/pci.c | 208 +++++++++++++++++++++++++++++++++++++++++++++---
>> 2 files changed, 202 insertions(+), 12 deletions(-)
>>
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 07d1811..bbcc6b1 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -89,6 +89,7 @@ config ARM64
>> select SPARSE_IRQ
>> select SYSCTL_EXCEPTION_TRACE
>> select HAVE_CONTEXT_TRACKING
>> + select HAVE_PCI_ECAM
>> help
>> ARM 64-bit (AArch64) Linux support.
>>
>> @@ -202,6 +203,11 @@ source "drivers/pci/Kconfig"
>> source "drivers/pci/pcie/Kconfig"
>> source "drivers/pci/hotplug/Kconfig"
>>
>> +config PCI_MMCONFIG
>> + def_bool y
>> + select PCI_ECAM
>> + depends on ACPI
>> +
>> endmenu
>>
>> menu "Kernel Features"
>> diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
>> index b3d098b..66cc1ae 100644
>> --- a/arch/arm64/kernel/pci.c
>> +++ b/arch/arm64/kernel/pci.c
>> @@ -11,12 +11,15 @@
>> */
>>
>> #include <linux/acpi.h>
>> +#include <linux/ecam.h>
>> #include <linux/init.h>
>> #include <linux/io.h>
>> #include <linux/kernel.h>
>> #include <linux/mm.h>
>> +#include <linux/of_address.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>
>> @@ -52,35 +55,216 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
>> }
>>
>> /*
>> - * Try to assign the IRQ number from DT when adding a new device
>> + * Try to assign the IRQ number from DT/ACPI when adding a new device
>> */
>> int pcibios_add_device(struct pci_dev *dev)
>> {
>> - dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
>> + if (acpi_disabled)
>> + dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
>> +#ifdef CONFIG_ACPI
>> + else
>> + acpi_pci_irq_enable(dev);
>> +#endif
>>
>> return 0;
>> }
>>
>> +#ifdef CONFIG_ACPI
>> +int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
>> +{
>> + struct acpi_pci_root *root = bridge->bus->sysdata;
>> +
>> + ACPI_COMPANION_SET(&bridge->dev, root->device);
>> + return 0;
>> +}
>> +
>> +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);
>> +}
>> +
>> +static int __init pcibios_assign_resources(void)
>> +{
>> + if (acpi_disabled)
>> + return 0;
>> +
>> + pci_assign_unassigned_resources();
>> + return 0;
>
> You can change this function into:
> {
> if (!acpi_disabled)
> pci_assign_unassigned_resources();
>
> return 0;
> }
>
> as the equivalent but shorter form.
Sure, will do.
>
>> +}
>> /*
>> - * raw_pci_read/write - Platform-specific PCI config space access.
>> + * rootfs_initcall comes after subsys_initcall and fs_initcall_sync,
>> + * so we know acpi scan and PCI_FIXUP_FINAL quirks have both run.
>> */
>> -int raw_pci_read(unsigned int domain, unsigned int bus,
>> - unsigned int devfn, int reg, int len, u32 *val)
>
> What happened with raw_pci_{read,write} ? Why do you remove them?
We do not need raw_pci_{read,write} any more, we will use empty
raw_pci_{read,write} from mcfg.c introduced in patch 6/11.
I think this is another candidate to split up, first I will remove these
raw_pci_{read,write} accessors and then introduce ACPI PCI hostbridge
init, it will be easier to review, what do you think?
>
>
>> +rootfs_initcall(pcibios_assign_resources);
>
> Would you be so kind and explain to me why you need this initcall?
> Can you not set the PCI_REASSIGN_ALL_RSRC flag before calling
> pci_scan_root_bus() ?
>
> I haven't focused on ACPI before so I'm a bit hazy on the init order when
> that is enabled. That being said, I don't like adding in the architecture
> code initcall hooks just to fix up some dependency orders that could / should
> be fixed some other way.
My idea was to defer resource reassigning to give a chance for running
DECLARE_PCI_FIXUP_FINAL. I used DECLARE_PCI_FIXUP_FINAL to set
IORESOURCE_PCI_FIXED for some PCI devices. Now I am not sure we need to
defer it, my DECLARE_PCI_FIXUP_FINALs might be done in firmware, let me
get back to you on this.
>
>> +
>> +static void __iomem *
>> +pci_mcfg_dev_base(struct pci_bus *bus, unsigned int devfn, int offset)
>> {
>> - return -ENXIO;
>> + struct pci_mmcfg_region *cfg;
>> +
>> + cfg = pci_mmconfig_lookup(pci_domain_nr(bus), bus->number);
>> + if (cfg && cfg->virt)
>> + return cfg->virt +
>> + (PCI_MMCFG_BUS_OFFSET(bus->number) | (devfn << 12)) +
>> + offset;
>> + return NULL;
>> }
>>
>> -int raw_pci_write(unsigned int domain, unsigned int bus,
>> - unsigned int devfn, int reg, int len, u32 val)
>> +struct pci_ops pci_root_ops = {
>> + .map_bus = pci_mcfg_dev_base,
>> + .read = pci_generic_config_read,
>> + .write = pci_generic_config_write,
>> +};
>> +
>> +#ifdef CONFIG_PCI_MMCONFIG
>> +static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
>> {
>> - return -ENXIO;
>> + struct pci_mmcfg_region *cfg;
>> + struct acpi_pci_root *root;
>> + int seg, start, end, err;
>> +
>> + root = ci->root;
>> + seg = root->segment;
>> + start = root->secondary.start;
>> + end = root->secondary.end;
>> +
>> + cfg = pci_mmconfig_lookup(seg, start);
>> + if (cfg)
>> + return 0;
>> +
>> + cfg = pci_mmconfig_alloc(seg, start, end, root->mcfg_addr);
>> + if (!cfg)
>> + return -ENOMEM;
>> +
>> + err = pci_mmconfig_inject(cfg);
>> + return err;
>> }
>>
>> -#ifdef CONFIG_ACPI
>> +static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci)
>> +{
>> + struct acpi_pci_root *root = ci->root;
>> + struct pci_mmcfg_region *cfg;
>> +
>> + cfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
>> + if (cfg)
>> + return;
>> +
>> + if (cfg->hot_added)
>> + pci_mmconfig_delete(root->segment, root->secondary.start,
>> + root->secondary.end);
>> +}
>> +#else
>> +static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
>> +{
>> + return 0;
>> +}
>> +
>> +static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci) { }
>> +#endif
>> +
>> +static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
>> +{
>> + return pci_add_mmconfig_region(ci);
>> +}
>> +
>> +static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
>> +{
>> + pci_remove_mmconfig_region(ci);
>> + kfree(ci);
>> +}
>> +
>> +static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
>> +{
>> + struct resource_entry *entry, *tmp;
>> + int ret;
>> +
>> + ret = acpi_pci_probe_root_resources(ci);
>> + if (ret < 0)
>> + return ret;
>> +
>> + resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
>> + struct resource *res = entry->res;
>> +
>> + /*
>> + * Special handling for ARM IO range
>
> There is nothing ARM specific here. It should apply to any memory mapped IO range.
OK, I will remove that comment.
>
>> + * TODO: need to move pci_register_io_range() function out
>> + * of drivers/of/address.c for both used by DT and ACPI
>> + */
>> + if (res->flags & IORESOURCE_IO) {
>> + unsigned long port;
>> + int err;
>> + resource_size_t length = res->end - res->start;
>> +
>> + err = pci_register_io_range(res->start, length);
>> + if (err) {
>> + resource_list_destroy_entry(entry);
>> + continue;
>> + }
>> +
>> + port = pci_address_to_pio(res->start);
>> + if (port == (unsigned long)-1) {
>> + resource_list_destroy_entry(entry);
>> + continue;
>> + }
>> +
>> + res->start = port;
>> + res->end = res->start + length - 1;
>> +
>> + if (pci_remap_iospace(res, res->start) < 0)
>> + resource_list_destroy_entry(entry);
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static struct acpi_pci_root_ops acpi_pci_root_ops = {
>> + .pci_ops = &pci_root_ops,
>> + .init_info = pci_acpi_root_init_info,
>> + .release_info = pci_acpi_root_release_info,
>> + .prepare_resources = pci_acpi_root_prepare_resources,
>> +};
>> +
>> /* Root bridge scanning */
>> struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
>> {
>> - /* TODO: Should be revisited when implementing PCI on ACPI */
>> - return NULL;
>> + int node = acpi_get_node(root->device->handle);
>> + int domain = root->segment;
>> + int busnum = root->secondary.start;
>> + struct acpi_pci_root_info *info;
>> + struct pci_bus *bus;
>> +
>> + if (domain && !pci_domains_supported) {
>> + pr_warn("PCI %04x:%02x: multiple domains not supported.\n",
>> + domain, busnum);
>> + return NULL;
>> + }
>> +
>> + info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
>> + if (!info) {
>> + dev_err(&root->device->dev,
>> + "pci_bus %04x:%02x: ignored (out of memory)\n",
>> + domain, busnum);
>> + return NULL;
>> + }
>> +
>> + bus = acpi_pci_root_create(root, &acpi_pci_root_ops, info, root);
>> +
>> + /* After the PCI-E bus has been walked and all devices discovered,
>> + * configure any settings of the fabric that might be necessary.
>> + */
>> + if (bus) {
>> + struct pci_bus *child;
>> +
>> + list_for_each_entry(child, &bus->children, node)
>> + pcie_bus_configure_settings(child);
>> + }
>> +
>> + return bus;
>> }
>> #endif
>> --
>> 1.9.1
>>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Liviu.Dudau@arm.com |
|---|---|
| Date | 2015-10-28 15:00 +0100 |
| Subject | Re: [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init |
| Message-ID | <qozqI-3k6-65@gated-at.bofh.it> |
| In reply to | #1258034 |
On Wed, Oct 28, 2015 at 02:42:30PM +0100, Tomasz Nowicki wrote:
> On 28.10.2015 12:49, Liviu.Dudau@arm.com wrote:
> >On Tue, Oct 27, 2015 at 05:38:42PM +0100, Tomasz Nowicki wrote:
> >>Because of two patch series:
> >>1. Jiang Liu's common interface to support PCI host bridge init
> >>2. Refactoring of MMCONFIG, part of this patch set
> >>now we can think about PCI buses enumeration for ARM64 and ACPI tables.
> >>
> >>This patch introduce ACPI based PCI hostbridge init calls which
> >>use information from MCFG table (PCI config space regions) and
> >>_CRS (IO/irq resources) to initialize PCI hostbridge.
> >>
> >>Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
> >>Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> >>Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> >>CC: Arnd Bergmann <arnd@arndb.de>
> >>CC: Catalin Marinas <catalin.marinas@arm.com>
> >>CC: Liviu Dudau <Liviu.Dudau@arm.com>
> >>CC: Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com>
> >>CC: Will Deacon <will.deacon@arm.com>
> >>---
> >> arch/arm64/Kconfig | 6 ++
> >> arch/arm64/kernel/pci.c | 208 +++++++++++++++++++++++++++++++++++++++++++++---
> >> 2 files changed, 202 insertions(+), 12 deletions(-)
> >>
> >>diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> >>index 07d1811..bbcc6b1 100644
> >>--- a/arch/arm64/Kconfig
> >>+++ b/arch/arm64/Kconfig
> >>@@ -89,6 +89,7 @@ config ARM64
> >> select SPARSE_IRQ
> >> select SYSCTL_EXCEPTION_TRACE
> >> select HAVE_CONTEXT_TRACKING
> >>+ select HAVE_PCI_ECAM
> >> help
> >> ARM 64-bit (AArch64) Linux support.
> >>
> >>@@ -202,6 +203,11 @@ source "drivers/pci/Kconfig"
> >> source "drivers/pci/pcie/Kconfig"
> >> source "drivers/pci/hotplug/Kconfig"
> >>
> >>+config PCI_MMCONFIG
> >>+ def_bool y
> >>+ select PCI_ECAM
> >>+ depends on ACPI
> >>+
> >> endmenu
> >>
> >> menu "Kernel Features"
> >>diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
> >>index b3d098b..66cc1ae 100644
> >>--- a/arch/arm64/kernel/pci.c
> >>+++ b/arch/arm64/kernel/pci.c
> >>@@ -11,12 +11,15 @@
> >> */
> >>
> >> #include <linux/acpi.h>
> >>+#include <linux/ecam.h>
> >> #include <linux/init.h>
> >> #include <linux/io.h>
> >> #include <linux/kernel.h>
> >> #include <linux/mm.h>
> >>+#include <linux/of_address.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>
> >>@@ -52,35 +55,216 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
> >> }
> >>
> >> /*
> >>- * Try to assign the IRQ number from DT when adding a new device
> >>+ * Try to assign the IRQ number from DT/ACPI when adding a new device
> >> */
> >> int pcibios_add_device(struct pci_dev *dev)
> >> {
> >>- dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
> >>+ if (acpi_disabled)
> >>+ dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
> >>+#ifdef CONFIG_ACPI
> >>+ else
> >>+ acpi_pci_irq_enable(dev);
> >>+#endif
> >>
> >> return 0;
> >> }
> >>
> >>+#ifdef CONFIG_ACPI
> >>+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
> >>+{
> >>+ struct acpi_pci_root *root = bridge->bus->sysdata;
> >>+
> >>+ ACPI_COMPANION_SET(&bridge->dev, root->device);
> >>+ return 0;
> >>+}
> >>+
> >>+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);
> >>+}
> >>+
> >>+static int __init pcibios_assign_resources(void)
> >>+{
> >>+ if (acpi_disabled)
> >>+ return 0;
> >>+
> >>+ pci_assign_unassigned_resources();
> >>+ return 0;
> >
> >You can change this function into:
> >{
> > if (!acpi_disabled)
> > pci_assign_unassigned_resources();
> >
> > return 0;
> >}
> >
> >as the equivalent but shorter form.
>
> Sure, will do.
>
> >
> >>+}
> >> /*
> >>- * raw_pci_read/write - Platform-specific PCI config space access.
> >>+ * rootfs_initcall comes after subsys_initcall and fs_initcall_sync,
> >>+ * so we know acpi scan and PCI_FIXUP_FINAL quirks have both run.
> >> */
> >>-int raw_pci_read(unsigned int domain, unsigned int bus,
> >>- unsigned int devfn, int reg, int len, u32 *val)
> >
> >What happened with raw_pci_{read,write} ? Why do you remove them?
>
> We do not need raw_pci_{read,write} any more, we will use empty
> raw_pci_{read,write} from mcfg.c introduced in patch 6/11.
>
> I think this is another candidate to split up, first I will remove these
> raw_pci_{read,write} accessors and then introduce ACPI PCI hostbridge init,
> it will be easier to review, what do you think?
Yes, I like that. If the calls were redundant after 6/11 then they should
not have been kept until this patch to be removed.
>
> >
> >
> >>+rootfs_initcall(pcibios_assign_resources);
> >
> >Would you be so kind and explain to me why you need this initcall?
> >Can you not set the PCI_REASSIGN_ALL_RSRC flag before calling
> >pci_scan_root_bus() ?
> >
> >I haven't focused on ACPI before so I'm a bit hazy on the init order when
> >that is enabled. That being said, I don't like adding in the architecture
> >code initcall hooks just to fix up some dependency orders that could / should
> >be fixed some other way.
>
> My idea was to defer resource reassigning to give a chance for running
> DECLARE_PCI_FIXUP_FINAL. I used DECLARE_PCI_FIXUP_FINAL to set
> IORESOURCE_PCI_FIXED for some PCI devices. Now I am not sure we need to
> defer it, my DECLARE_PCI_FIXUP_FINALs might be done in firmware, let me get
> back to you on this.
If fixups can be done in firmware then that is the preferred direction nowadays.
>
> >
> >>+
> >>+static void __iomem *
> >>+pci_mcfg_dev_base(struct pci_bus *bus, unsigned int devfn, int offset)
> >> {
> >>- return -ENXIO;
> >>+ struct pci_mmcfg_region *cfg;
> >>+
> >>+ cfg = pci_mmconfig_lookup(pci_domain_nr(bus), bus->number);
> >>+ if (cfg && cfg->virt)
> >>+ return cfg->virt +
> >>+ (PCI_MMCFG_BUS_OFFSET(bus->number) | (devfn << 12)) +
> >>+ offset;
> >>+ return NULL;
> >> }
> >>
> >>-int raw_pci_write(unsigned int domain, unsigned int bus,
> >>- unsigned int devfn, int reg, int len, u32 val)
> >>+struct pci_ops pci_root_ops = {
> >>+ .map_bus = pci_mcfg_dev_base,
> >>+ .read = pci_generic_config_read,
> >>+ .write = pci_generic_config_write,
> >>+};
> >>+
> >>+#ifdef CONFIG_PCI_MMCONFIG
> >>+static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
> >> {
> >>- return -ENXIO;
> >>+ struct pci_mmcfg_region *cfg;
> >>+ struct acpi_pci_root *root;
> >>+ int seg, start, end, err;
> >>+
> >>+ root = ci->root;
> >>+ seg = root->segment;
> >>+ start = root->secondary.start;
> >>+ end = root->secondary.end;
> >>+
> >>+ cfg = pci_mmconfig_lookup(seg, start);
> >>+ if (cfg)
> >>+ return 0;
> >>+
> >>+ cfg = pci_mmconfig_alloc(seg, start, end, root->mcfg_addr);
> >>+ if (!cfg)
> >>+ return -ENOMEM;
> >>+
> >>+ err = pci_mmconfig_inject(cfg);
> >>+ return err;
> >> }
> >>
> >>-#ifdef CONFIG_ACPI
> >>+static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci)
> >>+{
> >>+ struct acpi_pci_root *root = ci->root;
> >>+ struct pci_mmcfg_region *cfg;
> >>+
> >>+ cfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
> >>+ if (cfg)
> >>+ return;
> >>+
> >>+ if (cfg->hot_added)
> >>+ pci_mmconfig_delete(root->segment, root->secondary.start,
> >>+ root->secondary.end);
> >>+}
> >>+#else
> >>+static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
> >>+{
> >>+ return 0;
> >>+}
> >>+
> >>+static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci) { }
> >>+#endif
> >>+
> >>+static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
> >>+{
> >>+ return pci_add_mmconfig_region(ci);
> >>+}
> >>+
> >>+static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
> >>+{
> >>+ pci_remove_mmconfig_region(ci);
> >>+ kfree(ci);
> >>+}
> >>+
> >>+static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
> >>+{
> >>+ struct resource_entry *entry, *tmp;
> >>+ int ret;
> >>+
> >>+ ret = acpi_pci_probe_root_resources(ci);
> >>+ if (ret < 0)
> >>+ return ret;
> >>+
> >>+ resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
> >>+ struct resource *res = entry->res;
> >>+
> >>+ /*
> >>+ * Special handling for ARM IO range
> >
> >There is nothing ARM specific here. It should apply to any memory mapped IO range.
>
> OK, I will remove that comment.
Thanks!
Liviu
>
> >
> >>+ * TODO: need to move pci_register_io_range() function out
> >>+ * of drivers/of/address.c for both used by DT and ACPI
> >>+ */
> >>+ if (res->flags & IORESOURCE_IO) {
> >>+ unsigned long port;
> >>+ int err;
> >>+ resource_size_t length = res->end - res->start;
> >>+
> >>+ err = pci_register_io_range(res->start, length);
> >>+ if (err) {
> >>+ resource_list_destroy_entry(entry);
> >>+ continue;
> >>+ }
> >>+
> >>+ port = pci_address_to_pio(res->start);
> >>+ if (port == (unsigned long)-1) {
> >>+ resource_list_destroy_entry(entry);
> >>+ continue;
> >>+ }
> >>+
> >>+ res->start = port;
> >>+ res->end = res->start + length - 1;
> >>+
> >>+ if (pci_remap_iospace(res, res->start) < 0)
> >>+ resource_list_destroy_entry(entry);
> >>+ }
> >>+ }
> >>+
> >>+ return 0;
> >>+}
> >>+
> >>+static struct acpi_pci_root_ops acpi_pci_root_ops = {
> >>+ .pci_ops = &pci_root_ops,
> >>+ .init_info = pci_acpi_root_init_info,
> >>+ .release_info = pci_acpi_root_release_info,
> >>+ .prepare_resources = pci_acpi_root_prepare_resources,
> >>+};
> >>+
> >> /* Root bridge scanning */
> >> struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
> >> {
> >>- /* TODO: Should be revisited when implementing PCI on ACPI */
> >>- return NULL;
> >>+ int node = acpi_get_node(root->device->handle);
> >>+ int domain = root->segment;
> >>+ int busnum = root->secondary.start;
> >>+ struct acpi_pci_root_info *info;
> >>+ struct pci_bus *bus;
> >>+
> >>+ if (domain && !pci_domains_supported) {
> >>+ pr_warn("PCI %04x:%02x: multiple domains not supported.\n",
> >>+ domain, busnum);
> >>+ return NULL;
> >>+ }
> >>+
> >>+ info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
> >>+ if (!info) {
> >>+ dev_err(&root->device->dev,
> >>+ "pci_bus %04x:%02x: ignored (out of memory)\n",
> >>+ domain, busnum);
> >>+ return NULL;
> >>+ }
> >>+
> >>+ bus = acpi_pci_root_create(root, &acpi_pci_root_ops, info, root);
> >>+
> >>+ /* After the PCI-E bus has been walked and all devices discovered,
> >>+ * configure any settings of the fabric that might be necessary.
> >>+ */
> >>+ if (bus) {
> >>+ struct pci_bus *child;
> >>+
> >>+ list_for_each_entry(child, &bus->children, node)
> >>+ pcie_bus_configure_settings(child);
> >>+ }
> >>+
> >>+ return bus;
> >> }
> >> #endif
> >>--
> >>1.9.1
> >>
> >
>
--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Sinan Kaya <okaya@codeaurora.org> |
|---|---|
| Date | 2015-10-28 19:50 +0100 |
| Subject | Re: [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init |
| Message-ID | <qoDXj-6mo-3@gated-at.bofh.it> |
| In reply to | #1256937 |
On 10/27/2015 12:38 PM, Tomasz Nowicki wrote:
> Because of two patch series:
> 1. Jiang Liu's common interface to support PCI host bridge init
> 2. Refactoring of MMCONFIG, part of this patch set
> now we can think about PCI buses enumeration for ARM64 and ACPI tables.
>
> This patch introduce ACPI based PCI hostbridge init calls which
> use information from MCFG table (PCI config space regions) and
> _CRS (IO/irq resources) to initialize PCI hostbridge.
>
> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> CC: Arnd Bergmann <arnd@arndb.de>
> CC: Catalin Marinas <catalin.marinas@arm.com>
> CC: Liviu Dudau <Liviu.Dudau@arm.com>
> CC: Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com>
> CC: Will Deacon <will.deacon@arm.com>
> ---
> arch/arm64/Kconfig | 6 ++
> arch/arm64/kernel/pci.c | 208 +++++++++++++++++++++++++++++++++++++++++++++---
> 2 files changed, 202 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 07d1811..bbcc6b1 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -89,6 +89,7 @@ config ARM64
> select SPARSE_IRQ
> select SYSCTL_EXCEPTION_TRACE
> select HAVE_CONTEXT_TRACKING
> + select HAVE_PCI_ECAM
> help
> ARM 64-bit (AArch64) Linux support.
>
> @@ -202,6 +203,11 @@ source "drivers/pci/Kconfig"
> source "drivers/pci/pcie/Kconfig"
> source "drivers/pci/hotplug/Kconfig"
>
> +config PCI_MMCONFIG
> + def_bool y
> + select PCI_ECAM
> + depends on ACPI
> +
> endmenu
>
> menu "Kernel Features"
> diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
> index b3d098b..66cc1ae 100644
> --- a/arch/arm64/kernel/pci.c
> +++ b/arch/arm64/kernel/pci.c
> @@ -11,12 +11,15 @@
> */
>
> #include <linux/acpi.h>
> +#include <linux/ecam.h>
> #include <linux/init.h>
> #include <linux/io.h>
> #include <linux/kernel.h>
> #include <linux/mm.h>
> +#include <linux/of_address.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>
> @@ -52,35 +55,216 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
> }
>
> /*
> - * Try to assign the IRQ number from DT when adding a new device
> + * Try to assign the IRQ number from DT/ACPI when adding a new device
> */
> int pcibios_add_device(struct pci_dev *dev)
> {
> - dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
> + if (acpi_disabled)
> + dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
> +#ifdef CONFIG_ACPI
> + else
> + acpi_pci_irq_enable(dev);
> +#endif
>
> return 0;
> }
>
> +#ifdef CONFIG_ACPI
> +int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
> +{
> + struct acpi_pci_root *root = bridge->bus->sysdata;
> +
> + ACPI_COMPANION_SET(&bridge->dev, root->device);
> + return 0;
> +}
> +
> +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);
> +}
> +
> +static int __init pcibios_assign_resources(void)
> +{
> + if (acpi_disabled)
> + return 0;
> +
> + pci_assign_unassigned_resources();
> + return 0;
> +}
> /*
> - * raw_pci_read/write - Platform-specific PCI config space access.
> + * rootfs_initcall comes after subsys_initcall and fs_initcall_sync,
> + * so we know acpi scan and PCI_FIXUP_FINAL quirks have both run.
> */
> -int raw_pci_read(unsigned int domain, unsigned int bus,
> - unsigned int devfn, int reg, int len, u32 *val)
> +rootfs_initcall(pcibios_assign_resources);
> +
> +static void __iomem *
> +pci_mcfg_dev_base(struct pci_bus *bus, unsigned int devfn, int offset)
> {
> - return -ENXIO;
> + struct pci_mmcfg_region *cfg;
> +
> + cfg = pci_mmconfig_lookup(pci_domain_nr(bus), bus->number);
> + if (cfg && cfg->virt)
> + return cfg->virt +
> + (PCI_MMCFG_BUS_OFFSET(bus->number) | (devfn << 12)) +
> + offset;
> + return NULL;
> }
>
> -int raw_pci_write(unsigned int domain, unsigned int bus,
> - unsigned int devfn, int reg, int len, u32 val)
> +struct pci_ops pci_root_ops = {
> + .map_bus = pci_mcfg_dev_base,
> + .read = pci_generic_config_read,
> + .write = pci_generic_config_write,
Can you change these with pci_generic_config_read32 and
pci_generic_config_write32? We have some targets that can only do 32
bits PCI config space access.
> +};
> +
> +#ifdef CONFIG_PCI_MMCONFIG
> +static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
> {
> - return -ENXIO;
> + struct pci_mmcfg_region *cfg;
> + struct acpi_pci_root *root;
> + int seg, start, end, err;
> +
> + root = ci->root;
> + seg = root->segment;
> + start = root->secondary.start;
> + end = root->secondary.end;
> +
> + cfg = pci_mmconfig_lookup(seg, start);
> + if (cfg)
> + return 0;
> +
> + cfg = pci_mmconfig_alloc(seg, start, end, root->mcfg_addr);
> + if (!cfg)
> + return -ENOMEM;
> +
> + err = pci_mmconfig_inject(cfg);
> + return err;
> }
>
> -#ifdef CONFIG_ACPI
> +static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci)
> +{
> + struct acpi_pci_root *root = ci->root;
> + struct pci_mmcfg_region *cfg;
> +
> + cfg = pci_mmconfig_lookup(root->segment, root->secondary.start);
> + if (cfg)
> + return;
> +
> + if (cfg->hot_added)
> + pci_mmconfig_delete(root->segment, root->secondary.start,
> + root->secondary.end);
> +}
> +#else
> +static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci)
> +{
> + return 0;
> +}
> +
> +static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci) { }
> +#endif
> +
> +static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci)
> +{
> + return pci_add_mmconfig_region(ci);
> +}
> +
> +static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci)
> +{
> + pci_remove_mmconfig_region(ci);
> + kfree(ci);
> +}
> +
> +static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
> +{
> + struct resource_entry *entry, *tmp;
> + int ret;
> +
> + ret = acpi_pci_probe_root_resources(ci);
> + if (ret < 0)
> + return ret;
> +
> + resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
> + struct resource *res = entry->res;
> +
> + /*
> + * Special handling for ARM IO range
> + * TODO: need to move pci_register_io_range() function out
> + * of drivers/of/address.c for both used by DT and ACPI
> + */
> + if (res->flags & IORESOURCE_IO) {
> + unsigned long port;
> + int err;
> + resource_size_t length = res->end - res->start;
> +
> + err = pci_register_io_range(res->start, length);
> + if (err) {
> + resource_list_destroy_entry(entry);
> + continue;
> + }
> +
> + port = pci_address_to_pio(res->start);
> + if (port == (unsigned long)-1) {
> + resource_list_destroy_entry(entry);
> + continue;
> + }
> +
> + res->start = port;
> + res->end = res->start + length - 1;
> +
> + if (pci_remap_iospace(res, res->start) < 0)
> + resource_list_destroy_entry(entry);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static struct acpi_pci_root_ops acpi_pci_root_ops = {
> + .pci_ops = &pci_root_ops,
> + .init_info = pci_acpi_root_init_info,
> + .release_info = pci_acpi_root_release_info,
> + .prepare_resources = pci_acpi_root_prepare_resources,
> +};
> +
> /* Root bridge scanning */
> struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
> {
> - /* TODO: Should be revisited when implementing PCI on ACPI */
> - return NULL;
> + int node = acpi_get_node(root->device->handle);
> + int domain = root->segment;
> + int busnum = root->secondary.start;
> + struct acpi_pci_root_info *info;
> + struct pci_bus *bus;
> +
> + if (domain && !pci_domains_supported) {
> + pr_warn("PCI %04x:%02x: multiple domains not supported.\n",
> + domain, busnum);
> + return NULL;
> + }
> +
> + info = kzalloc_node(sizeof(*info), GFP_KERNEL, node);
> + if (!info) {
> + dev_err(&root->device->dev,
> + "pci_bus %04x:%02x: ignored (out of memory)\n",
> + domain, busnum);
> + return NULL;
> + }
> +
> + bus = acpi_pci_root_create(root, &acpi_pci_root_ops, info, root);
> +
> + /* After the PCI-E bus has been walked and all devices discovered,
> + * configure any settings of the fabric that might be necessary.
> + */
> + if (bus) {
> + struct pci_bus *child;
> +
> + list_for_each_entry(child, &bus->children, node)
> + pcie_bus_configure_settings(child);
> + }
> +
> + return bus;
> }
> #endif
>
--
Sinan Kaya
Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a
Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:50 +0100 |
| Subject | [PATCH V1 05/11] x86, pci, ecam: mmconfig_64.c becomes default implementation for ECAM driver. |
| Message-ID | <qofBF-7xc-37@gated-at.bofh.it> |
| In reply to | #1256927 |
Hosts with custom ECAM hooks (like 32bit x86) should select
ARCH_HAS_CUSTOM_PCI_ECAM. Otherwise, host will use generic version
provided by this patch (like 64bit x86 does).
Note, we leaved x86-specific PCI config accessors in corresponding files.
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
---
arch/x86/Kconfig | 1 +
arch/x86/include/asm/pci_x86.h | 4 ---
arch/x86/pci/mmconfig_64.c | 55 ---------------------------------------
drivers/acpi/mcfg.c | 2 --
drivers/pci/Kconfig | 3 +++
drivers/pci/ecam.c | 59 +++++++++++++++++++++++++++++++++++++++++-
include/linux/ecam.h | 6 +++++
7 files changed, 68 insertions(+), 62 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 4ca8134..b4b68eb 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -30,6 +30,7 @@ config X86
select ARCH_HAS_PMEM_API if X86_64
select ARCH_HAS_MMIO_FLUSH
select ARCH_HAS_SG_CHAIN
+ select ARCH_HAS_CUSTOM_PCI_ECAM if X86_32
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
select ARCH_MIGHT_HAVE_PC_PARPORT
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index 039f69e..c9bda33 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -122,10 +122,6 @@ extern int pci_legacy_init(void);
extern void pcibios_fixup_irqs(void);
/* pci-mmconfig.c */
-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);
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index d0c48eb..fd356cc 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -90,58 +90,3 @@ int pci_mmcfg_write(unsigned int seg, unsigned int bus,
return 0;
}
-
-static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
-{
- void __iomem *addr;
- u64 start, size;
- int num_buses;
-
- start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
- num_buses = cfg->end_bus - cfg->start_bus + 1;
- size = PCI_MMCFG_BUS_OFFSET(num_buses);
- addr = ioremap_nocache(start, size);
- if (addr)
- addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
- return addr;
-}
-
-int __init pci_mmcfg_arch_init(void)
-{
- struct pci_mmcfg_region *cfg;
-
- list_for_each_entry(cfg, &pci_mmcfg_list, list)
- if (pci_mmcfg_arch_map(cfg)) {
- pci_mmcfg_arch_free();
- return 0;
- }
-
- return 1;
-}
-
-void __init pci_mmcfg_arch_free(void)
-{
- struct pci_mmcfg_region *cfg;
-
- list_for_each_entry(cfg, &pci_mmcfg_list, list)
- pci_mmcfg_arch_unmap(cfg);
-}
-
-int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
-{
- cfg->virt = mcfg_ioremap(cfg);
- if (!cfg->virt) {
- pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
-{
- if (cfg && cfg->virt) {
- iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
- cfg->virt = NULL;
- }
-}
diff --git a/drivers/acpi/mcfg.c b/drivers/acpi/mcfg.c
index fad9917..745b83e 100644
--- a/drivers/acpi/mcfg.c
+++ b/drivers/acpi/mcfg.c
@@ -10,8 +10,6 @@
#include <linux/acpi.h>
#include <linux/ecam.h>
-#include <asm/pci_x86.h> /* Temp hack before refactoring arch-specific calls */
-
#define PREFIX "MCFG: "
int __init acpi_parse_mcfg(struct acpi_table_header *header)
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 9950248..b2e27c8 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -33,6 +33,9 @@ config PCI_ECAM
config HAVE_PCI_ECAM
bool
+config ARCH_HAS_CUSTOM_PCI_ECAM
+ bool
+
config PCI_DEBUG
bool "PCI Debugging"
depends on PCI && DEBUG_KERNEL
diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c
index d221dba..8a5eef7 100644
--- a/drivers/pci/ecam.c
+++ b/drivers/pci/ecam.c
@@ -16,7 +16,6 @@
#include <linux/ecam.h>
#include <asm/io.h>
-#include <asm/pci_x86.h> /* Temp hack before refactoring arch-specific calls */
#define PREFIX "PCI: "
@@ -24,6 +23,64 @@ static DEFINE_MUTEX(pci_mmcfg_lock);
LIST_HEAD(pci_mmcfg_list);
+#ifndef CONFIG_ARCH_HAS_CUSTOM_PCI_ECAM
+
+static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
+{
+ void __iomem *addr;
+ u64 start, size;
+ int num_buses;
+
+ start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
+ num_buses = cfg->end_bus - cfg->start_bus + 1;
+ size = PCI_MMCFG_BUS_OFFSET(num_buses);
+ addr = ioremap_nocache(start, size);
+ if (addr)
+ addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
+ return addr;
+}
+
+int __init pci_mmcfg_arch_init(void)
+{
+ struct pci_mmcfg_region *cfg;
+
+ list_for_each_entry(cfg, &pci_mmcfg_list, list)
+ if (pci_mmcfg_arch_map(cfg)) {
+ pci_mmcfg_arch_free();
+ return 0;
+ }
+
+ return 1;
+}
+
+void __init pci_mmcfg_arch_free(void)
+{
+ struct pci_mmcfg_region *cfg;
+
+ list_for_each_entry(cfg, &pci_mmcfg_list, list)
+ pci_mmcfg_arch_unmap(cfg);
+}
+
+int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
+{
+ cfg->virt = mcfg_ioremap(cfg);
+ if (!cfg->virt) {
+ pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
+{
+ if (cfg && cfg->virt) {
+ iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
+ cfg->virt = NULL;
+ }
+}
+#endif
+
static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
{
if (cfg->res.parent)
diff --git a/include/linux/ecam.h b/include/linux/ecam.h
index dec3b52..813acd1 100644
--- a/include/linux/ecam.h
+++ b/include/linux/ecam.h
@@ -29,6 +29,12 @@ void list_add_sorted(struct pci_mmcfg_region *new);
void free_all_mmcfg(void);
int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
+/* Arch specific calls */
+int pci_mmcfg_arch_init(void);
+void pci_mmcfg_arch_free(void);
+int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
+void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
+
extern struct list_head pci_mmcfg_list;
#define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20)
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:50 +0100 |
| Subject | [PATCH V1 08/11] pci, acpi, ecam: Add flag to indicate whether ECAM region was hot added or not. |
| Message-ID | <qofBF-7xc-39@gated-at.bofh.it> |
| In reply to | #1256927 |
There are two ways we can get ECAM (aka MCFG) regions using ACPI,
from MCFG static table and from _CBA method. We cannot remove static
regions, however regions coming from _CBA should be removed while removing
bridge device.
In the light of above we need flag to mark hot added ECAM entries
so that user should use pci_mmconfig_inject while adding regions from
_CBA method.
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
---
drivers/pci/ecam.c | 2 ++
include/linux/ecam.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c
index 8a5eef7..da35b4c 100644
--- a/drivers/pci/ecam.c
+++ b/drivers/pci/ecam.c
@@ -131,6 +131,7 @@ struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
new->segment = segment;
new->start_bus = start;
new->end_bus = end;
+ new->hot_added = false;
res = &new->res;
res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
@@ -221,6 +222,7 @@ int pci_mmconfig_inject(struct pci_mmcfg_region *cfg)
err = -ENOMEM;
goto out;
} else {
+ cfg->hot_added = true;
list_add_sorted(cfg);
pr_info("MMCONFIG at %pR (base %#lx)\n",
&cfg->res, (unsigned long)cfg->address);
diff --git a/include/linux/ecam.h b/include/linux/ecam.h
index 813acd1..e0f322e 100644
--- a/include/linux/ecam.h
+++ b/include/linux/ecam.h
@@ -17,6 +17,7 @@ struct pci_mmcfg_region {
u8 start_bus;
u8 end_bus;
char name[PCI_MMCFG_RESOURCE_NAME_LEN];
+ bool hot_added;
};
struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:50 +0100 |
| Subject | [PATCH V1 01/11] x86, pci: Reorder logic of pci_mmconfig_insert() function |
| Message-ID | <qofBF-7xc-45@gated-at.bofh.it> |
| In reply to | #1256927 |
This patch is the first step for MMCONFIG refactoring process.
Code that uses pci_mmcfg_lock will be moved to common file and become
accessible for all architectures. pci_mmconfig_insert() cannot be moved
so easily since it is mixing generic mmconfig code with x86 specific logic
inside of mutual exclusive block guarded by pci_mmcfg_lock.
To get rid of that constraint, we reorder actions as follow:
1. sanity check for mmconfig region presence, if we already have such
region it doesn't make snese to alloc new mmconfig list entry
2. mmconfig entry allocation, no need to lock
3. insertion to iomem_resource has its own lock, no need to wrap it into mutex
4. insertion to mmconfig list can be done as the final step in separate
function (candidate for further refactoring) and needs another mmconfig
lookup to avoid race condition.
Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
---
arch/x86/pci/mmconfig-shared.c | 101 +++++++++++++++++++++++------------------
1 file changed, 58 insertions(+), 43 deletions(-)
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index dd30b7e..c8bb9b0 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -720,6 +720,38 @@ static int __init pci_mmcfg_late_insert_resources(void)
*/
late_initcall(pci_mmcfg_late_insert_resources);
+static int pci_mmconfig_inject(struct pci_mmcfg_region *cfg)
+{
+ struct pci_mmcfg_region *cfg_conflict;
+ int err = 0;
+
+ mutex_lock(&pci_mmcfg_lock);
+ cfg_conflict = pci_mmconfig_lookup(cfg->segment, cfg->start_bus);
+ if (cfg_conflict) {
+ if (cfg_conflict->end_bus < cfg->end_bus)
+ pr_info(FW_INFO "MMCONFIG for "
+ "domain %04x [bus %02x-%02x] "
+ "only partially covers this bridge\n",
+ cfg_conflict->segment, cfg_conflict->start_bus,
+ cfg_conflict->end_bus);
+ err = -EEXIST;
+ goto out;
+ }
+
+ if (pci_mmcfg_arch_map(cfg)) {
+ pr_warn("fail to map MMCONFIG %pR.\n", &cfg->res);
+ err = -ENOMEM;
+ goto out;
+ } else {
+ list_add_sorted(cfg);
+ pr_info("MMCONFIG at %pR (base %#lx)\n",
+ &cfg->res, (unsigned long)cfg->address);
+ }
+out:
+ mutex_unlock(&pci_mmcfg_lock);
+ return err;
+}
+
/* Add MMCFG information for host bridges */
int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
phys_addr_t addr)
@@ -734,63 +766,46 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
if (start > end)
return -EINVAL;
- mutex_lock(&pci_mmcfg_lock);
+ rcu_read_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);
+ rcu_read_unlock();
+ if (cfg)
return -EEXIST;
- }
- if (!addr) {
- mutex_unlock(&pci_mmcfg_lock);
+ if (!addr)
return -EINVAL;
- }
- rc = -EBUSY;
cfg = pci_mmconfig_alloc(seg, start, end, addr);
- if (cfg == NULL) {
+ if (!cfg) {
dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
- rc = -ENOMEM;
- } else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
+ return -ENOMEM;
+ }
+
+ rc = -EBUSY;
+ 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);
-
- 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;
- }
+ goto error;
}
- if (cfg) {
- if (cfg->res.parent)
- release_resource(&cfg->res);
- kfree(cfg);
+ /* 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);
+ goto error;
}
- mutex_unlock(&pci_mmcfg_lock);
+ rc = pci_mmconfig_inject(cfg);
+ if (!rc)
+ return 0;
+error:
+ if (cfg->res.parent)
+ release_resource(&cfg->res);
+ kfree(cfg);
return rc;
}
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-27 17:50 +0100 |
| Subject | [PATCH V1 04/11] x86, pci: mmconfig_{32,64}.c code refactoring - remove code duplication. |
| Message-ID | <qofBF-7xc-31@gated-at.bofh.it> |
| In reply to | #1256927 |
mmconfig_64.c version is going to be default implementation for low-level
operation on mmconfig regions. However, now it initializes raw_pci_ext_ops pointer which is specific for
x86 only. Moreover, mmconfig_32.c is doing the same thing at the same time.
So lets move it to mmconfig_shared.c so it becomes common for both and
mmconfig_64.c turns out to be purely arch agnostic.
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
---
arch/x86/include/asm/pci_x86.h | 5 +++++
arch/x86/pci/mmconfig-shared.c | 10 ++++++++--
arch/x86/pci/mmconfig_32.c | 10 ++--------
arch/x86/pci/mmconfig_64.c | 11 ++---------
4 files changed, 17 insertions(+), 19 deletions(-)
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index 64cb514..039f69e 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -129,6 +129,11 @@ 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);
+int pci_mmcfg_read(unsigned int seg, unsigned int bus, unsigned int devfn,
+ int reg, int len, u32 *value);
+int pci_mmcfg_write(unsigned int seg, unsigned int bus, unsigned int devfn,
+ int reg, int len, u32 value);
+
/*
* AMD Fam10h CPUs are buggy, and cannot access MMIO config space
* on their northbrige except through the * %eax register. As such, you MUST
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index ce2c2e4..980f304 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -29,6 +29,11 @@
static bool pci_mmcfg_running_state;
static bool pci_mmcfg_arch_init_failed;
+const struct pci_raw_ops pci_mmcfg = {
+ .read = pci_mmcfg_read,
+ .write = pci_mmcfg_write,
+};
+
static const char *__init pci_mmcfg_e7520(void)
{
u32 win;
@@ -512,9 +517,10 @@ static void __init __pci_mmcfg_init(int early)
}
}
- if (pci_mmcfg_arch_init())
+ if (pci_mmcfg_arch_init()) {
+ raw_pci_ext_ops = &pci_mmcfg;
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
- else {
+ } else {
free_all_mmcfg();
pci_mmcfg_arch_init_failed = true;
}
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 246f135..2ded56f 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -50,7 +50,7 @@ static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
}
}
-static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
+int pci_mmcfg_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
unsigned long flags;
@@ -89,7 +89,7 @@ err: *value = -1;
return 0;
}
-static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
+int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
unsigned long flags;
@@ -126,15 +126,9 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
return 0;
}
-const struct pci_raw_ops pci_mmcfg = {
- .read = pci_mmcfg_read,
- .write = pci_mmcfg_write,
-};
-
int __init pci_mmcfg_arch_init(void)
{
printk(KERN_INFO "PCI: Using MMCONFIG for extended config space\n");
- raw_pci_ext_ops = &pci_mmcfg;
return 1;
}
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index b14fcd3..d0c48eb 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -25,7 +25,7 @@ static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned i
return NULL;
}
-static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
+int pci_mmcfg_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
char __iomem *addr;
@@ -59,7 +59,7 @@ err: *value = -1;
return 0;
}
-static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
+int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
char __iomem *addr;
@@ -91,11 +91,6 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
return 0;
}
-const struct pci_raw_ops pci_mmcfg = {
- .read = pci_mmcfg_read,
- .write = pci_mmcfg_write,
-};
-
static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
{
void __iomem *addr;
@@ -121,8 +116,6 @@ int __init pci_mmcfg_arch_init(void)
return 0;
}
- raw_pci_ext_ops = &pci_mmcfg;
-
return 1;
}
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Jon Masters <jcm@redhat.com> |
|---|---|
| Date | 2015-10-30 05:10 +0100 |
| Subject | Re: [PATCH V1 00/11] MMCONFIG refactoring and ARM64 PCI hostbridge init based on ACPI |
| Message-ID | <qp9aN-12S-3@gated-at.bofh.it> |
| In reply to | #1256927 |
Hi Tomasz, Thanks for posting this series. On 10/27/2015 12:38 PM, Tomasz Nowicki wrote: > From the functionality point of view this series might be split into two logic parts: > 1. Making MMCONFIG code arch-agnostic which allows all architectures to collect > PCI config regions and used when necessary. > 2. Using generic MMCONFIG code and introducing ACPI based PCI hostbridge > initialization for ARM64 Can I confirm that the intention here is that this replaces Hanjun's previous patch series? Here's the previous one we were tracking: https://lkml.kernel.org/g/1432644564-24746-1-git-send-email-hanjun.guo@linaro.org Assuming that is the case, then we will ping a number of folks to conduct testing and provide acks (this has already been discussed in a number of conversations with semiconductors over the past few days). Thanks, Jon. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Hanjun Guo <guohanjun@huawei.com> |
|---|---|
| Date | 2015-10-30 06:00 +0100 |
| Subject | Re: [PATCH V1 00/11] MMCONFIG refactoring and ARM64 PCI hostbridge init based on ACPI |
| Message-ID | <qp9Xc-1ia-3@gated-at.bofh.it> |
| In reply to | #1259194 |
Hi Jon, On 2015/10/30 12:07, Jon Masters wrote: > Hi Tomasz, > > Thanks for posting this series. > > On 10/27/2015 12:38 PM, Tomasz Nowicki wrote: > >> From the functionality point of view this series might be split into two logic parts: >> 1. Making MMCONFIG code arch-agnostic which allows all architectures to collect >> PCI config regions and used when necessary. >> 2. Using generic MMCONFIG code and introducing ACPI based PCI hostbridge >> initialization for ARM64 > Can I confirm that the intention here is that this replaces Hanjun's > previous patch series? Here's the previous one we were tracking: > > https://lkml.kernel.org/g/1432644564-24746-1-git-send-email-hanjun.guo@linaro.org Yes, that's the new version according to the discussion from my version. > > Assuming that is the case, then we will ping a number of folks to > conduct testing and provide acks (this has already been discussed in a > number of conversations with semiconductors over the past few days). Much appreciated. Thanks Hanjun -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tomasz Nowicki <tn@semihalf.com> |
|---|---|
| Date | 2015-10-30 09:30 +0100 |
| Subject | Re: [PATCH V1 00/11] MMCONFIG refactoring and ARM64 PCI hostbridge init based on ACPI |
| Message-ID | <qpdeq-3t7-29@gated-at.bofh.it> |
| In reply to | #1259194 |
On 10/30/2015 05:07 AM, Jon Masters wrote: > Hi Tomasz, > > Thanks for posting this series. > > On 10/27/2015 12:38 PM, Tomasz Nowicki wrote: > >> From the functionality point of view this series might be split into two logic parts: >> 1. Making MMCONFIG code arch-agnostic which allows all architectures to collect >> PCI config regions and used when necessary. >> 2. Using generic MMCONFIG code and introducing ACPI based PCI hostbridge >> initialization for ARM64 > Can I confirm that the intention here is that this replaces Hanjun's > previous patch series? Here's the previous one we were tracking: > > https://lkml.kernel.org/g/1432644564-24746-1-git-send-email-hanjun.guo@linaro.org Indeed, we can call it next version. > > Assuming that is the case, then we will ping a number of folks to > conduct testing and provide acks (this has already been discussed in a > number of conversations with semiconductors over the past few days). Yes, please, thanks! Tomasz -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web