aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/platform-pci.c
diff options
context:
space:
mode:
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>2010-05-17 12:08:21 -0400
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-07-22 19:46:09 -0400
commit183d03cc4ff39e0f0d952c09aa96d0abfd6e0c3c (patch)
tree75947fc4a9ac69e902663c9cb618993b7c656cff /drivers/xen/platform-pci.c
parent38e20b07efd541a959de367dc90a17f92ce2e8a6 (diff)
xen: Xen PCI platform device driver.
Add the xen pci platform device driver that is responsible for initializing the grant table and xenbus in PV on HVM mode. Few changes to xenbus and grant table are necessary to allow the delayed initialization in HVM mode. Grant table needs few additional modifications to work in HVM mode. The Xen PCI platform device raises an irq every time an event has been delivered to us. However these interrupts are only delivered to vcpu 0. The Xen PCI platform interrupt handler calls xen_hvm_evtchn_do_upcall that is a little wrapper around __xen_evtchn_do_upcall, the traditional Xen upcall handler, the very same used with traditional PV guests. When running on HVM the event channel upcall is never called while in progress because it is a normal Linux irq handler (and we cannot switch the irq chip wholesale to the Xen PV ones as we are running QEMU and might have passed in PCI devices), therefore we cannot be sure that evtchn_upcall_pending is 0 when returning. For this reason if evtchn_upcall_pending is set by Xen we need to loop again on the event channels set pending otherwise we might loose some event channel deliveries. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Signed-off-by: Sheng Yang <sheng@linux.intel.com> Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Diffstat (limited to 'drivers/xen/platform-pci.c')
-rw-r--r--drivers/xen/platform-pci.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c
new file mode 100644
index 000000000000..a0ee5d06f715
--- /dev/null
+++ b/drivers/xen/platform-pci.c
@@ -0,0 +1,181 @@
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 * Copyright (c) 2010, Citrix
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20 * Place - Suite 330, Boston, MA 02111-1307 USA.
21 *
22 */
23
24
25#include <linux/interrupt.h>
26#include <linux/io.h>
27#include <linux/module.h>
28#include <linux/pci.h>
29
30#include <xen/grant_table.h>
31#include <xen/xenbus.h>
32#include <xen/events.h>
33#include <xen/hvm.h>
34
35#define DRV_NAME "xen-platform-pci"
36
37MODULE_AUTHOR("ssmith@xensource.com and stefano.stabellini@eu.citrix.com");
38MODULE_DESCRIPTION("Xen platform PCI device");
39MODULE_LICENSE("GPL");
40
41static unsigned long platform_mmio;
42static unsigned long platform_mmio_alloc;
43static unsigned long platform_mmiolen;
44
45unsigned long alloc_xen_mmio(unsigned long len)
46{
47 unsigned long addr;
48
49 addr = platform_mmio + platform_mmio_alloc;
50 platform_mmio_alloc += len;
51 BUG_ON(platform_mmio_alloc > platform_mmiolen);
52
53 return addr;
54}
55
56static uint64_t get_callback_via(struct pci_dev *pdev)
57{
58 u8 pin;
59 int irq;
60
61 irq = pdev->irq;
62 if (irq < 16)
63 return irq; /* ISA IRQ */
64
65 pin = pdev->pin;
66
67 /* We don't know the GSI. Specify the PCI INTx line instead. */
68 return ((uint64_t)0x01 << 56) | /* PCI INTx identifier */
69 ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
70 ((uint64_t)pdev->bus->number << 16) |
71 ((uint64_t)(pdev->devfn & 0xff) << 8) |
72 ((uint64_t)(pin - 1) & 3);
73}
74
75static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
76{
77 xen_hvm_evtchn_do_upcall();
78 return IRQ_HANDLED;
79}
80
81static int xen_allocate_irq(struct pci_dev *pdev)
82{
83 return request_irq(pdev->irq, do_hvm_evtchn_intr,
84 IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
85 "xen-platform-pci", pdev);
86}
87
88static int __devinit platform_pci_init(struct pci_dev *pdev,
89 const struct pci_device_id *ent)
90{
91 int i, ret;
92 long ioaddr, iolen;
93 long mmio_addr, mmio_len;
94 uint64_t callback_via;
95 unsigned int max_nr_gframes;
96
97 i = pci_enable_device(pdev);
98 if (i)
99 return i;
100
101 ioaddr = pci_resource_start(pdev, 0);
102 iolen = pci_resource_len(pdev, 0);
103
104 mmio_addr = pci_resource_start(pdev, 1);
105 mmio_len = pci_resource_len(pdev, 1);
106
107 if (mmio_addr == 0 || ioaddr == 0) {
108 dev_err(&pdev->dev, "no resources found\n");
109 ret = -ENOENT;
110 goto pci_out;
111 }
112
113 if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) {
114 dev_err(&pdev->dev, "MEM I/O resource 0x%lx @ 0x%lx busy\n",
115 mmio_addr, mmio_len);
116 ret = -EBUSY;
117 goto pci_out;
118 }
119
120 if (request_region(ioaddr, iolen, DRV_NAME) == NULL) {
121 dev_err(&pdev->dev, "I/O resource 0x%lx @ 0x%lx busy\n",
122 iolen, ioaddr);
123 ret = -EBUSY;
124 goto mem_out;
125 }
126
127 platform_mmio = mmio_addr;
128 platform_mmiolen = mmio_len;
129
130 if (!xen_have_vector_callback) {
131 ret = xen_allocate_irq(pdev);
132 if (ret) {
133 dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret);
134 goto out;
135 }
136 callback_via = get_callback_via(pdev);
137 ret = xen_set_callback_via(callback_via);
138 if (ret) {
139 dev_warn(&pdev->dev, "Unable to set the evtchn callback "
140 "err=%d\n", ret);
141 goto out;
142 }
143 }
144
145 max_nr_gframes = gnttab_max_grant_frames();
146 xen_hvm_resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
147 ret = gnttab_init();
148 if (ret)
149 goto out;
150 xenbus_probe(NULL);
151 return 0;
152
153out:
154 release_region(ioaddr, iolen);
155mem_out:
156 release_mem_region(mmio_addr, mmio_len);
157pci_out:
158 pci_disable_device(pdev);
159 return ret;
160}
161
162static struct pci_device_id platform_pci_tbl[] __devinitdata = {
163 {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM,
164 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
165 {0,}
166};
167
168MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
169
170static struct pci_driver platform_driver = {
171 .name = DRV_NAME,
172 .probe = platform_pci_init,
173 .id_table = platform_pci_tbl,
174};
175
176static int __init platform_pci_module_init(void)
177{
178 return pci_register_driver(&platform_driver);
179}
180
181module_init(platform_pci_module_init);