direct-io.hg
changeset 6817:1184286a2ee6
Fix mmapping of PCI resources from userspace.
Signed-off-by: Keir Fraser <keir@xensource.com>
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, ®); 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