drm_pci.c revision 1.3.4.2 1 1.3.4.2 rmind /* $NetBSD: drm_pci.c,v 1.3.4.2 2014/05/18 17:46:01 rmind Exp $ */
2 1.3.4.2 rmind
3 1.3.4.2 rmind /*-
4 1.3.4.2 rmind * Copyright (c) 2013 The NetBSD Foundation, Inc.
5 1.3.4.2 rmind * All rights reserved.
6 1.3.4.2 rmind *
7 1.3.4.2 rmind * This code is derived from software contributed to The NetBSD Foundation
8 1.3.4.2 rmind * by Taylor R. Campbell.
9 1.3.4.2 rmind *
10 1.3.4.2 rmind * Redistribution and use in source and binary forms, with or without
11 1.3.4.2 rmind * modification, are permitted provided that the following conditions
12 1.3.4.2 rmind * are met:
13 1.3.4.2 rmind * 1. Redistributions of source code must retain the above copyright
14 1.3.4.2 rmind * notice, this list of conditions and the following disclaimer.
15 1.3.4.2 rmind * 2. Redistributions in binary form must reproduce the above copyright
16 1.3.4.2 rmind * notice, this list of conditions and the following disclaimer in the
17 1.3.4.2 rmind * documentation and/or other materials provided with the distribution.
18 1.3.4.2 rmind *
19 1.3.4.2 rmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.3.4.2 rmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.3.4.2 rmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.3.4.2 rmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.3.4.2 rmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.3.4.2 rmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.3.4.2 rmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.3.4.2 rmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.3.4.2 rmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.3.4.2 rmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.3.4.2 rmind * POSSIBILITY OF SUCH DAMAGE.
30 1.3.4.2 rmind */
31 1.3.4.2 rmind
32 1.3.4.2 rmind #include <sys/cdefs.h>
33 1.3.4.2 rmind __KERNEL_RCSID(0, "$NetBSD: drm_pci.c,v 1.3.4.2 2014/05/18 17:46:01 rmind Exp $");
34 1.3.4.2 rmind
35 1.3.4.2 rmind #include <sys/types.h>
36 1.3.4.2 rmind #include <sys/errno.h>
37 1.3.4.2 rmind #include <sys/systm.h>
38 1.3.4.2 rmind
39 1.3.4.2 rmind #include <dev/pci/pcivar.h>
40 1.3.4.2 rmind
41 1.3.4.2 rmind #include <drm/drmP.h>
42 1.3.4.2 rmind
43 1.3.4.2 rmind static int drm_pci_get_irq(struct drm_device *);
44 1.3.4.2 rmind static int drm_pci_irq_install(struct drm_device *,
45 1.3.4.2 rmind irqreturn_t (*)(void *), int, const char *, void *,
46 1.3.4.2 rmind struct drm_bus_irq_cookie **);
47 1.3.4.2 rmind static void drm_pci_irq_uninstall(struct drm_device *,
48 1.3.4.2 rmind struct drm_bus_irq_cookie *);
49 1.3.4.2 rmind static const char *
50 1.3.4.2 rmind drm_pci_get_name(struct drm_device *);
51 1.3.4.2 rmind static int drm_pci_set_busid(struct drm_device *, struct drm_master *);
52 1.3.4.2 rmind static int drm_pci_set_unique(struct drm_device *, struct drm_master *,
53 1.3.4.2 rmind struct drm_unique *);
54 1.3.4.2 rmind static int drm_pci_irq_by_busid(struct drm_device *,
55 1.3.4.2 rmind struct drm_irq_busid *);
56 1.3.4.2 rmind static int drm_pci_agp_init(struct drm_device *);
57 1.3.4.2 rmind
58 1.3.4.2 rmind const struct drm_bus drm_pci_bus = {
59 1.3.4.2 rmind .bus_type = DRIVER_BUS_PCI,
60 1.3.4.2 rmind .get_irq = drm_pci_get_irq,
61 1.3.4.2 rmind .irq_install = drm_pci_irq_install,
62 1.3.4.2 rmind .irq_uninstall = drm_pci_irq_uninstall,
63 1.3.4.2 rmind .get_name = drm_pci_get_name,
64 1.3.4.2 rmind .set_busid = drm_pci_set_busid,
65 1.3.4.2 rmind .set_unique = drm_pci_set_unique,
66 1.3.4.2 rmind .irq_by_busid = drm_pci_irq_by_busid,
67 1.3.4.2 rmind .agp_init = drm_pci_agp_init,
68 1.3.4.2 rmind };
69 1.3.4.2 rmind
70 1.3.4.2 rmind static const struct pci_attach_args *
71 1.3.4.2 rmind drm_pci_attach_args(struct drm_device *dev)
72 1.3.4.2 rmind {
73 1.3.4.2 rmind return &dev->pdev->pd_pa;
74 1.3.4.2 rmind }
75 1.3.4.2 rmind
76 1.3.4.2 rmind int
77 1.3.4.2 rmind drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver __unused)
78 1.3.4.2 rmind {
79 1.3.4.2 rmind
80 1.3.4.2 rmind driver->bus = &drm_pci_bus;
81 1.3.4.2 rmind return 0;
82 1.3.4.2 rmind }
83 1.3.4.2 rmind
84 1.3.4.2 rmind void
85 1.3.4.2 rmind drm_pci_exit(struct drm_driver *driver __unused,
86 1.3.4.2 rmind struct pci_driver *pdriver __unused)
87 1.3.4.2 rmind {
88 1.3.4.2 rmind }
89 1.3.4.2 rmind
90 1.3.4.2 rmind /* XXX Should go elsewhere. */
91 1.3.4.2 rmind #define PCI_NMAPREGS ((PCI_MAPREG_END - PCI_MAPREG_START) / 4)
92 1.3.4.2 rmind
93 1.3.4.2 rmind void
94 1.3.4.2 rmind drm_pci_attach(device_t self, const struct pci_attach_args *pa,
95 1.3.4.2 rmind struct pci_dev *pdev, struct drm_device *dev)
96 1.3.4.2 rmind {
97 1.3.4.2 rmind unsigned int unit;
98 1.3.4.2 rmind
99 1.3.4.2 rmind linux_pci_dev_init(pdev, self, pa, 0);
100 1.3.4.2 rmind
101 1.3.4.2 rmind dev->pdev = pdev;
102 1.3.4.2 rmind dev->pci_vendor = pdev->vendor;
103 1.3.4.2 rmind dev->pci_device = pdev->device;
104 1.3.4.2 rmind
105 1.3.4.2 rmind /* XXX Set the power state to D0? */
106 1.3.4.2 rmind
107 1.3.4.2 rmind dev->bst = pa->pa_memt;
108 1.3.4.2 rmind /* XXX Let the driver say something about 32-bit vs 64-bit DMA? */
109 1.3.4.2 rmind dev->bus_dmat = (pci_dma64_available(pa)? pa->pa_dmat64 : pa->pa_dmat);
110 1.3.4.2 rmind dev->dmat = dev->bus_dmat;
111 1.3.4.2 rmind dev->dmat_subregion_p = false;
112 1.3.4.2 rmind
113 1.3.4.2 rmind CTASSERT(PCI_NMAPREGS < (SIZE_MAX / sizeof(dev->bus_maps[0])));
114 1.3.4.2 rmind dev->bus_nmaps = PCI_NMAPREGS;
115 1.3.4.2 rmind dev->bus_maps = kmem_zalloc((PCI_NMAPREGS * sizeof(dev->bus_maps[0])),
116 1.3.4.2 rmind KM_SLEEP);
117 1.3.4.2 rmind for (unit = 0; unit < dev->bus_nmaps; unit++) {
118 1.3.4.2 rmind struct drm_bus_map *const bm = &dev->bus_maps[unit];
119 1.3.4.2 rmind const int reg = PCI_BAR(unit);
120 1.3.4.2 rmind const pcireg_t type =
121 1.3.4.2 rmind pci_mapreg_type(pa->pa_pc, pa->pa_tag, reg);
122 1.3.4.2 rmind
123 1.3.4.2 rmind /* Reject non-memory mappings. */
124 1.3.4.2 rmind if ((type & PCI_MAPREG_TYPE_MEM) != PCI_MAPREG_TYPE_MEM) {
125 1.3.4.2 rmind aprint_debug_dev(self, "map %u has non-memory type:"
126 1.3.4.2 rmind " 0x%"PRIxMAX"\n", unit, (uintmax_t)type);
127 1.3.4.2 rmind continue;
128 1.3.4.2 rmind }
129 1.3.4.2 rmind
130 1.3.4.2 rmind /* Inquire about it. We'll map it in drm_ioremap. */
131 1.3.4.2 rmind if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, type,
132 1.3.4.2 rmind &bm->bm_base, &bm->bm_size, &bm->bm_flags) != 0) {
133 1.3.4.2 rmind aprint_debug_dev(self, "map %u failed\n", unit);
134 1.3.4.2 rmind continue;
135 1.3.4.2 rmind }
136 1.3.4.2 rmind
137 1.3.4.2 rmind aprint_debug_dev(self, "map %u at %"PRIxMAX" size %"PRIxMAX
138 1.3.4.2 rmind " flags 0x%"PRIxMAX"\n",
139 1.3.4.2 rmind unit, (uintmax_t)bm->bm_base, (uintmax_t)bm->bm_size,
140 1.3.4.2 rmind (uintmax_t)bm->bm_flags);
141 1.3.4.2 rmind
142 1.3.4.2 rmind /* Assume since it is a memory mapping it can be linear. */
143 1.3.4.2 rmind bm->bm_flags |= BUS_SPACE_MAP_LINEAR;
144 1.3.4.2 rmind }
145 1.3.4.2 rmind
146 1.3.4.2 rmind /* All `agp' maps are just initialized to zero. */
147 1.3.4.2 rmind CTASSERT(PCI_NMAPREGS < (SIZE_MAX / sizeof(dev->agp_maps[0])));
148 1.3.4.2 rmind dev->agp_nmaps = PCI_NMAPREGS;
149 1.3.4.2 rmind dev->agp_maps = kmem_zalloc((PCI_NMAPREGS * sizeof(dev->agp_maps[0])),
150 1.3.4.2 rmind KM_SLEEP);
151 1.3.4.2 rmind }
152 1.3.4.2 rmind
153 1.3.4.2 rmind int
154 1.3.4.2 rmind drm_pci_detach(struct drm_device *dev __unused, int flags __unused)
155 1.3.4.2 rmind {
156 1.3.4.2 rmind
157 1.3.4.2 rmind kmem_free(dev->bus_maps, (PCI_NMAPREGS * sizeof(dev->bus_maps[0])));
158 1.3.4.2 rmind kmem_free(dev->agp_maps, (PCI_NMAPREGS * sizeof(dev->agp_maps[0])));
159 1.3.4.2 rmind
160 1.3.4.2 rmind /*
161 1.3.4.2 rmind * XXX This is the wrong place! Should be a routine in
162 1.3.4.2 rmind * drm_memory.c.
163 1.3.4.2 rmind */
164 1.3.4.2 rmind if (dev->dmat_subregion_p)
165 1.3.4.2 rmind bus_dmatag_destroy(dev->dmat);
166 1.3.4.2 rmind
167 1.3.4.2 rmind /* XXX Disestablish irqs or anything? */
168 1.3.4.2 rmind return 0;
169 1.3.4.2 rmind }
170 1.3.4.2 rmind
171 1.3.4.2 rmind static int
172 1.3.4.2 rmind drm_pci_get_irq(struct drm_device *dev)
173 1.3.4.2 rmind {
174 1.3.4.2 rmind pci_intr_handle_t ih_pih;
175 1.3.4.2 rmind int ih_int;
176 1.3.4.2 rmind
177 1.3.4.2 rmind /*
178 1.3.4.2 rmind * This is a compile-time assertion that the types match. If
179 1.3.4.2 rmind * this fails, we have to change a bunch of drm code that uses
180 1.3.4.2 rmind * int for intr handles.
181 1.3.4.2 rmind */
182 1.3.4.2 rmind KASSERT(&ih_pih != &ih_int);
183 1.3.4.2 rmind
184 1.3.4.2 rmind if (pci_intr_map(drm_pci_attach_args(dev), &ih_pih))
185 1.3.4.2 rmind return -1; /* XXX Hope -1 is an invalid intr handle. */
186 1.3.4.2 rmind
187 1.3.4.2 rmind ih_int = ih_pih;
188 1.3.4.2 rmind return ih_int;
189 1.3.4.2 rmind }
190 1.3.4.2 rmind
191 1.3.4.2 rmind static int
192 1.3.4.2 rmind drm_pci_irq_install(struct drm_device *dev, irqreturn_t (*handler)(void *),
193 1.3.4.2 rmind int flags, const char *name, void *arg,
194 1.3.4.2 rmind struct drm_bus_irq_cookie **cookiep)
195 1.3.4.2 rmind {
196 1.3.4.2 rmind const struct pci_attach_args *const pa = drm_pci_attach_args(dev);
197 1.3.4.2 rmind pci_intr_handle_t ih;
198 1.3.4.2 rmind const char *intrstr;
199 1.3.4.2 rmind void *ih_cookie;
200 1.3.4.2 rmind char intrbuf[PCI_INTRSTR_LEN];
201 1.3.4.2 rmind
202 1.3.4.2 rmind if (pci_intr_map(pa, &ih))
203 1.3.4.2 rmind return -ENOENT;
204 1.3.4.2 rmind
205 1.3.4.2 rmind intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf));
206 1.3.4.2 rmind ih_cookie = pci_intr_establish(pa->pa_pc, ih, IPL_DRM, handler, arg);
207 1.3.4.2 rmind if (ih_cookie == NULL) {
208 1.3.4.2 rmind aprint_error_dev(dev->dev,
209 1.3.4.2 rmind "couldn't establish interrupt at %s (%s)\n",
210 1.3.4.2 rmind intrstr, name);
211 1.3.4.2 rmind return -ENOENT;
212 1.3.4.2 rmind }
213 1.3.4.2 rmind
214 1.3.4.2 rmind aprint_normal_dev(dev->dev, "interrupting at %s (%s)\n",
215 1.3.4.2 rmind intrstr, name);
216 1.3.4.2 rmind *cookiep = (struct drm_bus_irq_cookie *)ih_cookie;
217 1.3.4.2 rmind return 0;
218 1.3.4.2 rmind }
219 1.3.4.2 rmind
220 1.3.4.2 rmind static void
221 1.3.4.2 rmind drm_pci_irq_uninstall(struct drm_device *dev,
222 1.3.4.2 rmind struct drm_bus_irq_cookie *cookie)
223 1.3.4.2 rmind {
224 1.3.4.2 rmind const struct pci_attach_args *pa = drm_pci_attach_args(dev);
225 1.3.4.2 rmind
226 1.3.4.2 rmind pci_intr_disestablish(pa->pa_pc, (void *)cookie);
227 1.3.4.2 rmind }
228 1.3.4.2 rmind
229 1.3.4.2 rmind static const char *
230 1.3.4.2 rmind drm_pci_get_name(struct drm_device *dev)
231 1.3.4.2 rmind {
232 1.3.4.2 rmind return "pci"; /* XXX PCI bus names? */
233 1.3.4.2 rmind }
234 1.3.4.2 rmind
235 1.3.4.2 rmind static int
236 1.3.4.2 rmind drm_pci_format_unique(struct drm_device *dev, char *buf, size_t size)
237 1.3.4.2 rmind {
238 1.3.4.2 rmind const unsigned int domain = 0; /* XXX PCI domains? */
239 1.3.4.2 rmind const unsigned int bus = dev->pdev->pd_pa.pa_bus;
240 1.3.4.2 rmind const unsigned int device = dev->pdev->pd_pa.pa_device;
241 1.3.4.2 rmind const unsigned int function = dev->pdev->pd_pa.pa_function;
242 1.3.4.2 rmind
243 1.3.4.2 rmind return snprintf(buf, size, "pci:%04x:%02x:%02x.%d",
244 1.3.4.2 rmind domain, bus, device, function);
245 1.3.4.2 rmind }
246 1.3.4.2 rmind
247 1.3.4.2 rmind static int
248 1.3.4.2 rmind drm_pci_format_devname(struct drm_device *dev, const char *unique,
249 1.3.4.2 rmind char *buf, size_t size)
250 1.3.4.2 rmind {
251 1.3.4.2 rmind
252 1.3.4.2 rmind return snprintf(buf, size, "%s@%s",
253 1.3.4.2 rmind device_xname(device_parent(dev->dev)),
254 1.3.4.2 rmind unique);
255 1.3.4.2 rmind }
256 1.3.4.2 rmind
257 1.3.4.2 rmind static int
258 1.3.4.2 rmind drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
259 1.3.4.2 rmind {
260 1.3.4.2 rmind int n;
261 1.3.4.2 rmind char *buf;
262 1.3.4.2 rmind
263 1.3.4.2 rmind n = drm_pci_format_unique(dev, NULL, 0);
264 1.3.4.2 rmind if (n < 0)
265 1.3.4.2 rmind return -ENOSPC; /* XXX */
266 1.3.4.2 rmind if (0xff < n)
267 1.3.4.2 rmind n = 0xff;
268 1.3.4.2 rmind
269 1.3.4.2 rmind buf = kzalloc(n + 1, GFP_KERNEL);
270 1.3.4.2 rmind (void)drm_pci_format_unique(dev, buf, n + 1);
271 1.3.4.2 rmind
272 1.3.4.2 rmind if (master->unique)
273 1.3.4.2 rmind kfree(master->unique);
274 1.3.4.2 rmind master->unique = buf;
275 1.3.4.2 rmind master->unique_len = n;
276 1.3.4.2 rmind master->unique_size = n + 1;
277 1.3.4.2 rmind
278 1.3.4.2 rmind n = drm_pci_format_devname(dev, master->unique, NULL, 0);
279 1.3.4.2 rmind if (n < 0)
280 1.3.4.2 rmind return -ENOSPC; /* XXX back out? */
281 1.3.4.2 rmind if (0xff < n)
282 1.3.4.2 rmind n = 0xff;
283 1.3.4.2 rmind
284 1.3.4.2 rmind buf = kzalloc(n + 1, GFP_KERNEL);
285 1.3.4.2 rmind (void)drm_pci_format_devname(dev, master->unique, buf, n + 1);
286 1.3.4.2 rmind
287 1.3.4.2 rmind if (dev->devname)
288 1.3.4.2 rmind kfree(dev->devname);
289 1.3.4.2 rmind dev->devname = buf;
290 1.3.4.2 rmind
291 1.3.4.2 rmind return 0;
292 1.3.4.2 rmind }
293 1.3.4.2 rmind
294 1.3.4.2 rmind static int
295 1.3.4.2 rmind drm_pci_set_unique(struct drm_device *dev, struct drm_master *master,
296 1.3.4.2 rmind struct drm_unique *unique __unused)
297 1.3.4.2 rmind {
298 1.3.4.2 rmind
299 1.3.4.2 rmind /*
300 1.3.4.2 rmind * XXX This is silly. We're supposed to reject unique names
301 1.3.4.2 rmind * that don't match the ones we would generate anyway. For
302 1.3.4.2 rmind * expedience, we'll just generate the one we would and ignore
303 1.3.4.2 rmind * whatever userland threw at us...
304 1.3.4.2 rmind */
305 1.3.4.2 rmind return drm_pci_set_busid(dev, master);
306 1.3.4.2 rmind }
307 1.3.4.2 rmind
308 1.3.4.2 rmind static int
309 1.3.4.2 rmind drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *busid)
310 1.3.4.2 rmind {
311 1.3.4.2 rmind return -ENOSYS; /* XXX */
312 1.3.4.2 rmind }
313 1.3.4.2 rmind
314 1.3.4.2 rmind static int
315 1.3.4.2 rmind drm_pci_agp_init(struct drm_device *dev)
316 1.3.4.2 rmind {
317 1.3.4.2 rmind return 0; /* XXX */
318 1.3.4.2 rmind }
319