ia64/xen-unstable

changeset 6843:1184286a2ee6

Fix mmapping of PCI resources from userspace.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Sep 14 17:54:43 2005 +0000 (2005-09-14)
parents 9c9a3bb878c2
children 1a29e0f5c610
files linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c linux-2.6-xen-sparse/arch/xen/kernel/devmem.c linux-2.6-xen-sparse/arch/xen/x86_64/pci/Makefile
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Wed Sep 14 17:06:37 2005 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/Makefile	Wed Sep 14 17:54:43 2005 +0000
     1.3 @@ -2,7 +2,7 @@ XENARCH	:= $(subst ",,$(CONFIG_XENARCH))
     1.4  
     1.5  CFLAGS	+= -Iarch/$(XENARCH)/pci
     1.6  
     1.7 -c-obj-y				:= i386.o
     1.8 +obj-y				:= i386.o
     1.9  
    1.10  #c-obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
    1.11  c-obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig.o
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/linux-2.6-xen-sparse/arch/xen/i386/pci/i386.c	Wed Sep 14 17:54:43 2005 +0000
     2.3 @@ -0,0 +1,304 @@
     2.4 +/*
     2.5 + *	Low-Level PCI Access for i386 machines
     2.6 + *
     2.7 + * Copyright 1993, 1994 Drew Eckhardt
     2.8 + *      Visionary Computing
     2.9 + *      (Unix and Linux consulting and custom programming)
    2.10 + *      Drew@Colorado.EDU
    2.11 + *      +1 (303) 786-7975
    2.12 + *
    2.13 + * Drew's work was sponsored by:
    2.14 + *	iX Multiuser Multitasking Magazine
    2.15 + *	Hannover, Germany
    2.16 + *	hm@ix.de
    2.17 + *
    2.18 + * Copyright 1997--2000 Martin Mares <mj@ucw.cz>
    2.19 + *
    2.20 + * For more information, please consult the following manuals (look at
    2.21 + * http://www.pcisig.com/ for how to get them):
    2.22 + *
    2.23 + * PCI BIOS Specification
    2.24 + * PCI Local Bus Specification
    2.25 + * PCI to PCI Bridge Specification
    2.26 + * PCI System Design Guide
    2.27 + *
    2.28 + */
    2.29 +
    2.30 +#include <linux/types.h>
    2.31 +#include <linux/kernel.h>
    2.32 +#include <linux/pci.h>
    2.33 +#include <linux/init.h>
    2.34 +#include <linux/ioport.h>
    2.35 +#include <linux/errno.h>
    2.36 +
    2.37 +#include "pci.h"
    2.38 +
    2.39 +/*
    2.40 + * We need to avoid collisions with `mirrored' VGA ports
    2.41 + * and other strange ISA hardware, so we always want the
    2.42 + * addresses to be allocated in the 0x000-0x0ff region
    2.43 + * modulo 0x400.
    2.44 + *
    2.45 + * Why? Because some silly external IO cards only decode
    2.46 + * the low 10 bits of the IO address. The 0x00-0xff region
    2.47 + * is reserved for motherboard devices that decode all 16
    2.48 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
    2.49 + * but we want to try to avoid allocating at 0x2900-0x2bff
    2.50 + * which might have be mirrored at 0x0100-0x03ff..
    2.51 + */
    2.52 +void
    2.53 +pcibios_align_resource(void *data, struct resource *res,
    2.54 +		       unsigned long size, unsigned long align)
    2.55 +{
    2.56 +	if (res->flags & IORESOURCE_IO) {
    2.57 +		unsigned long start = res->start;
    2.58 +
    2.59 +		if (start & 0x300) {
    2.60 +			start = (start + 0x3ff) & ~0x3ff;
    2.61 +			res->start = start;
    2.62 +		}
    2.63 +	}
    2.64 +}
    2.65 +
    2.66 +
    2.67 +/*
    2.68 + *  Handle resources of PCI devices.  If the world were perfect, we could
    2.69 + *  just allocate all the resource regions and do nothing more.  It isn't.
    2.70 + *  On the other hand, we cannot just re-allocate all devices, as it would
    2.71 + *  require us to know lots of host bridge internals.  So we attempt to
    2.72 + *  keep as much of the original configuration as possible, but tweak it
    2.73 + *  when it's found to be wrong.
    2.74 + *
    2.75 + *  Known BIOS problems we have to work around:
    2.76 + *	- I/O or memory regions not configured
    2.77 + *	- regions configured, but not enabled in the command register
    2.78 + *	- bogus I/O addresses above 64K used
    2.79 + *	- expansion ROMs left enabled (this may sound harmless, but given
    2.80 + *	  the fact the PCI specs explicitly allow address decoders to be
    2.81 + *	  shared between expansion ROMs and other resource regions, it's
    2.82 + *	  at least dangerous)
    2.83 + *
    2.84 + *  Our solution:
    2.85 + *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
    2.86 + *	    This gives us fixed barriers on where we can allocate.
    2.87 + *	(2) Allocate resources for all enabled devices.  If there is
    2.88 + *	    a collision, just mark the resource as unallocated. Also
    2.89 + *	    disable expansion ROMs during this step.
    2.90 + *	(3) Try to allocate resources for disabled devices.  If the
    2.91 + *	    resources were assigned correctly, everything goes well,
    2.92 + *	    if they weren't, they won't disturb allocation of other
    2.93 + *	    resources.
    2.94 + *	(4) Assign new addresses to resources which were either
    2.95 + *	    not configured at all or misconfigured.  If explicitly
    2.96 + *	    requested by the user, configure expansion ROM address
    2.97 + *	    as well.
    2.98 + */
    2.99 +
   2.100 +static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
   2.101 +{
   2.102 +	struct pci_bus *bus;
   2.103 +	struct pci_dev *dev;
   2.104 +	int idx;
   2.105 +	struct resource *r, *pr;
   2.106 +
   2.107 +	/* Depth-First Search on bus tree */
   2.108 +	list_for_each_entry(bus, bus_list, node) {
   2.109 +		if ((dev = bus->self)) {
   2.110 +			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
   2.111 +				r = &dev->resource[idx];
   2.112 +				if (!r->start)
   2.113 +					continue;
   2.114 +				pr = pci_find_parent_resource(dev, r);
   2.115 +				if (!pr || request_resource(pr, r) < 0)
   2.116 +					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev));
   2.117 +			}
   2.118 +		}
   2.119 +		pcibios_allocate_bus_resources(&bus->children);
   2.120 +	}
   2.121 +}
   2.122 +
   2.123 +static void __init pcibios_allocate_resources(int pass)
   2.124 +{
   2.125 +	struct pci_dev *dev = NULL;
   2.126 +	int idx, disabled;
   2.127 +	u16 command;
   2.128 +	struct resource *r, *pr;
   2.129 +
   2.130 +	for_each_pci_dev(dev) {
   2.131 +		pci_read_config_word(dev, PCI_COMMAND, &command);
   2.132 +		for(idx = 0; idx < 6; idx++) {
   2.133 +			r = &dev->resource[idx];
   2.134 +			if (r->parent)		/* Already allocated */
   2.135 +				continue;
   2.136 +			if (!r->start)		/* Address not assigned at all */
   2.137 +				continue;
   2.138 +			if (r->flags & IORESOURCE_IO)
   2.139 +				disabled = !(command & PCI_COMMAND_IO);
   2.140 +			else
   2.141 +				disabled = !(command & PCI_COMMAND_MEMORY);
   2.142 +			if (pass == disabled) {
   2.143 +				DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
   2.144 +				    r->start, r->end, r->flags, disabled, pass);
   2.145 +				pr = pci_find_parent_resource(dev, r);
   2.146 +				if (!pr || request_resource(pr, r) < 0) {
   2.147 +					printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, pci_name(dev));
   2.148 +					/* We'll assign a new address later */
   2.149 +					r->end -= r->start;
   2.150 +					r->start = 0;
   2.151 +				}
   2.152 +			}
   2.153 +		}
   2.154 +		if (!pass) {
   2.155 +			r = &dev->resource[PCI_ROM_RESOURCE];
   2.156 +			if (r->flags & IORESOURCE_ROM_ENABLE) {
   2.157 +				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
   2.158 +				u32 reg;
   2.159 +				DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
   2.160 +				r->flags &= ~IORESOURCE_ROM_ENABLE;
   2.161 +				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
   2.162 +				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
   2.163 +			}
   2.164 +		}
   2.165 +	}
   2.166 +}
   2.167 +
   2.168 +static int __init pcibios_assign_resources(void)
   2.169 +{
   2.170 +	struct pci_dev *dev = NULL;
   2.171 +	int idx;
   2.172 +	struct resource *r;
   2.173 +
   2.174 +	for_each_pci_dev(dev) {
   2.175 +		int class = dev->class >> 8;
   2.176 +
   2.177 +		/* Don't touch classless devices and host bridges */
   2.178 +		if (!class || class == PCI_CLASS_BRIDGE_HOST)
   2.179 +			continue;
   2.180 +
   2.181 +		for(idx=0; idx<6; idx++) {
   2.182 +			r = &dev->resource[idx];
   2.183 +
   2.184 +			/*
   2.185 +			 *  Don't touch IDE controllers and I/O ports of video cards!
   2.186 +			 */
   2.187 +			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
   2.188 +			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
   2.189 +				continue;
   2.190 +
   2.191 +			/*
   2.192 +			 *  We shall assign a new address to this resource, either because
   2.193 +			 *  the BIOS forgot to do so or because we have decided the old
   2.194 +			 *  address was unusable for some reason.
   2.195 +			 */
   2.196 +			if (!r->start && r->end)
   2.197 +				pci_assign_resource(dev, idx);
   2.198 +		}
   2.199 +
   2.200 +		if (pci_probe & PCI_ASSIGN_ROMS) {
   2.201 +			r = &dev->resource[PCI_ROM_RESOURCE];
   2.202 +			r->end -= r->start;
   2.203 +			r->start = 0;
   2.204 +			if (r->end)
   2.205 +				pci_assign_resource(dev, PCI_ROM_RESOURCE);
   2.206 +		}
   2.207 +	}
   2.208 +	return 0;
   2.209 +}
   2.210 +
   2.211 +void __init pcibios_resource_survey(void)
   2.212 +{
   2.213 +	DBG("PCI: Allocating resources\n");
   2.214 +	pcibios_allocate_bus_resources(&pci_root_buses);
   2.215 +	pcibios_allocate_resources(0);
   2.216 +	pcibios_allocate_resources(1);
   2.217 +}
   2.218 +
   2.219 +/**
   2.220 + * called in fs_initcall (one below subsys_initcall),
   2.221 + * give a chance for motherboard reserve resources
   2.222 + */
   2.223 +fs_initcall(pcibios_assign_resources);
   2.224 +
   2.225 +int pcibios_enable_resources(struct pci_dev *dev, int mask)
   2.226 +{
   2.227 +	u16 cmd, old_cmd;
   2.228 +	int idx;
   2.229 +	struct resource *r;
   2.230 +
   2.231 +	pci_read_config_word(dev, PCI_COMMAND, &cmd);
   2.232 +	old_cmd = cmd;
   2.233 +	for(idx=0; idx<6; idx++) {
   2.234 +		/* Only set up the requested stuff */
   2.235 +		if (!(mask & (1<<idx)))
   2.236 +			continue;
   2.237 +
   2.238 +		r = &dev->resource[idx];
   2.239 +		if (!r->start && r->end) {
   2.240 +			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
   2.241 +			return -EINVAL;
   2.242 +		}
   2.243 +		if (r->flags & IORESOURCE_IO)
   2.244 +			cmd |= PCI_COMMAND_IO;
   2.245 +		if (r->flags & IORESOURCE_MEM)
   2.246 +			cmd |= PCI_COMMAND_MEMORY;
   2.247 +	}
   2.248 +	if (dev->resource[PCI_ROM_RESOURCE].start)
   2.249 +		cmd |= PCI_COMMAND_MEMORY;
   2.250 +	if (cmd != old_cmd) {
   2.251 +		printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
   2.252 +		pci_write_config_word(dev, PCI_COMMAND, cmd);
   2.253 +	}
   2.254 +	return 0;
   2.255 +}
   2.256 +
   2.257 +/*
   2.258 + *  If we set up a device for bus mastering, we need to check the latency
   2.259 + *  timer as certain crappy BIOSes forget to set it properly.
   2.260 + */
   2.261 +unsigned int pcibios_max_latency = 255;
   2.262 +
   2.263 +void pcibios_set_master(struct pci_dev *dev)
   2.264 +{
   2.265 +	u8 lat;
   2.266 +	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
   2.267 +	if (lat < 16)
   2.268 +		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
   2.269 +	else if (lat > pcibios_max_latency)
   2.270 +		lat = pcibios_max_latency;
   2.271 +	else
   2.272 +		return;
   2.273 +	printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
   2.274 +	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
   2.275 +}
   2.276 +
   2.277 +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
   2.278 +			enum pci_mmap_state mmap_state, int write_combine)
   2.279 +{
   2.280 +	unsigned long prot;
   2.281 +
   2.282 +	/* I/O space cannot be accessed via normal processor loads and
   2.283 +	 * stores on this platform.
   2.284 +	 */
   2.285 +	if (mmap_state == pci_mmap_io)
   2.286 +		return -EINVAL;
   2.287 +
   2.288 +	/* Leave vm_pgoff as-is, the PCI space address is the physical
   2.289 +	 * address on this platform.
   2.290 +	 */
   2.291 +	vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
   2.292 +
   2.293 +	prot = pgprot_val(vma->vm_page_prot);
   2.294 +	if (boot_cpu_data.x86 > 3)
   2.295 +		prot |= _PAGE_PCD | _PAGE_PWT;
   2.296 +	vma->vm_page_prot = __pgprot(prot);
   2.297 +
   2.298 +	/* Write-combine setting is ignored, it is changed via the mtrr
   2.299 +	 * interfaces on this platform.
   2.300 +	 */
   2.301 +	if (direct_remap_pfn_range(vma->vm_mm, vma->vm_start, vma->vm_pgoff,
   2.302 +				   vma->vm_end - vma->vm_start,
   2.303 +				   vma->vm_page_prot, DOMID_IO))
   2.304 +		return -EAGAIN;
   2.305 +
   2.306 +	return 0;
   2.307 +}
     3.1 --- a/linux-2.6-xen-sparse/arch/xen/kernel/devmem.c	Wed Sep 14 17:06:37 2005 +0000
     3.2 +++ b/linux-2.6-xen-sparse/arch/xen/kernel/devmem.c	Wed Sep 14 17:54:43 2005 +0000
     3.3 @@ -27,7 +27,7 @@
     3.4  #include <asm/uaccess.h>
     3.5  #include <asm/io.h>
     3.6  
     3.7 -static inline int uncached_access(struct file *file, unsigned long addr)
     3.8 +static inline int uncached_access(struct file *file)
     3.9  {
    3.10          if (file->f_flags & O_SYNC)
    3.11                  return 1;
    3.12 @@ -90,10 +90,9 @@ out:
    3.13  
    3.14  static int mmap_mem(struct file * file, struct vm_area_struct * vma)
    3.15  {
    3.16 -	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
    3.17  	int uncached;
    3.18  
    3.19 -	uncached = uncached_access(file, offset);
    3.20 +	uncached = uncached_access(file);
    3.21  	if (uncached)
    3.22  		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    3.23  
    3.24 @@ -106,8 +105,9 @@ static int mmap_mem(struct file * file, 
    3.25  	if (uncached)
    3.26  		vma->vm_flags |= VM_IO;
    3.27  
    3.28 -	if (io_remap_page_range(vma, vma->vm_start, offset, 
    3.29 -				vma->vm_end-vma->vm_start, vma->vm_page_prot))
    3.30 +	if (direct_remap_pfn_range(vma->vm_mm, vma->vm_start, vma->vm_pgoff,
    3.31 +				   vma->vm_end - vma->vm_start,
    3.32 +				   vma->vm_page_prot, DOMID_IO))
    3.33  		return -EAGAIN;
    3.34  
    3.35  	return 0;
     4.1 --- a/linux-2.6-xen-sparse/arch/xen/x86_64/pci/Makefile	Wed Sep 14 17:06:37 2005 +0000
     4.2 +++ b/linux-2.6-xen-sparse/arch/xen/x86_64/pci/Makefile	Wed Sep 14 17:54:43 2005 +0000
     4.3 @@ -8,7 +8,7 @@ CFLAGS	+= -Iarch/$(XENARCH)/pci
     4.4  
     4.5  CFLAGS += -Iarch/i386/pci
     4.6  
     4.7 -c-i386-obj-y		:= i386.o
     4.8 +c-xen-obj-y		:= i386.o
     4.9  c-i386-obj-y		+= fixup.o
    4.10  c-i386-obj-$(CONFIG_ACPI_PCI)	+= acpi.o
    4.11  c-i386-obj-y			+= legacy.o common.o