ia64/xen-unstable

annotate unmodified_drivers/linux-2.6/platform-pci/platform-pci.c @ 16242:3d97c1c1f7c8

pv-on-hvm: fixes for unmodified drivers build and modern Linux

- The adjustments to README and overrides.mk are generic.
- The removal of explicit linux/config.h inclusion should also not
cause any issues.
- The introduction of irq_handler_t should eliminiate warnings on
2.6.19+ kernels (I didn't check they're there, but since the
request_irq prototype changed, I'm sure there's at least
one. However, as a result changes to the Linux tree are expected to
be required.
- The change setup_xen_features -> xen_setup_features follows the
naming in mainline 2.6.23 but would apparently also require changes
to the Linux tree.
- The changes SA_* -> IRQF_ and pci_module_init ->
pci_register_driver should also not cause issues.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir@xensource.com>
date Thu Oct 25 15:54:19 2007 +0100 (2007-10-25)
parents 049d4baa9965
children 27314cfbcefe
rev   line source
kfraser@11185 1 /******************************************************************************
keir@14764 2 * platform-pci.c
kfraser@14784 3 *
keir@14764 4 * Xen platform PCI device driver
kfraser@14784 5 * Copyright (c) 2005, Intel Corporation.
kfraser@14784 6 * Copyright (c) 2007, XenSource Inc.
kfraser@11185 7 *
kfraser@11185 8 * This program is free software; you can redistribute it and/or modify it
kfraser@11185 9 * under the terms and conditions of the GNU General Public License,
kfraser@11185 10 * version 2, as published by the Free Software Foundation.
kfraser@11185 11 *
kfraser@11185 12 * This program is distributed in the hope it will be useful, but WITHOUT
kfraser@11185 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
kfraser@11185 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
kfraser@11185 15 * more details.
kfraser@11185 16 *
kfraser@11185 17 * You should have received a copy of the GNU General Public License along with
kfraser@11185 18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
kfraser@11185 19 * Place - Suite 330, Boston, MA 02111-1307 USA.
kfraser@11185 20 *
kfraser@11185 21 */
kaf24@11443 22
kfraser@11185 23 #include <linux/module.h>
kfraser@11185 24 #include <linux/kernel.h>
kfraser@11185 25 #include <linux/sched.h>
kfraser@11185 26 #include <linux/errno.h>
kfraser@11185 27 #include <linux/pci.h>
kfraser@11185 28 #include <linux/init.h>
kfraser@11185 29 #include <linux/version.h>
kfraser@11185 30 #include <linux/interrupt.h>
kaf24@11443 31 #include <linux/vmalloc.h>
kaf24@11443 32 #include <linux/mm.h>
kfraser@11185 33 #include <asm/system.h>
kfraser@11185 34 #include <asm/io.h>
kfraser@11185 35 #include <asm/irq.h>
kfraser@11185 36 #include <asm/uaccess.h>
kfraser@11185 37 #include <asm/hypervisor.h>
ian@11974 38 #include <asm/pgtable.h>
kfraser@11185 39 #include <xen/interface/memory.h>
kfraser@14784 40 #include <xen/interface/hvm/params.h>
kfraser@11185 41 #include <xen/features.h>
kfraser@14784 42 #include <xen/evtchn.h>
awilliam@11805 43 #ifdef __ia64__
awilliam@11805 44 #include <asm/xen/xencomm.h>
awilliam@11805 45 #endif
kfraser@11185 46
kfraser@11185 47 #include "platform-pci.h"
kfraser@11185 48
ian@11983 49 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
ian@11983 50 #include <xen/platform-compat.h>
ian@11983 51 #endif
ian@11983 52
kfraser@11185 53 #define DRV_NAME "xen-platform-pci"
kfraser@11185 54 #define DRV_VERSION "0.10"
kfraser@11185 55 #define DRV_RELDATE "03/03/2005"
kfraser@11185 56
kfraser@15230 57 static int max_hypercall_stub_pages, nr_hypercall_stub_pages;
kfraser@11249 58 char *hypercall_stubs;
kfraser@11249 59 EXPORT_SYMBOL(hypercall_stubs);
kfraser@11185 60
kfraser@11185 61 MODULE_AUTHOR("ssmith@xensource.com");
kfraser@11185 62 MODULE_DESCRIPTION("Xen platform PCI device");
kfraser@11185 63 MODULE_LICENSE("GPL");
kfraser@11185 64
kfraser@14801 65 struct pci_dev *xen_platform_pdev;
kfraser@14801 66
Tim@14659 67 static unsigned long shared_info_frame;
Tim@14659 68 static uint64_t callback_via;
Tim@14659 69
ian@13569 70 static int __devinit init_xen_info(void)
kfraser@11185 71 {
kfraser@11185 72 struct xen_add_to_physmap xatp;
kfraser@11185 73 extern void *shared_info_area;
kfraser@11185 74
awilliam@11805 75 #ifdef __ia64__
alex@15760 76 xencomm_initialize();
awilliam@11805 77 #endif
awilliam@11805 78
kfraser@11185 79 setup_xen_features();
kfraser@11185 80
kfraser@11185 81 shared_info_frame = alloc_xen_mmio(PAGE_SIZE) >> PAGE_SHIFT;
kfraser@11185 82 xatp.domid = DOMID_SELF;
kfraser@11185 83 xatp.idx = 0;
kfraser@11185 84 xatp.space = XENMAPSPACE_shared_info;
kfraser@11185 85 xatp.gpfn = shared_info_frame;
kfraser@11186 86 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
kfraser@11186 87 BUG();
kfraser@11186 88
kfraser@11185 89 shared_info_area =
kfraser@11185 90 ioremap(shared_info_frame << PAGE_SHIFT, PAGE_SIZE);
kfraser@11186 91 if (shared_info_area == NULL)
kfraser@11185 92 panic("can't map shared info\n");
kfraser@11185 93
kfraser@11185 94 return 0;
kfraser@11185 95 }
kfraser@11185 96
kfraser@11185 97 static unsigned long platform_mmio;
kfraser@11185 98 static unsigned long platform_mmio_alloc;
kfraser@11185 99 static unsigned long platform_mmiolen;
kfraser@11185 100
kfraser@11185 101 unsigned long alloc_xen_mmio(unsigned long len)
kfraser@11185 102 {
kfraser@11185 103 unsigned long addr;
kfraser@11185 104
keir@13889 105 addr = platform_mmio + platform_mmio_alloc;
keir@13889 106 platform_mmio_alloc += len;
keir@13889 107 BUG_ON(platform_mmio_alloc > platform_mmiolen);
keir@13889 108
kfraser@11185 109 return addr;
kfraser@11185 110 }
kfraser@11185 111
kaf24@11468 112 #ifndef __ia64__
kfraser@15230 113
kfraser@15230 114 static int init_hypercall_stubs(void)
kfraser@11185 115 {
kaf24@11443 116 uint32_t eax, ebx, ecx, edx, pages, msr, i;
kfraser@11185 117 char signature[13];
kfraser@11185 118
kfraser@11185 119 cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
kfraser@11185 120 *(uint32_t*)(signature + 0) = ebx;
kfraser@11185 121 *(uint32_t*)(signature + 4) = ecx;
kfraser@11185 122 *(uint32_t*)(signature + 8) = edx;
kfraser@11185 123 signature[12] = 0;
kfraser@11185 124
kfraser@11249 125 if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
kfraser@11185 126 printk(KERN_WARNING
kfraser@11249 127 "Detected Xen platform device but not Xen VMM?"
kfraser@11249 128 " (sig %s, eax %x)\n",
kfraser@11185 129 signature, eax);
kfraser@11185 130 return -EINVAL;
kfraser@11185 131 }
kfraser@11185 132
kfraser@11185 133 cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
kfraser@11185 134
kfraser@11185 135 printk(KERN_INFO "Xen version %d.%d.\n", eax >> 16, eax & 0xffff);
kfraser@11185 136
kfraser@15230 137 /*
kfraser@15230 138 * Find largest supported number of hypercall pages.
kfraser@15230 139 * We'll create as many as possible up to this number.
kfraser@15230 140 */
kfraser@11249 141 cpuid(0x40000002, &pages, &msr, &ecx, &edx);
kfraser@11185 142
kfraser@15230 143 /*
kfraser@15230 144 * Use __vmalloc() because vmalloc_exec() is not an exported symbol.
kfraser@15230 145 * PAGE_KERNEL_EXEC also is not exported, hence we use PAGE_KERNEL.
kfraser@15230 146 * hypercall_stubs = vmalloc_exec(pages * PAGE_SIZE);
kfraser@15230 147 */
kfraser@15230 148 while (pages > 0) {
kfraser@15230 149 hypercall_stubs = __vmalloc(
kfraser@15230 150 pages * PAGE_SIZE,
kfraser@15230 151 GFP_KERNEL | __GFP_HIGHMEM,
kfraser@15230 152 __pgprot(__PAGE_KERNEL & ~_PAGE_NX));
kfraser@15230 153 if (hypercall_stubs != NULL)
kfraser@15230 154 break;
kfraser@15230 155 pages--; /* vmalloc failed: try one fewer pages */
kfraser@15230 156 }
kfraser@11185 157
kfraser@11249 158 if (hypercall_stubs == NULL)
kfraser@11185 159 return -ENOMEM;
kfraser@11249 160
kaf24@11443 161 for (i = 0; i < pages; i++) {
kaf24@11443 162 unsigned long pfn;
kaf24@11443 163 pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
kaf24@11443 164 wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
kaf24@11443 165 }
kfraser@11185 166
kfraser@15230 167 nr_hypercall_stub_pages = pages;
kfraser@15230 168 max_hypercall_stub_pages = pages;
kfraser@15230 169
kfraser@15230 170 printk(KERN_INFO "Hypercall area is %u pages.\n", pages);
kfraser@15230 171
kfraser@11185 172 return 0;
kfraser@11185 173 }
kfraser@15230 174
kfraser@15230 175 static void resume_hypercall_stubs(void)
kfraser@15230 176 {
kfraser@15230 177 uint32_t eax, ebx, ecx, edx, pages, msr, i;
kfraser@15230 178 char signature[13];
kfraser@15230 179
kfraser@15230 180 cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
kfraser@15230 181 *(uint32_t*)(signature + 0) = ebx;
kfraser@15230 182 *(uint32_t*)(signature + 4) = ecx;
kfraser@15230 183 *(uint32_t*)(signature + 8) = edx;
kfraser@15230 184 signature[12] = 0;
kfraser@15230 185
kfraser@15230 186 BUG_ON(strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002));
kfraser@15230 187
kfraser@15230 188 cpuid(0x40000002, &pages, &msr, &ecx, &edx);
kfraser@15230 189
kfraser@15230 190 if (pages > max_hypercall_stub_pages)
kfraser@15230 191 pages = max_hypercall_stub_pages;
kfraser@15230 192
kfraser@15230 193 for (i = 0; i < pages; i++) {
kfraser@15230 194 unsigned long pfn;
kfraser@15230 195 pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
kfraser@15230 196 wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
kfraser@15230 197 }
kfraser@15230 198
kfraser@15230 199 nr_hypercall_stub_pages = pages;
kfraser@15230 200 }
kfraser@15230 201
kaf24@11468 202 #else /* __ia64__ */
kfraser@15230 203
kfraser@15230 204 #define init_hypercall_stubs() (0)
kfraser@15230 205 #define resume_hypercall_stubs() ((void)0)
kfraser@15230 206
kaf24@11468 207 #endif
kfraser@11185 208
kfraser@13374 209 static uint64_t get_callback_via(struct pci_dev *pdev)
kfraser@12545 210 {
awilliam@13842 211 u8 pin;
keir@13889 212 int irq;
keir@13889 213
kfraser@12545 214 #ifdef __ia64__
kfraser@12545 215 for (irq = 0; irq < 16; irq++) {
kfraser@12545 216 if (isa_irq_to_vector(irq) == pdev->irq)
awilliam@13842 217 return irq; /* ISA IRQ */
kfraser@12545 218 }
kfraser@12545 219 #else /* !__ia64__ */
keir@13889 220 irq = pdev->irq;
keir@13889 221 if (irq < 16)
keir@13889 222 return irq; /* ISA IRQ */
awilliam@13842 223 #endif
ian@13569 224
ian@13569 225 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
ian@13569 226 pin = pdev->pin;
ian@13569 227 #else
ian@13569 228 pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
ian@13569 229 #endif
ian@13569 230
kfraser@13374 231 /* We don't know the GSI. Specify the PCI INTx line instead. */
kfraser@13374 232 return (((uint64_t)0x01 << 56) | /* PCI INTx identifier */
kfraser@13374 233 ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
kfraser@13374 234 ((uint64_t)pdev->bus->number << 16) |
kfraser@13374 235 ((uint64_t)(pdev->devfn & 0xff) << 8) |
ian@13569 236 ((uint64_t)(pin - 1) & 3));
kfraser@12545 237 }
kfraser@12545 238
kfraser@14784 239 static int set_callback_via(uint64_t via)
kfraser@14784 240 {
kfraser@14784 241 struct xen_hvm_param a;
kfraser@14784 242
kfraser@14784 243 a.domid = DOMID_SELF;
kfraser@14784 244 a.index = HVM_PARAM_CALLBACK_IRQ;
kfraser@14784 245 a.value = via;
kfraser@14784 246 return HYPERVISOR_hvm_op(HVMOP_set_param, &a);
kfraser@14784 247 }
kfraser@14784 248
kfraser@14801 249 int xen_irq_init(struct pci_dev *pdev);
kfraser@14784 250 int xenbus_init(void);
kfraser@14784 251 int xen_reboot_init(void);
kfraser@14801 252 int gnttab_init(void);
kfraser@14784 253
kfraser@11185 254 static int __devinit platform_pci_init(struct pci_dev *pdev,
kfraser@11185 255 const struct pci_device_id *ent)
kfraser@11185 256 {
kfraser@13374 257 int i, ret;
kfraser@11185 258 long ioaddr, iolen;
kfraser@11185 259 long mmio_addr, mmio_len;
kfraser@11185 260
kfraser@14801 261 if (xen_platform_pdev)
kfraser@14801 262 return -EBUSY;
kfraser@14801 263 xen_platform_pdev = pdev;
kfraser@14801 264
kfraser@11185 265 i = pci_enable_device(pdev);
kfraser@11185 266 if (i)
kfraser@11185 267 return i;
kfraser@11185 268
kfraser@11185 269 ioaddr = pci_resource_start(pdev, 0);
kfraser@11185 270 iolen = pci_resource_len(pdev, 0);
kfraser@11185 271
kfraser@11185 272 mmio_addr = pci_resource_start(pdev, 1);
kfraser@11185 273 mmio_len = pci_resource_len(pdev, 1);
kfraser@11185 274
kfraser@13374 275 callback_via = get_callback_via(pdev);
kfraser@12545 276
kfraser@13374 277 if (mmio_addr == 0 || ioaddr == 0 || callback_via == 0) {
kfraser@11185 278 printk(KERN_WARNING DRV_NAME ":no resources found\n");
kfraser@11185 279 return -ENOENT;
kfraser@11185 280 }
kfraser@11185 281
kfraser@14784 282 if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) {
kfraser@11185 283 printk(KERN_ERR ":MEM I/O resource 0x%lx @ 0x%lx busy\n",
kfraser@11185 284 mmio_addr, mmio_len);
kfraser@11185 285 return -EBUSY;
kfraser@11185 286 }
kfraser@11185 287
kfraser@14784 288 if (request_region(ioaddr, iolen, DRV_NAME) == NULL) {
kfraser@11185 289 printk(KERN_ERR DRV_NAME ":I/O resource 0x%lx @ 0x%lx busy\n",
kfraser@11185 290 iolen, ioaddr);
kfraser@11185 291 release_mem_region(mmio_addr, mmio_len);
kfraser@11185 292 return -EBUSY;
kfraser@11185 293 }
kfraser@11185 294
kfraser@11185 295 platform_mmio = mmio_addr;
kfraser@11185 296 platform_mmiolen = mmio_len;
kfraser@11185 297
kfraser@15230 298 ret = init_hypercall_stubs();
kfraser@11185 299 if (ret < 0)
kfraser@11185 300 goto out;
kfraser@11185 301
kfraser@11185 302 if ((ret = init_xen_info()))
kfraser@11185 303 goto out;
kfraser@11185 304
kfraser@14801 305 if ((ret = gnttab_init()))
kfraser@14801 306 goto out;
kfraser@14801 307
kfraser@14801 308 if ((ret = xen_irq_init(pdev)))
kfraser@11185 309 goto out;
kfraser@11185 310
kfraser@13374 311 if ((ret = set_callback_via(callback_via)))
kfraser@11185 312 goto out;
kfraser@11185 313
kfraser@14784 314 if ((ret = xenbus_init()))
kfraser@14784 315 goto out;
kfraser@14784 316
kfraser@14784 317 if ((ret = xen_reboot_init()))
kfraser@14784 318 goto out;
kfraser@14784 319
kfraser@11185 320 out:
kfraser@11185 321 if (ret) {
kfraser@11185 322 release_mem_region(mmio_addr, mmio_len);
kfraser@11185 323 release_region(ioaddr, iolen);
kfraser@11185 324 }
kfraser@11185 325
kfraser@11185 326 return ret;
kfraser@11185 327 }
kfraser@11185 328
ssmith@11555 329 #define XEN_PLATFORM_VENDOR_ID 0x5853
ssmith@11555 330 #define XEN_PLATFORM_DEVICE_ID 0x0001
kfraser@11185 331 static struct pci_device_id platform_pci_tbl[] __devinitdata = {
kfraser@11185 332 {XEN_PLATFORM_VENDOR_ID, XEN_PLATFORM_DEVICE_ID,
kfraser@11185 333 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
ssmith@11555 334 /* Continue to recognise the old ID for now */
ssmith@11555 335 {0xfffd, 0x0101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
kfraser@11185 336 {0,}
kfraser@11185 337 };
kfraser@11185 338
kfraser@11185 339 MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
kfraser@11185 340
kfraser@11185 341 static struct pci_driver platform_driver = {
kfraser@11185 342 name: DRV_NAME,
kfraser@11185 343 probe: platform_pci_init,
kfraser@11185 344 id_table: platform_pci_tbl,
kfraser@11185 345 };
kfraser@11185 346
kfraser@11185 347 static int pci_device_registered;
kfraser@11185 348
Tim@14659 349 void platform_pci_resume(void)
Tim@14659 350 {
Tim@14659 351 struct xen_add_to_physmap xatp;
Tim@14659 352
kfraser@15230 353 resume_hypercall_stubs();
kfraser@15230 354
Tim@14659 355 xatp.domid = DOMID_SELF;
Tim@14659 356 xatp.idx = 0;
Tim@14659 357 xatp.space = XENMAPSPACE_shared_info;
Tim@14659 358 xatp.gpfn = shared_info_frame;
Tim@14659 359 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
Tim@14659 360 BUG();
Tim@14659 361
kfraser@14784 362 if (set_callback_via(callback_via))
Tim@14659 363 printk("platform_pci_resume failure!\n");
Tim@14659 364 }
Tim@14659 365
kfraser@11185 366 static int __init platform_pci_module_init(void)
kfraser@11185 367 {
kfraser@11185 368 int rc;
kfraser@11185 369
keir@16242 370 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
kfraser@11185 371 rc = pci_module_init(&platform_driver);
keir@16242 372 #else
keir@16242 373 rc = pci_register_driver(&platform_driver);
keir@16242 374 #endif
kfraser@14784 375 if (rc) {
kfraser@14784 376 printk(KERN_INFO DRV_NAME
kfraser@14784 377 ": No platform pci device model found\n");
kfraser@14784 378 return rc;
kfraser@14784 379 }
kfraser@11185 380
kfraser@14784 381 pci_device_registered = 1;
kfraser@14784 382 return 0;
kfraser@11185 383 }
kfraser@11185 384
kfraser@11185 385 module_init(platform_pci_module_init);