Subject: linux/pci: reserve io/memory space for bridge From: http://xenbits.xensource.com/linux-2.6.18-xen.hg (tip 1010:10eae161c153) Patch-mainline: n/a reserve io/memory space for bridge which will be used later by PCI hotplug. Signed-off-by: Isaku Yamahata Acked-by: jbeulich@novell.com --- head-2011-03-11.orig/Documentation/kernel-parameters.txt 2011-03-11 10:49:08.000000000 +0100 +++ head-2011-03-11/Documentation/kernel-parameters.txt 2011-03-11 10:49:17.000000000 +0100 @@ -2010,6 +2010,13 @@ bytes respectively. Such letter suffixes off: Turn ECRC off on: Turn ECRC on. + pci_reserve= [PCI] + Format: [[+IO][+MEM]][,...] + Format of sbdf: [:]:. + Specifies the least reserved io size or memory size + which is assigned to PCI bridge even when no child + pci device exists. This is useful with PCI hotplug. + pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power Management. off Disable ASPM. --- head-2011-03-11.orig/drivers/pci/Kconfig 2011-01-31 14:31:27.000000000 +0100 +++ head-2011-03-11/drivers/pci/Kconfig 2011-01-31 14:32:40.000000000 +0100 @@ -45,6 +45,13 @@ config PCI_IOMULTI help Say Y here if you need io multiplexing. +config PCI_RESERVE + bool "PCI IO/MEMORY space reserve" + depends on PCI && XEN_PRIVILEGED_GUEST + default y + help + Say Y here if you need PCI IO/MEMORY space reserve + config PCI_STUB tristate "PCI Stub driver" depends on PCI --- head-2011-03-11.orig/drivers/pci/Makefile 2011-01-31 14:31:28.000000000 +0100 +++ head-2011-03-11/drivers/pci/Makefile 2011-01-31 14:32:40.000000000 +0100 @@ -11,6 +11,7 @@ obj-$(CONFIG_PCI_GUESTDEV) += guestdev.o obj-$(CONFIG_PCI_IOMULTI) += pci-iomul.o iomul-$(CONFIG_PCI_IOMULTI) := iomulti.o obj-y += $(iomul-y) $(iomul-m) +obj-$(CONFIG_PCI_RESERVE) += reserve.o obj-$(CONFIG_PCI_QUIRKS) += quirks.o --- head-2011-03-11.orig/drivers/pci/pci.h 2011-01-31 14:31:28.000000000 +0100 +++ head-2011-03-11/drivers/pci/pci.h 2011-01-31 14:32:40.000000000 +0100 @@ -357,4 +357,19 @@ extern int pci_is_iomuldev(struct pci_de #define pci_is_iomuldev(dev) 0 #endif +#ifdef CONFIG_PCI_RESERVE +unsigned long pci_reserve_size_io(struct pci_bus *bus); +unsigned long pci_reserve_size_mem(struct pci_bus *bus); +#else +static inline unsigned long pci_reserve_size_io(struct pci_bus *bus) +{ + return 0; +} + +static inline unsigned long pci_reserve_size_mem(struct pci_bus *bus) +{ + return 0; +} +#endif /* CONFIG_PCI_RESERVE */ + #endif /* DRIVERS_PCI_H */ --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ head-2011-03-11/drivers/pci/reserve.c 2011-01-31 14:32:40.000000000 +0100 @@ -0,0 +1,137 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (c) 2009 Isaku Yamahata + * VA Linux Systems Japan K.K. + */ + +#include +#include + +#include + +static char pci_reserve_param[COMMAND_LINE_SIZE]; + +/* pci_reserve= [PCI] + * Format: [[+IO][+MEM]][,...] + * Format of sbdf: [:]:. + */ +static int pci_reserve_parse_size(const char *str, + unsigned long *io_size, + unsigned long *mem_size) +{ + if (sscanf(str, "io%lx", io_size) == 1 || + sscanf(str, "IO%lx", io_size) == 1) + return 0; + + if (sscanf(str, "mem%lx", mem_size) == 1 || + sscanf(str, "MEM%lx", mem_size) == 1) + return 0; + + return -EINVAL; +} + +static int pci_reserve_parse_one(const char *str, + int *seg, int *bus, int *dev, int *func, + unsigned long *io_size, + unsigned long *mem_size) +{ + char *p; + + *io_size = 0; + *mem_size = 0; + + if (sscanf(str, "%x:%x:%x.%x", seg, bus, dev, func) != 4) { + *seg = 0; + if (sscanf(str, "%x:%x.%x", bus, dev, func) != 3) { + return -EINVAL; + } + } + + p = strchr(str, '+'); + if (p == NULL) + return -EINVAL; + if (pci_reserve_parse_size(++p, io_size, mem_size)) + return -EINVAL; + + p = strchr(p, '+'); + return p ? pci_reserve_parse_size(p + 1, io_size, mem_size) : 0; +} + +static unsigned long pci_reserve_size(struct pci_bus *pbus, int flags) +{ + char *sp; + char *ep; + + int seg; + int bus; + int dev; + int func; + + unsigned long io_size; + unsigned long mem_size; + + sp = pci_reserve_param; + + do { + ep = strchr(sp, ','); + if (ep) + *ep = '\0'; /* chomp */ + + if (pci_reserve_parse_one(sp, &seg, &bus, &dev, &func, + &io_size, &mem_size) == 0) { + if (pci_domain_nr(pbus) == seg && + pbus->number == bus && + PCI_SLOT(pbus->self->devfn) == dev && + PCI_FUNC(pbus->self->devfn) == func) { + switch (flags) { + case IORESOURCE_IO: + return io_size; + case IORESOURCE_MEM: + return mem_size; + default: + break; + } + } + } + + if (ep) { + *ep = ','; /* restore chomp'ed ',' for later */ + ep++; + } + sp = ep; + } while (ep); + + return 0; +} + +unsigned long pci_reserve_size_io(struct pci_bus *pbus) +{ + return pci_reserve_size(pbus, IORESOURCE_IO); +} + +unsigned long pci_reserve_size_mem(struct pci_bus *pbus) +{ + return pci_reserve_size(pbus, IORESOURCE_MEM); +} + +static int __init pci_reserve_setup(char *str) +{ + if (strlen(str) >= sizeof(pci_reserve_param)) + return 0; + strlcpy(pci_reserve_param, str, sizeof(pci_reserve_param)); + return 1; +} +__setup("pci_reserve=", pci_reserve_setup); --- head-2011-03-11.orig/drivers/pci/setup-bus.c 2011-03-11 10:41:54.000000000 +0100 +++ head-2011-03-11/drivers/pci/setup-bus.c 2011-01-31 14:32:40.000000000 +0100 @@ -448,6 +448,9 @@ static void pbus_size_io(struct pci_bus size = ALIGN(size + size1, 4096); if (size < old_size) size = old_size; + size1 = pci_reserve_size_io(bus); + if (size < size1) + size = ALIGN(size1, 4096); if (!size) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " @@ -537,7 +540,8 @@ static int pbus_size_mem(struct pci_bus min_align = align1 >> 1; align += aligns[order]; } - size = ALIGN(size, min_align); + size = ALIGN(max(size, (resource_size_t)pci_reserve_size_mem(bus)), + min_align); if (!size) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window "