ia64/xen-unstable

view unmodified_drivers/linux-2.6/platform-pci/platform-pci.c @ 13405:c6cea93d3cd9

[PV-on-HVM] Allow platform interrupt to be used for entropy.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Jan 12 14:40:13 2007 +0000 (2007-01-12)
parents 5c5d9692f559
children a2b2b2a011f1
line source
1 /******************************************************************************
2 * evtchn-pci.c
3 * xen event channel fake PCI device driver
4 * Copyright (C) 2005, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 *
19 */
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/sched.h>
24 #include <linux/errno.h>
25 #include <linux/pci.h>
26 #include <linux/init.h>
27 #include <linux/version.h>
28 #include <linux/interrupt.h>
29 #include <linux/vmalloc.h>
30 #include <linux/mm.h>
31 #include <asm/system.h>
32 #include <asm/io.h>
33 #include <asm/irq.h>
34 #include <asm/uaccess.h>
35 #include <asm/hypervisor.h>
36 #include <asm/pgtable.h>
37 #include <xen/interface/memory.h>
38 #include <xen/features.h>
39 #ifdef __ia64__
40 #include <asm/xen/xencomm.h>
41 #endif
43 #include "platform-pci.h"
45 #ifdef HAVE_XEN_PLATFORM_COMPAT_H
46 #include <xen/platform-compat.h>
47 #endif
49 #define DRV_NAME "xen-platform-pci"
50 #define DRV_VERSION "0.10"
51 #define DRV_RELDATE "03/03/2005"
53 char *hypercall_stubs;
54 EXPORT_SYMBOL(hypercall_stubs);
56 // Used to be xiaofeng.ling@intel.com
57 MODULE_AUTHOR("ssmith@xensource.com");
58 MODULE_DESCRIPTION("Xen platform PCI device");
59 MODULE_LICENSE("GPL");
61 unsigned long *phys_to_machine_mapping;
62 EXPORT_SYMBOL(phys_to_machine_mapping);
64 static int __init init_xen_info(void)
65 {
66 unsigned long shared_info_frame;
67 struct xen_add_to_physmap xatp;
68 extern void *shared_info_area;
70 #ifdef __ia64__
71 xencomm_init();
72 #endif
74 setup_xen_features();
76 shared_info_frame = alloc_xen_mmio(PAGE_SIZE) >> PAGE_SHIFT;
77 xatp.domid = DOMID_SELF;
78 xatp.idx = 0;
79 xatp.space = XENMAPSPACE_shared_info;
80 xatp.gpfn = shared_info_frame;
81 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
82 BUG();
84 shared_info_area =
85 ioremap(shared_info_frame << PAGE_SHIFT, PAGE_SIZE);
86 if (shared_info_area == NULL)
87 panic("can't map shared info\n");
89 phys_to_machine_mapping = NULL;
91 gnttab_init();
93 return 0;
94 }
96 static void __devexit platform_pci_remove(struct pci_dev *pdev)
97 {
98 long ioaddr, iolen;
99 long mmio_addr, mmio_len;
101 ioaddr = pci_resource_start(pdev, 0);
102 iolen = pci_resource_len(pdev, 0);
103 mmio_addr = pci_resource_start(pdev, 1);
104 mmio_len = pci_resource_len(pdev, 1);
106 release_region(ioaddr, iolen);
107 release_mem_region(mmio_addr, mmio_len);
109 pci_set_drvdata(pdev, NULL);
110 free_irq(pdev->irq, pdev);
111 }
113 static unsigned long platform_mmio;
114 static unsigned long platform_mmio_alloc;
115 static unsigned long platform_mmiolen;
117 unsigned long alloc_xen_mmio(unsigned long len)
118 {
119 unsigned long addr;
121 addr = 0;
122 if (platform_mmio_alloc + len <= platform_mmiolen)
123 {
124 addr = platform_mmio + platform_mmio_alloc;
125 platform_mmio_alloc += len;
126 } else {
127 panic("ran out of xen mmio space");
128 }
129 return addr;
130 }
132 #ifndef __ia64__
133 /* Lifted from hvmloader.c */
134 static int get_hypercall_stubs(void)
135 {
136 uint32_t eax, ebx, ecx, edx, pages, msr, i;
137 char signature[13];
139 cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
140 *(uint32_t*)(signature + 0) = ebx;
141 *(uint32_t*)(signature + 4) = ecx;
142 *(uint32_t*)(signature + 8) = edx;
143 signature[12] = 0;
145 if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
146 printk(KERN_WARNING
147 "Detected Xen platform device but not Xen VMM?"
148 " (sig %s, eax %x)\n",
149 signature, eax);
150 return -EINVAL;
151 }
153 cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
155 printk(KERN_INFO "Xen version %d.%d.\n", eax >> 16, eax & 0xffff);
157 cpuid(0x40000002, &pages, &msr, &ecx, &edx);
159 printk(KERN_INFO "Hypercall area is %u pages.\n", pages);
161 /* Use __vmalloc() because vmalloc_exec() is not an exported symbol. */
162 /* PAGE_KERNEL_EXEC also is not exported, hence we use PAGE_KERNEL. */
163 /* hypercall_stubs = vmalloc_exec(pages * PAGE_SIZE); */
164 hypercall_stubs = __vmalloc(pages * PAGE_SIZE,
165 GFP_KERNEL | __GFP_HIGHMEM,
166 __pgprot(__PAGE_KERNEL & ~_PAGE_NX));
167 if (hypercall_stubs == NULL)
168 return -ENOMEM;
170 for (i = 0; i < pages; i++) {
171 unsigned long pfn;
172 pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
173 wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
174 }
176 return 0;
177 }
178 #else /* __ia64__ */
179 #define get_hypercall_stubs() (0)
180 #endif
182 static uint64_t get_callback_via(struct pci_dev *pdev)
183 {
184 #ifdef __ia64__
185 int irq;
186 for (irq = 0; irq < 16; irq++) {
187 if (isa_irq_to_vector(irq) == pdev->irq)
188 return irq;
189 }
190 return 0;
191 #else /* !__ia64__ */
192 if (pdev->irq < 16)
193 return pdev->irq; /* ISA IRQ */
194 /* We don't know the GSI. Specify the PCI INTx line instead. */
195 return (((uint64_t)0x01 << 56) | /* PCI INTx identifier */
196 ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
197 ((uint64_t)pdev->bus->number << 16) |
198 ((uint64_t)(pdev->devfn & 0xff) << 8) |
199 ((uint64_t)(pdev->pin - 1) & 3));
200 #endif
201 }
203 static int __devinit platform_pci_init(struct pci_dev *pdev,
204 const struct pci_device_id *ent)
205 {
206 int i, ret;
207 long ioaddr, iolen;
208 long mmio_addr, mmio_len;
209 uint64_t callback_via;
211 i = pci_enable_device(pdev);
212 if (i)
213 return i;
215 ioaddr = pci_resource_start(pdev, 0);
216 iolen = pci_resource_len(pdev, 0);
218 mmio_addr = pci_resource_start(pdev, 1);
219 mmio_len = pci_resource_len(pdev, 1);
221 callback_via = get_callback_via(pdev);
223 if (mmio_addr == 0 || ioaddr == 0 || callback_via == 0) {
224 printk(KERN_WARNING DRV_NAME ":no resources found\n");
225 return -ENOENT;
226 }
228 if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL)
229 {
230 printk(KERN_ERR ":MEM I/O resource 0x%lx @ 0x%lx busy\n",
231 mmio_addr, mmio_len);
232 return -EBUSY;
233 }
235 if (request_region(ioaddr, iolen, DRV_NAME) == NULL)
236 {
237 printk(KERN_ERR DRV_NAME ":I/O resource 0x%lx @ 0x%lx busy\n",
238 iolen, ioaddr);
239 release_mem_region(mmio_addr, mmio_len);
240 return -EBUSY;
241 }
243 platform_mmio = mmio_addr;
244 platform_mmiolen = mmio_len;
246 ret = get_hypercall_stubs();
247 if (ret < 0)
248 goto out;
250 if ((ret = init_xen_info()))
251 goto out;
253 if ((ret = request_irq(pdev->irq, evtchn_interrupt,
254 SA_SHIRQ | SA_SAMPLE_RANDOM,
255 "xen-platform-pci", pdev)))
256 goto out;
258 if ((ret = set_callback_via(callback_via)))
259 goto out;
261 out:
262 if (ret) {
263 release_mem_region(mmio_addr, mmio_len);
264 release_region(ioaddr, iolen);
265 }
267 return ret;
268 }
270 #define XEN_PLATFORM_VENDOR_ID 0x5853
271 #define XEN_PLATFORM_DEVICE_ID 0x0001
272 static struct pci_device_id platform_pci_tbl[] __devinitdata = {
273 {XEN_PLATFORM_VENDOR_ID, XEN_PLATFORM_DEVICE_ID,
274 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
275 /* Continue to recognise the old ID for now */
276 {0xfffd, 0x0101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
277 {0,}
278 };
280 MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
282 static struct pci_driver platform_driver = {
283 name: DRV_NAME,
284 probe: platform_pci_init,
285 remove: __devexit_p(platform_pci_remove),
286 id_table: platform_pci_tbl,
287 };
289 static int pci_device_registered;
291 static int __init platform_pci_module_init(void)
292 {
293 int rc;
295 rc = pci_module_init(&platform_driver);
296 if (rc)
297 printk(KERN_INFO DRV_NAME ":No platform pci device model found\n");
298 else
299 pci_device_registered = 1;
301 return rc;
302 }
304 static void __exit platform_pci_module_cleanup(void)
305 {
306 printk(KERN_INFO DRV_NAME ":Do platform module cleanup\n");
307 /* disable hypervisor for callback irq */
308 set_callback_via(0);
309 if (pci_device_registered)
310 pci_unregister_driver(&platform_driver);
311 }
313 module_init(platform_pci_module_init);
314 module_exit(platform_pci_module_cleanup);