ia64/xen-unstable

view 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
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 struct pci_dev *xen_platform_pdev;
67 static unsigned long shared_info_frame;
68 static uint64_t callback_via;
70 static int __devinit init_xen_info(void)
71 {
72 struct xen_add_to_physmap xatp;
73 extern void *shared_info_area;
75 #ifdef __ia64__
76 xencomm_initialize();
77 #endif
79 setup_xen_features();
81 shared_info_frame = alloc_xen_mmio(PAGE_SIZE) >> PAGE_SHIFT;
82 xatp.domid = DOMID_SELF;
83 xatp.idx = 0;
84 xatp.space = XENMAPSPACE_shared_info;
85 xatp.gpfn = shared_info_frame;
86 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
87 BUG();
89 shared_info_area =
90 ioremap(shared_info_frame << PAGE_SHIFT, PAGE_SIZE);
91 if (shared_info_area == NULL)
92 panic("can't map shared info\n");
94 return 0;
95 }
97 static unsigned long platform_mmio;
98 static unsigned long platform_mmio_alloc;
99 static unsigned long platform_mmiolen;
101 unsigned long alloc_xen_mmio(unsigned long len)
102 {
103 unsigned long addr;
105 addr = platform_mmio + platform_mmio_alloc;
106 platform_mmio_alloc += len;
107 BUG_ON(platform_mmio_alloc > platform_mmiolen);
109 return addr;
110 }
112 #ifndef __ia64__
114 static int init_hypercall_stubs(void)
115 {
116 uint32_t eax, ebx, ecx, edx, pages, msr, i;
117 char signature[13];
119 cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
120 *(uint32_t*)(signature + 0) = ebx;
121 *(uint32_t*)(signature + 4) = ecx;
122 *(uint32_t*)(signature + 8) = edx;
123 signature[12] = 0;
125 if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
126 printk(KERN_WARNING
127 "Detected Xen platform device but not Xen VMM?"
128 " (sig %s, eax %x)\n",
129 signature, eax);
130 return -EINVAL;
131 }
133 cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
135 printk(KERN_INFO "Xen version %d.%d.\n", eax >> 16, eax & 0xffff);
137 /*
138 * Find largest supported number of hypercall pages.
139 * We'll create as many as possible up to this number.
140 */
141 cpuid(0x40000002, &pages, &msr, &ecx, &edx);
143 /*
144 * Use __vmalloc() because vmalloc_exec() is not an exported symbol.
145 * PAGE_KERNEL_EXEC also is not exported, hence we use PAGE_KERNEL.
146 * hypercall_stubs = vmalloc_exec(pages * PAGE_SIZE);
147 */
148 while (pages > 0) {
149 hypercall_stubs = __vmalloc(
150 pages * PAGE_SIZE,
151 GFP_KERNEL | __GFP_HIGHMEM,
152 __pgprot(__PAGE_KERNEL & ~_PAGE_NX));
153 if (hypercall_stubs != NULL)
154 break;
155 pages--; /* vmalloc failed: try one fewer pages */
156 }
158 if (hypercall_stubs == NULL)
159 return -ENOMEM;
161 for (i = 0; i < pages; i++) {
162 unsigned long pfn;
163 pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
164 wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
165 }
167 nr_hypercall_stub_pages = pages;
168 max_hypercall_stub_pages = pages;
170 printk(KERN_INFO "Hypercall area is %u pages.\n", pages);
172 return 0;
173 }
175 static void resume_hypercall_stubs(void)
176 {
177 uint32_t eax, ebx, ecx, edx, pages, msr, i;
178 char signature[13];
180 cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
181 *(uint32_t*)(signature + 0) = ebx;
182 *(uint32_t*)(signature + 4) = ecx;
183 *(uint32_t*)(signature + 8) = edx;
184 signature[12] = 0;
186 BUG_ON(strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002));
188 cpuid(0x40000002, &pages, &msr, &ecx, &edx);
190 if (pages > max_hypercall_stub_pages)
191 pages = max_hypercall_stub_pages;
193 for (i = 0; i < pages; i++) {
194 unsigned long pfn;
195 pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
196 wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
197 }
199 nr_hypercall_stub_pages = pages;
200 }
202 #else /* __ia64__ */
204 #define init_hypercall_stubs() (0)
205 #define resume_hypercall_stubs() ((void)0)
207 #endif
209 static uint64_t get_callback_via(struct pci_dev *pdev)
210 {
211 u8 pin;
212 int irq;
214 #ifdef __ia64__
215 for (irq = 0; irq < 16; irq++) {
216 if (isa_irq_to_vector(irq) == pdev->irq)
217 return irq; /* ISA IRQ */
218 }
219 #else /* !__ia64__ */
220 irq = pdev->irq;
221 if (irq < 16)
222 return irq; /* ISA IRQ */
223 #endif
225 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
226 pin = pdev->pin;
227 #else
228 pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
229 #endif
231 /* We don't know the GSI. Specify the PCI INTx line instead. */
232 return (((uint64_t)0x01 << 56) | /* PCI INTx identifier */
233 ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
234 ((uint64_t)pdev->bus->number << 16) |
235 ((uint64_t)(pdev->devfn & 0xff) << 8) |
236 ((uint64_t)(pin - 1) & 3));
237 }
239 static int set_callback_via(uint64_t via)
240 {
241 struct xen_hvm_param a;
243 a.domid = DOMID_SELF;
244 a.index = HVM_PARAM_CALLBACK_IRQ;
245 a.value = via;
246 return HYPERVISOR_hvm_op(HVMOP_set_param, &a);
247 }
249 int xen_irq_init(struct pci_dev *pdev);
250 int xenbus_init(void);
251 int xen_reboot_init(void);
252 int gnttab_init(void);
254 static int __devinit platform_pci_init(struct pci_dev *pdev,
255 const struct pci_device_id *ent)
256 {
257 int i, ret;
258 long ioaddr, iolen;
259 long mmio_addr, mmio_len;
261 if (xen_platform_pdev)
262 return -EBUSY;
263 xen_platform_pdev = pdev;
265 i = pci_enable_device(pdev);
266 if (i)
267 return i;
269 ioaddr = pci_resource_start(pdev, 0);
270 iolen = pci_resource_len(pdev, 0);
272 mmio_addr = pci_resource_start(pdev, 1);
273 mmio_len = pci_resource_len(pdev, 1);
275 callback_via = get_callback_via(pdev);
277 if (mmio_addr == 0 || ioaddr == 0 || callback_via == 0) {
278 printk(KERN_WARNING DRV_NAME ":no resources found\n");
279 return -ENOENT;
280 }
282 if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) {
283 printk(KERN_ERR ":MEM I/O resource 0x%lx @ 0x%lx busy\n",
284 mmio_addr, mmio_len);
285 return -EBUSY;
286 }
288 if (request_region(ioaddr, iolen, DRV_NAME) == NULL) {
289 printk(KERN_ERR DRV_NAME ":I/O resource 0x%lx @ 0x%lx busy\n",
290 iolen, ioaddr);
291 release_mem_region(mmio_addr, mmio_len);
292 return -EBUSY;
293 }
295 platform_mmio = mmio_addr;
296 platform_mmiolen = mmio_len;
298 ret = init_hypercall_stubs();
299 if (ret < 0)
300 goto out;
302 if ((ret = init_xen_info()))
303 goto out;
305 if ((ret = gnttab_init()))
306 goto out;
308 if ((ret = xen_irq_init(pdev)))
309 goto out;
311 if ((ret = set_callback_via(callback_via)))
312 goto out;
314 if ((ret = xenbus_init()))
315 goto out;
317 if ((ret = xen_reboot_init()))
318 goto out;
320 out:
321 if (ret) {
322 release_mem_region(mmio_addr, mmio_len);
323 release_region(ioaddr, iolen);
324 }
326 return ret;
327 }
329 #define XEN_PLATFORM_VENDOR_ID 0x5853
330 #define XEN_PLATFORM_DEVICE_ID 0x0001
331 static struct pci_device_id platform_pci_tbl[] __devinitdata = {
332 {XEN_PLATFORM_VENDOR_ID, XEN_PLATFORM_DEVICE_ID,
333 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
334 /* Continue to recognise the old ID for now */
335 {0xfffd, 0x0101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
336 {0,}
337 };
339 MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
341 static struct pci_driver platform_driver = {
342 name: DRV_NAME,
343 probe: platform_pci_init,
344 id_table: platform_pci_tbl,
345 };
347 static int pci_device_registered;
349 void platform_pci_resume(void)
350 {
351 struct xen_add_to_physmap xatp;
353 resume_hypercall_stubs();
355 xatp.domid = DOMID_SELF;
356 xatp.idx = 0;
357 xatp.space = XENMAPSPACE_shared_info;
358 xatp.gpfn = shared_info_frame;
359 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
360 BUG();
362 if (set_callback_via(callback_via))
363 printk("platform_pci_resume failure!\n");
364 }
366 static int __init platform_pci_module_init(void)
367 {
368 int rc;
370 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
371 rc = pci_module_init(&platform_driver);
372 #else
373 rc = pci_register_driver(&platform_driver);
374 #endif
375 if (rc) {
376 printk(KERN_INFO DRV_NAME
377 ": No platform pci device model found\n");
378 return rc;
379 }
381 pci_device_registered = 1;
382 return 0;
383 }
385 module_init(platform_pci_module_init);