xref: /openbmc/linux/drivers/xen/platform-pci.c (revision 4d75f5c664195b970e1cd2fd25b65b5eff257a0a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /******************************************************************************
3  * platform-pci.c
4  *
5  * Xen platform PCI device driver
6  *
7  * Authors: ssmith@xensource.com and stefano.stabellini@eu.citrix.com
8  *
9  * Copyright (c) 2005, Intel Corporation.
10  * Copyright (c) 2007, XenSource Inc.
11  * Copyright (c) 2010, Citrix
12  */
13 
14 
15 #include <linux/interrupt.h>
16 #include <linux/io.h>
17 #include <linux/init.h>
18 #include <linux/pci.h>
19 
20 #include <xen/platform_pci.h>
21 #include <xen/grant_table.h>
22 #include <xen/xenbus.h>
23 #include <xen/events.h>
24 #include <xen/hvm.h>
25 #include <xen/xen-ops.h>
26 
27 #define DRV_NAME    "xen-platform-pci"
28 
29 #define PCI_DEVICE_ID_XEN_PLATFORM_XS61	0x0002
30 
31 static unsigned long platform_mmio;
32 static unsigned long platform_mmio_alloc;
33 static unsigned long platform_mmiolen;
34 static uint64_t callback_via;
35 
alloc_xen_mmio(unsigned long len)36 static unsigned long alloc_xen_mmio(unsigned long len)
37 {
38 	unsigned long addr;
39 
40 	addr = platform_mmio + platform_mmio_alloc;
41 	platform_mmio_alloc += len;
42 	BUG_ON(platform_mmio_alloc > platform_mmiolen);
43 
44 	return addr;
45 }
46 
get_callback_via(struct pci_dev * pdev)47 static uint64_t get_callback_via(struct pci_dev *pdev)
48 {
49 	u8 pin;
50 	int irq;
51 
52 	irq = pdev->irq;
53 	if (irq < 16)
54 		return irq; /* ISA IRQ */
55 
56 	pin = pdev->pin;
57 
58 	/* We don't know the GSI. Specify the PCI INTx line instead. */
59 	return ((uint64_t)HVM_PARAM_CALLBACK_TYPE_PCI_INTX <<
60 			  HVM_CALLBACK_VIA_TYPE_SHIFT) |
61 		((uint64_t)pci_domain_nr(pdev->bus) << 32) |
62 		((uint64_t)pdev->bus->number << 16) |
63 		((uint64_t)(pdev->devfn & 0xff) << 8) |
64 		((uint64_t)(pin - 1) & 3);
65 }
66 
do_hvm_evtchn_intr(int irq,void * dev_id)67 static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
68 {
69 	return xen_evtchn_do_upcall();
70 }
71 
xen_allocate_irq(struct pci_dev * pdev)72 static int xen_allocate_irq(struct pci_dev *pdev)
73 {
74 	return request_irq(pdev->irq, do_hvm_evtchn_intr,
75 			IRQF_NOBALANCING | IRQF_SHARED,
76 			"xen-platform-pci", pdev);
77 }
78 
platform_pci_resume(struct device * dev)79 static int platform_pci_resume(struct device *dev)
80 {
81 	int err;
82 
83 	if (xen_have_vector_callback)
84 		return 0;
85 
86 	err = xen_set_callback_via(callback_via);
87 	if (err) {
88 		dev_err(dev, "platform_pci_resume failure!\n");
89 		return err;
90 	}
91 	return 0;
92 }
93 
platform_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)94 static int platform_pci_probe(struct pci_dev *pdev,
95 			      const struct pci_device_id *ent)
96 {
97 	int i, ret;
98 	long ioaddr;
99 	long mmio_addr, mmio_len;
100 	unsigned int max_nr_gframes;
101 	unsigned long grant_frames;
102 
103 	if (!xen_domain())
104 		return -ENODEV;
105 
106 	i = pci_enable_device(pdev);
107 	if (i)
108 		return i;
109 
110 	ioaddr = pci_resource_start(pdev, 0);
111 
112 	mmio_addr = pci_resource_start(pdev, 1);
113 	mmio_len = pci_resource_len(pdev, 1);
114 
115 	if (mmio_addr == 0 || ioaddr == 0) {
116 		dev_err(&pdev->dev, "no resources found\n");
117 		ret = -ENOENT;
118 		goto pci_out;
119 	}
120 
121 	ret = pci_request_region(pdev, 1, DRV_NAME);
122 	if (ret < 0)
123 		goto pci_out;
124 
125 	ret = pci_request_region(pdev, 0, DRV_NAME);
126 	if (ret < 0)
127 		goto mem_out;
128 
129 	platform_mmio = mmio_addr;
130 	platform_mmiolen = mmio_len;
131 	if (!xen_have_vector_callback) {
132 		ret = xen_allocate_irq(pdev);
133 		if (ret) {
134 			dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret);
135 			goto out;
136 		}
137 		/*
138 		 * It doesn't strictly *have* to run on CPU0 but it sure
139 		 * as hell better process the event channel ports delivered
140 		 * to CPU0.
141 		 */
142 		irq_set_affinity(pdev->irq, cpumask_of(0));
143 
144 		callback_via = get_callback_via(pdev);
145 		ret = xen_set_callback_via(callback_via);
146 		if (ret) {
147 			dev_warn(&pdev->dev, "Unable to set the evtchn callback "
148 					 "err=%d\n", ret);
149 			goto irq_out;
150 		}
151 	}
152 
153 	max_nr_gframes = gnttab_max_grant_frames();
154 	grant_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
155 	ret = gnttab_setup_auto_xlat_frames(grant_frames);
156 	if (ret)
157 		goto irq_out;
158 	ret = gnttab_init();
159 	if (ret)
160 		goto grant_out;
161 	return 0;
162 grant_out:
163 	gnttab_free_auto_xlat_frames();
164 irq_out:
165 	if (!xen_have_vector_callback)
166 		free_irq(pdev->irq, pdev);
167 out:
168 	pci_release_region(pdev, 0);
169 mem_out:
170 	pci_release_region(pdev, 1);
171 pci_out:
172 	pci_disable_device(pdev);
173 	return ret;
174 }
175 
176 static const struct pci_device_id platform_pci_tbl[] = {
177 	{PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM,
178 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
179 	{PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM_XS61,
180 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
181 	{0,}
182 };
183 
184 static const struct dev_pm_ops platform_pm_ops = {
185 	.resume_noirq =   platform_pci_resume,
186 };
187 
188 static struct pci_driver platform_driver = {
189 	.name =           DRV_NAME,
190 	.probe =          platform_pci_probe,
191 	.id_table =       platform_pci_tbl,
192 	.driver = {
193 		.pm =     &platform_pm_ops,
194 	},
195 };
196 
197 builtin_pci_driver(platform_driver);
198