ia64/linux-2.6.18-xen.hg

changeset 884:c7c92f868aa1

linux/pci: reserve io/memory space for bridge

reserve io/memory space for bridge which will be used later
by PCI hotplug.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 28 10:00:03 2009 +0100 (2009-05-28)
parents b998614e2e2a
children a4b49dff3387
files Documentation/kernel-parameters.txt drivers/pci/Kconfig drivers/pci/Makefile drivers/pci/pci.h drivers/pci/reserve.c drivers/pci/setup-bus.c
line diff
     1.1 --- a/Documentation/kernel-parameters.txt	Thu May 28 09:59:18 2009 +0100
     1.2 +++ b/Documentation/kernel-parameters.txt	Thu May 28 10:00:03 2009 +0100
     1.3 @@ -1259,6 +1259,13 @@ running once the system is up.
     1.4  				IXP2000 systems where the bus has to be
     1.5  				configured a certain way for adjunct CPUs.
     1.6  
     1.7 +	pci_reserve=	[PCI]
     1.8 +			Format: [<sbdf>[+IO<size>][+MEM<size>]][,<sbdf>...]
     1.9 +			Format of sbdf: [<segment>:]<bus>:<dev>.<func>
    1.10 +			Specifies the least reserved io size or memory size
    1.11 +			which is assigned to PCI bridge even when no child
    1.12 +			pci device exists. This is useful with PCI hotplug.
    1.13 +
    1.14  	pcmv=		[HW,PCMCIA] BadgePAD 4
    1.15  
    1.16  	pd.		[PARIDE]
     2.1 --- a/drivers/pci/Kconfig	Thu May 28 09:59:18 2009 +0100
     2.2 +++ b/drivers/pci/Kconfig	Thu May 28 10:00:03 2009 +0100
     2.3 @@ -43,6 +43,14 @@ config PCI_IOMULTI
     2.4  	default y
     2.5  	help
     2.6  	  Say Y here if you need io multiplexing.
     2.7 +
     2.8 +config PCI_RESERVE
     2.9 +	bool "PCI IO/MEMORY space reserve"
    2.10 +	depends on PCI
    2.11 +	default y
    2.12 +	help
    2.13 +	  Say Y here if you need PCI IO/MEMORY space reserve
    2.14 +
    2.15  config PCI_IOV
    2.16  	bool "PCI IOV support"
    2.17  	depends on PCI
     3.1 --- a/drivers/pci/Makefile	Thu May 28 09:59:18 2009 +0100
     3.2 +++ b/drivers/pci/Makefile	Thu May 28 10:00:03 2009 +0100
     3.3 @@ -7,6 +7,7 @@ obj-y		+= access.o bus.o probe.o remove.
     3.4  obj-$(CONFIG_PROC_FS) += proc.o
     3.5  obj-$(CONFIG_PCI_GUESTDEV) += guestdev.o
     3.6  obj-$(CONFIG_PCI_IOMULTI) += iomulti.o
     3.7 +obj-$(CONFIG_PCI_RESERVE) += reserve.o
     3.8  
     3.9  # Build PCI Express stuff if needed
    3.10  obj-$(CONFIG_PCIEPORTBUS) += pcie/
     4.1 --- a/drivers/pci/pci.h	Thu May 28 09:59:18 2009 +0100
     4.2 +++ b/drivers/pci/pci.h	Thu May 28 10:00:03 2009 +0100
     4.3 @@ -189,3 +189,18 @@ static inline int pci_iov_bus_range(stru
     4.4  	return 0;
     4.5  }
     4.6  #endif /* CONFIG_PCI_IOV */
     4.7 +
     4.8 +#ifdef CONFIG_PCI_RESERVE
     4.9 +unsigned long pci_reserve_size_io(struct pci_bus *bus);
    4.10 +unsigned long pci_reserve_size_mem(struct pci_bus *bus);
    4.11 +#else
    4.12 +static inline unsigned long pci_reserve_size_io(struct pci_bus *bus)
    4.13 +{
    4.14 +	return 0;
    4.15 +}
    4.16 +
    4.17 +static inline unsigned long pci_reserve_size_mem(struct pci_bus *bus)
    4.18 +{
    4.19 +	return 0;
    4.20 +}
    4.21 +#endif /* CONFIG_PCI_RESERVE */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/drivers/pci/reserve.c	Thu May 28 10:00:03 2009 +0100
     5.3 @@ -0,0 +1,143 @@
     5.4 +/*
     5.5 + * This program is free software; you can redistribute it and/or modify
     5.6 + * it under the terms of the GNU General Public License as published by
     5.7 + * the Free Software Foundation; either version 2 of the License, or
     5.8 + * (at your option) any later version.
     5.9 + *
    5.10 + * This program is distributed in the hope that it will be useful,
    5.11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.13 + * GNU General Public License for more details.
    5.14 + *
    5.15 + * You should have received a copy of the GNU General Public License
    5.16 + * along with this program; if not, write to the Free Software
    5.17 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    5.18 + *
    5.19 + * Copyright (c) 2009 Isaku Yamahata
    5.20 + *                    VA Linux Systems Japan K.K.
    5.21 + *
    5.22 + */
    5.23 +
    5.24 +#include <linux/kernel.h>
    5.25 +#include <linux/pci.h>
    5.26 +
    5.27 +#include <asm/setup.h>
    5.28 +
    5.29 +static char pci_reserve_param[COMMAND_LINE_SIZE];
    5.30 +
    5.31 +/* pci_reserve=	[PCI]
    5.32 + * Format: [<sbdf>[+IO<size>][+MEM<size>]][,<sbdf>...]
    5.33 + * Format of sbdf: [<segment>:]<bus>:<dev>.<func>
    5.34 + */
    5.35 +static int pci_reserve_parse_size(const char *str,
    5.36 +				  unsigned long *io_size,
    5.37 +				  unsigned long *mem_size)
    5.38 +{
    5.39 +	if (sscanf(str, "io%lx", io_size) == 1 ||
    5.40 +	    sscanf(str, "IO%lx", io_size) == 1)
    5.41 +		return 0;
    5.42 +
    5.43 +	if (sscanf(str, "mem%lx", mem_size) == 1 ||
    5.44 +	    sscanf(str, "MEM%lx", mem_size) == 1)
    5.45 +		return 0;
    5.46 +
    5.47 +	return -EINVAL;
    5.48 +}
    5.49 +
    5.50 +static int pci_reserve_parse_one(const char *str,
    5.51 +				 int *seg, int *bus, int *dev, int *func,
    5.52 +				 unsigned long *io_size,
    5.53 +				 unsigned long *mem_size)
    5.54 +{
    5.55 +	char *p;
    5.56 +
    5.57 +	*io_size = 0;
    5.58 +	*mem_size = 0;
    5.59 +
    5.60 +	if (sscanf(str, "%x:%x:%x.%x", seg, bus, dev, func) != 4) {
    5.61 +		*seg = 0;
    5.62 +		if (sscanf(str, "%x:%x.%x", bus, dev, func) != 3) {
    5.63 +			return -EINVAL;
    5.64 +		}
    5.65 +	}
    5.66 +
    5.67 +	p = strchr(str, '+');
    5.68 +	if (p == NULL)
    5.69 +		return -EINVAL;
    5.70 +	p++;
    5.71 +	if (pci_reserve_parse_size(p, io_size, mem_size))
    5.72 +		return -EINVAL;
    5.73 +
    5.74 +	p = strchr(str, '+');
    5.75 +	if (p != NULL) {
    5.76 +		p++;
    5.77 +		pci_reserve_parse_size(p, io_size, mem_size);
    5.78 +	}
    5.79 +	return 0;
    5.80 +}
    5.81 +
    5.82 +static unsigned long pci_reserve_size(struct pci_bus *pbus, int flags)
    5.83 +{
    5.84 +	char *sp;
    5.85 +	char *ep;
    5.86 +
    5.87 +	int seg;
    5.88 +	int bus;
    5.89 +	int dev;
    5.90 +	int func;
    5.91 +
    5.92 +	unsigned long io_size;
    5.93 +	unsigned long mem_size;
    5.94 +
    5.95 +	sp = pci_reserve_param;
    5.96 +
    5.97 +	do {
    5.98 +		ep = strchr(sp, ',');
    5.99 +		if (ep)
   5.100 +			*ep = '\0';	/* chomp */
   5.101 +
   5.102 +		if (pci_reserve_parse_one(sp, &seg, &bus, &dev, &func,
   5.103 +					  &io_size, &mem_size) == 0) {
   5.104 +			if (pci_domain_nr(pbus) == seg &&
   5.105 +			    pbus->number == bus &&
   5.106 +			    PCI_SLOT(pbus->self->devfn) == dev &&
   5.107 +			    PCI_FUNC(pbus->self->devfn) == func) {
   5.108 +				switch (flags) {
   5.109 +				case IORESOURCE_IO:
   5.110 +					return io_size;
   5.111 +				case IORESOURCE_MEM:
   5.112 +					return mem_size;
   5.113 +				default:
   5.114 +					break;
   5.115 +				}
   5.116 +			}
   5.117 +		}
   5.118 +
   5.119 +		if (ep) {
   5.120 +			*ep = ',';	/* restore chomp'ed ',' for later */
   5.121 +			ep++;
   5.122 +		}
   5.123 +		sp = ep;
   5.124 +	} while (ep);
   5.125 +
   5.126 +	return 0;
   5.127 +}
   5.128 +
   5.129 +unsigned long pci_reserve_size_io(struct pci_bus *pbus)
   5.130 +{
   5.131 +	return pci_reserve_size(pbus, IORESOURCE_IO);
   5.132 +}
   5.133 +
   5.134 +unsigned long pci_reserve_size_mem(struct pci_bus *pbus)
   5.135 +{
   5.136 +	return pci_reserve_size(pbus, IORESOURCE_MEM);
   5.137 +}
   5.138 +
   5.139 +static int __init pci_reserve_setup(char *str)
   5.140 +{
   5.141 +	if (strlen(str) > sizeof(pci_reserve_param))
   5.142 +		return 0;
   5.143 +	strcpy(pci_reserve_param, str);
   5.144 +	return 1;
   5.145 +}
   5.146 +__setup("pci_reserve=", pci_reserve_setup);
     6.1 --- a/drivers/pci/setup-bus.c	Thu May 28 09:59:18 2009 +0100
     6.2 +++ b/drivers/pci/setup-bus.c	Thu May 28 10:00:03 2009 +0100
     6.3 @@ -315,7 +315,7 @@ pbus_size_io(struct pci_bus *bus)
     6.4  #if defined(CONFIG_ISA) || defined(CONFIG_EISA)
     6.5  	size = (size & 0xff) + ((size & ~0xffUL) << 2);
     6.6  #endif
     6.7 -	size = ROUND_UP(size + size1, 4096);
     6.8 +	size = ROUND_UP(max(size + size1, pci_reserve_size_io(bus)), 4096);
     6.9  	if (!size) {
    6.10  		b_res->flags = 0;
    6.11  		return;
    6.12 @@ -393,7 +393,7 @@ pbus_size_mem(struct pci_bus *bus, unsig
    6.13  			min_align = align1 >> 1;
    6.14  		align += aligns[order];
    6.15  	}
    6.16 -	size = ROUND_UP(size, min_align);
    6.17 +	size = ROUND_UP(max(size, pci_reserve_size_mem(bus)), min_align);
    6.18  	if (!size) {
    6.19  		b_res->flags = 0;
    6.20  		return 1;