[PATCH 5/6] PCI, x86: introduce pci_mmcongi_add() / pci_mmconfig_delete()

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

 



This patch replaces pci_mmconfig_add() and introduces pci_mmconfig_delte()
for adding or deleting MCFG region.

The newly pci_mmconfig_add() does the following:
  - region check
  - insert_resource
  - ioremap
  - add new pci_mmcfg_region entry to pci_mmcfg_list

Signed-off-by: Taku Izumi <izumi.taku@xxxxxxxxxxxxxx>
---
 arch/x86/include/asm/pci_x86.h |    3 
 arch/x86/pci/mmconfig-shared.c |  142 ++++++++++++++++++++++++++++++-----------
 arch/x86/pci/mmconfig_64.c     |   11 ---
 3 files changed, 109 insertions(+), 47 deletions(-)

Index: bjorn-next/arch/x86/include/asm/pci_x86.h
===================================================================
--- bjorn-next.orig/arch/x86/include/asm/pci_x86.h
+++ bjorn-next/arch/x86/include/asm/pci_x86.h
@@ -138,7 +138,8 @@ extern void __init pci_mmcfg_arch_free(v
 extern int __devinit pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
 extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
 extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
-
+extern int __devinit pci_mmconfig_add(int seg, int start, int end, u64 addr);
+extern int pci_mmconfig_delete(int seg, int start, int end);
 extern struct list_head pci_mmcfg_list;
 
 #define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
Index: bjorn-next/arch/x86/pci/mmconfig-shared.c
===================================================================
--- bjorn-next.orig/arch/x86/pci/mmconfig-shared.c
+++ bjorn-next/arch/x86/pci/mmconfig-shared.c
@@ -17,6 +17,7 @@
 #include <linux/bitmap.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 #include <linux/rculist.h>
 #include <asm/e820.h>
 #include <asm/pci_x86.h>
@@ -96,18 +97,6 @@ static __devinit struct pci_mmcfg_region
 	return new;
 }
 
-static __init 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)
-		list_add_sorted(new);
-
-	return new;
-}
-
 struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
 {
 	struct pci_mmcfg_region *cfg;
@@ -129,7 +118,7 @@ static const char __init *pci_mmcfg_e752
 	if (win == 0x0000 || win == 0xf000)
 		return NULL;
 
-	if (pci_mmconfig_add(0, 0, 255, win << 16) == NULL)
+	if (pci_mmconfig_add(0, 0, 255, win << 16))
 		return NULL;
 
 	return "Intel Corporation E7520 Memory Controller Hub";
@@ -173,7 +162,7 @@ static const char __init *pci_mmcfg_inte
 	if ((pciexbar & mask) >= 0xf0000000U)
 		return NULL;
 
-	if (pci_mmconfig_add(0, 0, (len >> 20) - 1, pciexbar & mask) == NULL)
+	if (pci_mmconfig_add(0, 0, (len >> 20) - 1, pciexbar & mask))
 		return NULL;
 
 	return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
@@ -221,7 +210,7 @@ static const char __init *pci_mmcfg_amd_
 	end_bus = (1 << busnbits) - 1;
 	for (i = 0; i < (1 << segnbits); i++)
 		if (pci_mmconfig_add(i, 0, end_bus,
-				     base + (1<<28) * i) == NULL) {
+				     base + (1<<28) * i)) {
 			free_all_mmcfg();
 			return NULL;
 		}
@@ -278,7 +267,7 @@ static const char __init *pci_mmcfg_nvid
 		base <<= extcfg_base_lshift;
 		start = (extcfg & extcfg_start_mask) >> extcfg_start_shift;
 		end = start + extcfg_sizebus[size_index] - 1;
-		if (pci_mmconfig_add(0, start, end, base) == NULL)
+		if (pci_mmconfig_add(0, start, end, base))
 			continue;
 		mcp55_mmconf_found++;
 	}
@@ -376,7 +365,7 @@ static void __init pci_mmcfg_insert_reso
 	pci_mmcfg_resources_inserted = 1;
 }
 
