debuggers.hg

view unmodified_drivers/linux-2.6/platform-pci/platform-pci.c @ 20913:8dcedf17b5b4

pv-on-hvm: Correct the order of the argument of out*()

The order of the argument of outl() is wrong.
The correct order is outl(value, port). This causes kernel panic.

And outw() is also similar.

Signed-off-by: KUWAMURA Shin'ya <kuwa@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jan 29 07:10:28 2010 +0000 (2010-01-29)
parents 15efdfc46593
children 628600e0e3b4
line source
1 /******************************************************************************
2 * platform-pci.c
3 *
4 * Xen platform PCI device driver
5 * Copyright (c) 2005, Intel Corporation.
6 * Copyright (c) 2007, XenSource Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place - Suite 330, Boston, MA 02111-1307 USA.
20 *
21 */
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/sched.h>
26 #include <linux/errno.h>
27 #include <linux/pci.h>
28 #include <linux/init.h>
29 #include <linux/version.h>
30 #include <linux/interrupt.h>
31 #include <linux/vmalloc.h>
32 #include <linux/mm.h>
33 #include <asm/system.h>
34 #include <asm/io.h>
35 #include <asm/irq.h>
36 #include <asm/uaccess.h>
37 #include <asm/hypervisor.h>
38 #include <asm/pgtable.h>
39 #include <xen/interface/memory.h>
40 #include <xen/interface/hvm/params.h>
41 #include <xen/features.h>
42 #include <xen/evtchn.h>
43 #ifdef __ia64__
44 #include <asm/xen/xencomm.h>
45 #endif
47 #include "platform-pci.h"
49 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
50 #include <xen/platform-compat.h>
51 #endif
53 #define DRV_NAME "xen-platform-pci"
54 #define DRV_VERSION "0.10"
55 #define DRV_RELDATE "03/03/2005"
57 static int max_hypercall_stub_pages, nr_hypercall_stub_pages;
58 char *hypercall_stubs;
59 EXPORT_SYMBOL(hypercall_stubs);
61 MODULE_AUTHOR("ssmith@xensource.com");
62 MODULE_DESCRIPTION("Xen platform PCI device");
63 MODULE_LICENSE("GPL");
65 /* NB. [aux-]ide-disks options do not unplug IDE CD-ROM drives. */
66 /* NB. aux-ide-disks is equiv to ide-disks except ignores primary master. */
67 static char *dev_unplug;
68 module_param(dev_unplug, charp, 0644);
69 MODULE_PARM_DESC(dev_unplug, "Emulated devices to unplug: "
70 "[all,][ide-disks,][aux-ide-disks,][nics]\n");
72 struct pci_dev *xen_platform_pdev;
74 static unsigned long shared_info_frame;
75 static uint64_t callback_via;
77 static int __devinit init_xen_info(void)
78 {
79 struct xen_add_to_physmap xatp;
80 extern void *shared_info_area;
82 #ifdef __ia64__
83 xencomm_initialize();
84 #endif
86 setup_xen_features();
88 shared_info_frame = alloc_xen_mmio(PAGE_SIZE) >> PAGE_SHIFT;
89 xatp.domid = DOMID_SELF;
90 xatp.idx = 0;
91 xatp.space = XENMAPSPACE_shared_info;
92 xatp.gpfn = shared_info_frame;
93 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
94 BUG();
96 shared_info_area =
97 ioremap(shared_info_frame << PAGE_SHIFT, PAGE_SIZE);
98 if (shared_info_area == NULL)
99 panic("can't map shared info\n");
101 return 0;
102 }
104 static unsigned long platform_mmio;
105 static unsigned long platform_mmio_alloc;
106 static unsigned long platform_mmiolen;
108 unsigned long alloc_xen_mmio(unsigned long len)
109 {
110 unsigned long addr;
112 addr = platform_mmio + platform_mmio_alloc;
113 platform_mmio_alloc += len;
114 BUG_ON(platform_mmio_alloc > platform_mmiolen);
116 return addr;
117 }
119 #ifndef __ia64__
121 static uint32_t xen_cpuid_base(void)
122 {
123 uint32_t base, eax, ebx, ecx, edx;
124 char signature[13];
126 for (base = 0x40000000; base < 0x40010000; base += 0x100) {
127 cpuid(base, &eax, &ebx, &ecx, &edx);
128 *(uint32_t*)(signature + 0) = ebx;
129 *(uint32_t*)(signature + 4) = ecx;
130 *(uint32_t*)(signature + 8) = edx;
131 signature[12] = 0;
133 if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
134 return base;
135 }
137 return 0;
138 }
140 static int init_hypercall_stubs(void)
141 {
142 uint32_t eax, ebx, ecx, edx, pages, msr, i, base;
144 base = xen_cpuid_base();
145 if (base == 0) {
146 printk(KERN_WARNING
147 "Detected Xen platform device but not Xen VMM?\n");
148 return -EINVAL;
149 }
151 cpuid(base + 1, &eax, &ebx, &ecx, &edx);
153 printk(KERN_INFO "Xen version %d.%d.\n", eax >> 16, eax & 0xffff);
155 /*
156 * Find largest supported number of hypercall pages.
157 * We'll create as many as possible up to this number.
158 */
159 cpuid(base + 2, &pages, &msr, &ecx, &edx);
161 /*
162 * Use __vmalloc() because vmalloc_exec() is not an exported symbol.
163 * PAGE_KERNEL_EXEC also is not exported, hence we use PAGE_KERNEL.
164 * hypercall_stubs = vmalloc_exec(pages * PAGE_SIZE);
165 */
166 while (pages > 0) {
167 hypercall_stubs = __vmalloc(
168 pages * PAGE_SIZE,
169 GFP_KERNEL | __GFP_HIGHMEM,
170 __pgprot(__PAGE_KERNEL & ~_PAGE_NX));
171 if (hypercall_stubs != NULL)
172 break;
173 pages--; /* vmalloc failed: try one fewer pages */
174 }
176 if (hypercall_stubs == NULL)
177 return -ENOMEM;
179 for (i = 0; i < pages; i++) {
180 unsigned long pfn;
181 pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
182 wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
183 }
185 nr_hypercall_stub_pages = pages;
186 max_hypercall_stub_pages = pages;
188 printk(KERN_INFO "Hypercall area is %u pages.\n", pages);
190 return 0;
191 }
193 static void resume_hypercall_stubs(void)
194 {
195 uint32_t base, ecx, edx, pages, msr, i;
197 base = xen_cpuid_base();
198 BUG_ON(base == 0);
200 cpuid(base + 2, &pages, &msr, &ecx, &edx);
202 if (pages > max_hypercall_stub_pages)
203 pages = max_hypercall_stub_pages;
205 for (i = 0; i < pages; i++) {
206 unsigned long pfn;
207 pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
208 wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
209 }
211 nr_hypercall_stub_pages = pages;
212 }
214 #else /* __ia64__ */
216 #define init_hypercall_stubs() (0)
217 #define resume_hypercall_stubs() ((void)0)
219 #endif
221 static uint64_t get_callback_via(struct pci_dev *pdev)
222 {
223 u8 pin;
224 int irq;
226 #ifdef __ia64__
227 for (irq = 0; irq < 16; irq++) {
228 if (isa_irq_to_vector(irq) == pdev->irq)
229 return irq; /* ISA IRQ */
230 }
231 #else /* !__ia64__ */
232 irq = pdev->irq;
233 if (irq < 16)
234 return irq; /* ISA IRQ */
235 #endif
237 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
238 pin = pdev->pin;
239 #else
240 pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
241 #endif
243 /* We don't know the GSI. Specify the PCI INTx line instead. */
244 return (((uint64_t)0x01 << 56) | /* PCI INTx identifier */
245 ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
246 ((uint64_t)pdev->bus->number << 16) |
247 ((uint64_t)(pdev->devfn & 0xff) << 8) |
248 ((uint64_t)(pin - 1) & 3));
249 }
251 static int set_callback_via(uint64_t via)
252 {
253 struct xen_hvm_param a;
255 a.domid = DOMID_SELF;
256 a.index = HVM_PARAM_CALLBACK_IRQ;
257 a.value = via;
258 return HYPERVISOR_hvm_op(HVMOP_set_param, &a);
259 }
261 int xen_irq_init(struct pci_dev *pdev);
262 int xenbus_init(void);
263 int xen_reboot_init(void);
264 int xen_panic_handler_init(void);
265 int gnttab_init(void);
267 #define XEN_IOPORT_BASE 0x10
269 #define XEN_IOPORT_PLATFLAGS (XEN_IOPORT_BASE + 0) /* 1 byte access (R/W) */
270 #define XEN_IOPORT_MAGIC (XEN_IOPORT_BASE + 0) /* 2 byte access (R) */
271 #define XEN_IOPORT_UNPLUG (XEN_IOPORT_BASE + 0) /* 2 byte access (W) */
272 #define XEN_IOPORT_DRVVER (XEN_IOPORT_BASE + 0) /* 4 byte access (W) */
274 #define XEN_IOPORT_SYSLOG (XEN_IOPORT_BASE + 2) /* 1 byte access (W) */
275 #define XEN_IOPORT_PROTOVER (XEN_IOPORT_BASE + 2) /* 1 byte access (R) */
276 #define XEN_IOPORT_PRODNUM (XEN_IOPORT_BASE + 2) /* 2 byte access (W) */
278 #define XEN_IOPORT_MAGIC_VAL 0x49d2
279 #define XEN_IOPORT_LINUX_PRODNUM 0xffff /* NB: register a proper one */
280 #define XEN_IOPORT_LINUX_DRVVER ((LINUX_VERSION_CODE << 8) + 0x0)
282 #define UNPLUG_ALL_IDE_DISKS 1
283 #define UNPLUG_ALL_NICS 2
284 #define UNPLUG_AUX_IDE_DISKS 4
285 #define UNPLUG_ALL 7
287 static int check_platform_magic(struct device *dev, long ioaddr, long iolen)
288 {
289 short magic, unplug = 0;
290 char protocol, *p, *q, *err;
292 for (p = dev_unplug; p; p = q) {
293 q = strchr(dev_unplug, ',');
294 if (q)
295 *q++ = '\0';
296 if (!strcmp(p, "all"))
297 unplug |= UNPLUG_ALL;
298 else if (!strcmp(p, "ide-disks"))
299 unplug |= UNPLUG_ALL_IDE_DISKS;
300 else if (!strcmp(p, "aux-ide-disks"))
301 unplug |= UNPLUG_AUX_IDE_DISKS;
302 else if (!strcmp(p, "nics"))
303 unplug |= UNPLUG_ALL_NICS;
304 else
305 dev_warn(dev, "unrecognised option '%s' "
306 "in module parameter 'dev_unplug'\n", p);
307 }
309 if (iolen < 0x16) {
310 err = "backend too old";
311 goto no_dev;
312 }
314 magic = inw(XEN_IOPORT_MAGIC);
316 if (magic != XEN_IOPORT_MAGIC_VAL) {
317 err = "unrecognised magic value";
318 goto no_dev;
319 }
321 protocol = inb(XEN_IOPORT_PROTOVER);
323 dev_info(dev, "I/O protocol version %d\n", protocol);
325 switch (protocol) {
326 case 1:
327 outw(XEN_IOPORT_LINUX_PRODNUM, XEN_IOPORT_PRODNUM);
328 outl(XEN_IOPORT_LINUX_DRVVER, XEN_IOPORT_DRVVER);
329 if (inw(XEN_IOPORT_MAGIC) != XEN_IOPORT_MAGIC_VAL) {
330 dev_err(dev, "blacklisted by host\n");
331 return -ENODEV;
332 }
333 /* Fall through */
334 case 0:
335 outw(0xf, XEN_IOPORT_UNPLUG);
336 break;
337 default:
338 err = "unknown I/O protocol version";
339 goto no_dev;
340 }
342 return 0;
344 no_dev:
345 dev_warn(dev, "failed backend handshake: %s\n", err);
346 if (!unplug)
347 return 0;
348 dev_err(dev, "failed to execute specified dev_unplug options!\n");
349 return -ENODEV;
350 }
352 static int __devinit platform_pci_init(struct pci_dev *pdev,
353 const struct pci_device_id *ent)
354 {
355 int i, ret;
356 long ioaddr, iolen;
357 long mmio_addr, mmio_len;
359 if (xen_platform_pdev)
360 return -EBUSY;
361 xen_platform_pdev = pdev;
363 i = pci_enable_device(pdev);
364 if (i)
365 return i;
367 ioaddr = pci_resource_start(pdev, 0);
368 iolen = pci_resource_len(pdev, 0);
370 mmio_addr = pci_resource_start(pdev, 1);
371 mmio_len = pci_resource_len(pdev, 1);
373 callback_via = get_callback_via(pdev);
375 if (mmio_addr == 0 || ioaddr == 0 || callback_via == 0) {
376 printk(KERN_WARNING DRV_NAME ":no resources found\n");
377 return -ENOENT;
378 }
380 if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) {
381 printk(KERN_ERR ":MEM I/O resource 0x%lx @ 0x%lx busy\n",
382 mmio_addr, mmio_len);
383 return -EBUSY;
384 }
386 if (request_region(ioaddr, iolen, DRV_NAME) == NULL) {
387 printk(KERN_ERR DRV_NAME ":I/O resource 0x%lx @ 0x%lx busy\n",
388 iolen, ioaddr);
389 release_mem_region(mmio_addr, mmio_len);
390 return -EBUSY;
391 }
393 platform_mmio = mmio_addr;
394 platform_mmiolen = mmio_len;
396 ret = init_hypercall_stubs();
397 if (ret < 0)
398 goto out;
400 ret = check_platform_magic(&pdev->dev, ioaddr, iolen);
401 if (ret < 0)
402 goto out;
404 if ((ret = init_xen_info()))
405 goto out;
407 if ((ret = gnttab_init()))
408 goto out;
410 if ((ret = xen_irq_init(pdev)))
411 goto out;
413 if ((ret = set_callback_via(callback_via)))
414 goto out;
416 if ((ret = xenbus_init()))
417 goto out;
419 if ((ret = xen_reboot_init()))
420 goto out;
422 if ((ret = xen_panic_handler_init()))
423 goto out;
425 out:
426 if (ret) {
427 release_mem_region(mmio_addr, mmio_len);
428 release_region(ioaddr, iolen);
429 }
431 return ret;
432 }
434 #define XEN_PLATFORM_VENDOR_ID 0x5853
435 #define XEN_PLATFORM_DEVICE_ID 0x0001
436 static struct pci_device_id platform_pci_tbl[] __devinitdata = {
437 {XEN_PLATFORM_VENDOR_ID, XEN_PLATFORM_DEVICE_ID,
438 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
439 /* Continue to recognise the old ID for now */
440 {0xfffd, 0x0101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
441 {0,}
442 };
444 MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
446 static struct pci_driver platform_driver = {
447 name: DRV_NAME,
448 probe: platform_pci_init,
449 id_table: platform_pci_tbl,
450 };
452 static int pci_device_registered;
454 void platform_pci_resume(void)
455 {
456 struct xen_add_to_physmap xatp;
458 resume_hypercall_stubs();
460 xatp.domid = DOMID_SELF;
461 xatp.idx = 0;
462 xatp.space = XENMAPSPACE_shared_info;
463 xatp.gpfn = shared_info_frame;
464 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
465 BUG();
467 if (set_callback_via(callback_via))
468 printk("platform_pci_resume failure!\n");
469 }
471 static int __init platform_pci_module_init(void)
472 {
473 int rc;
475 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
476 rc = pci_module_init(&platform_driver);
477 #else
478 rc = pci_register_driver(&platform_driver);
479 #endif
480 if (rc) {
481 printk(KERN_INFO DRV_NAME
482 ": No platform pci device model found\n");
483 return rc;
484 }
486 pci_device_registered = 1;
487 return 0;
488 }
490 module_init(platform_pci_module_init);