-static acpi_status __init check_mcfg_resource(struct acpi_resource *res,
+static acpi_status __devinit check_mcfg_resource(struct acpi_resource *res,
 					      void *data)
 {
 	struct resource *mcfg_res = data;
@@ -413,7 +402,7 @@ static acpi_status __init check_mcfg_res
 	return AE_OK;
 }
 
-static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
+static acpi_status __devinit find_mboard_resource(acpi_handle handle, u32 lvl,
 		void *context, void **rv)
 {
 	struct resource *mcfg_res = context;
@@ -427,7 +416,7 @@ static acpi_status __init find_mboard_re
 	return AE_OK;
 }
 
-static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
+static int __devinit is_acpi_reserved(u64 start, u64 end, unsigned not_used)
 {
 	struct resource mcfg_res;
 
@@ -446,7 +435,7 @@ static int __init is_acpi_reserved(u64 s
 
 typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
 
-static int __init is_mmconf_reserved(check_reserved_t is_reserved,
+static int __devinit is_mmconf_reserved(check_reserved_t is_reserved,
 				    struct pci_mmcfg_region *cfg, int with_e820)
 {
 	u64 addr = cfg->res.start;
@@ -507,19 +496,6 @@ static int __devinit pci_mmcfg_check_res
 	return false;
 }
 
-static void __init pci_mmcfg_reject_broken(int early)
-{
-	struct pci_mmcfg_region *cfg;
-
-	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
-		if (pci_mmcfg_check_reserved(cfg, early) == false) {
-			printk(KERN_INFO PREFIX "not using MMCONFIG\n");
-			free_all_mmcfg();
-			return;
-		}
-	}
-}
-
 static int __initdata known_bridge;
 
 static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
@@ -613,8 +589,6 @@ static void __init __pci_mmcfg_init(int 
 	if (!known_bridge)
 		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
 
-	pci_mmcfg_reject_broken(early);
-
 	if (list_empty(&pci_mmcfg_list))
 		return;
 
@@ -676,3 +650,101 @@ static int __init pci_mmcfg_late_insert_
  * with other system resources.
  */
 late_initcall(pci_mmcfg_late_insert_resources);
+
+static DEFINE_MUTEX(pci_mmcfg_lock);
+
+int __devinit pci_mmconfig_add(int segment, int start, int end, u64 addr)
+{
+	int rc = 0;
+	struct pci_mmcfg_region *cfg, *new = NULL;
+
+	if (segment < 0 || segment > USHRT_MAX ||
+	    start < 0 || start > 255 || end < start || end > 255)
+		return -EINVAL;
+
+	mutex_lock(&pci_mmcfg_lock);
+	cfg = pci_mmconfig_lookup(segment, start);
+	if (cfg) {
+		if (cfg->start_bus <= start && cfg->end_bus >= end) {
+			rc = -EEXIST;
+		} else {
+			rc = -EINVAL;
+			printk(KERN_WARNING PREFIX
+			       "MMCONFIG for domain %04x [bus %02x-%02x] "
+			       "conflicts with domain %04x [bus %02x-%02x]\n",
+			       segment, start, end,
+			       cfg->segment, cfg->start_bus, cfg->end_bus);
+		}
+		goto out;
+	}
+
+	new = pci_mmconfig_alloc(segment, start, end, addr);
+	if (new == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	if (!pci_mmcfg_check_reserved(new, 0)) {
+		rc = -EINVAL;
+		printk(KERN_WARNING PREFIX
+		       "MMCONFIG for domain %04x [bus %02x-%02x] "
+		       "isn't reserved\n", segment, start, end);
+		goto out;
+	}
+
+	if (pci_mmcfg_resources_inserted &&
+	    insert_resource(&iomem_resource, &new->res)) {
+		rc = -EBUSY;
+		printk(KERN_WARNING PREFIX
+		       "failed to insert resource for domain "
+		       "%04x [bus %02x-%02x]\n", segment, start, end);
+		goto out;
+	}
+
+	if (pci_mmcfg_arch_map(new)) {
+		rc = -EBUSY;
+		printk(KERN_WARNING PREFIX
+		       "failed to map resource for domain "
+		       "%04x [bus %02x-%02x]\n", segment, start, end);
+		goto out;
+	}
+
+	list_add_sorted(new);
+	new = NULL;
+
+out:
+	if (new) {
+		if (new->res.parent)
+			release_resource(&new->res);
+		kfree(new);
+	}
+
+	mutex_unlock(&pci_mmcfg_lock);
+
+	return rc;
+}
+
+/* Delete MMCFG information at runtime */
+int pci_mmconfig_delete(int segment, int start, int end)
+{
+	struct pci_mmcfg_region *cfg;
+
+	mutex_lock(&pci_mmcfg_lock);
+	list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
+		if (cfg->segment == segment && 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;
+}
+
Index: bjorn-next/arch/x86/pci/mmconfig_64.c
===================================================================
--- bjorn-next.orig/arch/x86/pci/mmconfig_64.c
+++ bjorn-next/arch/x86/pci/mmconfig_64.c
@@ -112,17 +112,6 @@ static void __iomem * __devinit mcfg_ior
 
 int __init pci_mmcfg_arch_init(void)
 {
-	struct pci_mmcfg_region *cfg;
-
-	list_for_each_entry(cfg, &pci_mmcfg_list, list) {
-		cfg->virt = mcfg_ioremap(cfg);
-		if (!cfg->virt) {
-			printk(KERN_ERR PREFIX "can't map MMCONFIG at %pR\n",
-			       &cfg->res);
-			pci_mmcfg_arch_free();
-			return 0;
-		}
-	}
 	raw_pci_ext_ops = &pci_mmcfg;
 	return 1;
 }

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


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

  Powered by Linux