xref: /freebsd/sys/dev/drm2/drm_pci.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1 /* drm_pci.h -- PCI DMA memory management wrappers for DRM -*- linux-c -*- */
2 /**
3  * \file drm_pci.c
4  * \brief Functions and ioctls to manage PCI memory
5  *
6  * \warning These interfaces aren't stable yet.
7  *
8  * \todo Implement the remaining ioctl's for the PCI pools.
9  * \todo The wrappers here are so thin that they would be better off inlined..
10  *
11  * \author José Fonseca <jrfonseca@tungstengraphics.com>
12  * \author Leif Delgass <ldelgass@retinalburn.net>
13  */
14 
15 /*
16  * Copyright 2003 José Fonseca.
17  * Copyright 2003 Leif Delgass.
18  * All Rights Reserved.
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining a
21  * copy of this software and associated documentation files (the "Software"),
22  * to deal in the Software without restriction, including without limitation
23  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
24  * and/or sell copies of the Software, and to permit persons to whom the
25  * Software is furnished to do so, subject to the following conditions:
26  *
27  * The above copyright notice and this permission notice (including the next
28  * paragraph) shall be included in all copies or substantial portions of the
29  * Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
34  * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37  */
38 
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41 
42 #include <dev/drm2/drmP.h>
43 
44 static int drm_msi = 1;	/* Enable by default. */
45 SYSCTL_NODE(_hw, OID_AUTO, drm, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
46     "DRM device");
47 SYSCTL_INT(_hw_drm, OID_AUTO, msi, CTLFLAG_RDTUN, &drm_msi, 1,
48     "Enable MSI interrupts for drm devices");
49 
50 /**********************************************************************/
51 /** \name PCI memory */
52 /*@{*/
53 
54 static void
55 drm_pci_busdma_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
56 {
57 	drm_dma_handle_t *dmah = arg;
58 
59 	if (error != 0)
60 		return;
61 
62 	KASSERT(nsegs == 1, ("drm_pci_busdma_callback: bad dma segment count"));
63 	dmah->busaddr = segs[0].ds_addr;
64 }
65 
66 /**
67  * \brief Allocate a PCI consistent memory block, for DMA.
68  */
69 drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size,
70     size_t align, dma_addr_t maxaddr)
71 {
72 	drm_dma_handle_t *dmah;
73 	int ret;
74 
75 	/* Need power-of-two alignment, so fail the allocation if it isn't. */
76 	if ((align & (align - 1)) != 0) {
77 		DRM_ERROR("drm_pci_alloc with non-power-of-two alignment %d\n",
78 		    (int)align);
79 		return NULL;
80 	}
81 
82 	dmah = malloc(sizeof(drm_dma_handle_t), DRM_MEM_DMA, M_ZERO | M_NOWAIT);
83 	if (dmah == NULL)
84 		return NULL;
85 
86 	/* Make sure we aren't holding mutexes here */
87 	mtx_assert(&dev->dma_lock, MA_NOTOWNED);
88 	if (mtx_owned(&dev->dma_lock))
89 	    DRM_ERROR("called while holding dma_lock\n");
90 
91 	ret = bus_dma_tag_create(
92 	    bus_get_dma_tag(dev->dev), /* parent */
93 	    align, 0, /* align, boundary */
94 	    maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
95 	    NULL, NULL, /* filtfunc, filtfuncargs */
96 	    size, 1, size, /* maxsize, nsegs, maxsegsize */
97 	    0, NULL, NULL, /* flags, lockfunc, lockfuncargs */
98 	    &dmah->tag);
99 	if (ret != 0) {
100 		free(dmah, DRM_MEM_DMA);
101 		return NULL;
102 	}
103 
104 	ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr,
105 	    BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map);
106 	if (ret != 0) {
107 		bus_dma_tag_destroy(dmah->tag);
108 		free(dmah, DRM_MEM_DMA);
109 		return NULL;
110 	}
111 
112 	ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size,
113 	    drm_pci_busdma_callback, dmah, BUS_DMA_NOWAIT);
114 	if (ret != 0) {
115 		bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
116 		bus_dma_tag_destroy(dmah->tag);
117 		free(dmah, DRM_MEM_DMA);
118 		return NULL;
119 	}
120 
121 	return dmah;
122 }
123 
124 EXPORT_SYMBOL(drm_pci_alloc);
125 
126 /**
127  * \brief Free a PCI consistent memory block without freeing its descriptor.
128  *
129  * This function is for internal use in the Linux-specific DRM core code.
130  */
131 void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
132 {
133 	if (dmah == NULL)
134 		return;
135 
136 	bus_dmamap_unload(dmah->tag, dmah->map);
137 	bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
138 	bus_dma_tag_destroy(dmah->tag);
139 }
140 
141 /**
142  * \brief Free a PCI consistent memory block
143  */
144 void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
145 {
146 	__drm_pci_free(dev, dmah);
147 	free(dmah, DRM_MEM_DMA);
148 }
149 
150 EXPORT_SYMBOL(drm_pci_free);
151 
152 static int drm_get_pci_domain(struct drm_device *dev)
153 {
154 	return dev->pci_domain;
155 }
156 
157 static int drm_pci_get_irq(struct drm_device *dev)
158 {
159 
160 	if (dev->irqr)
161 		return (dev->irq);
162 
163 	dev->irqr = bus_alloc_resource_any(dev->dev, SYS_RES_IRQ,
164 	    &dev->irqrid, RF_SHAREABLE);
165 	if (!dev->irqr) {
166 		dev_err(dev->dev, "Failed to allocate IRQ\n");
167 		return (0);
168 	}
169 
170 	dev->irq = (int) rman_get_start(dev->irqr);
171 
172 	return (dev->irq);
173 }
174 
175 static void drm_pci_free_irq(struct drm_device *dev)
176 {
177 	if (dev->irqr == NULL)
178 		return;
179 
180 	bus_release_resource(dev->dev, SYS_RES_IRQ,
181 	    dev->irqrid, dev->irqr);
182 
183 	dev->irqr = NULL;
184 	dev->irq = 0;
185 }
186 
187 static const char *drm_pci_get_name(struct drm_device *dev)
188 {
189 	return dev->driver->name;
190 }
191 
192 int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
193 {
194 	int len, ret;
195 	master->unique_len = 40;
196 	master->unique_size = master->unique_len;
197 	master->unique = malloc(master->unique_size, DRM_MEM_DRIVER, M_NOWAIT);
198 	if (master->unique == NULL)
199 		return -ENOMEM;
200 
201 
202 	len = snprintf(master->unique, master->unique_len,
203 		       "pci:%04x:%02x:%02x.%d",
204 		       dev->pci_domain,
205 		       dev->pci_bus,
206 		       dev->pci_slot,
207 		       dev->pci_func);
208 
209 	if (len >= master->unique_len) {
210 		DRM_ERROR("buffer overflow");
211 		ret = -EINVAL;
212 		goto err;
213 	} else
214 		master->unique_len = len;
215 
216 	return 0;
217 err:
218 	return ret;
219 }
220 
221 int drm_pci_set_unique(struct drm_device *dev,
222 		       struct drm_master *master,
223 		       struct drm_unique *u)
224 {
225 	int domain, bus, slot, func, ret;
226 
227 	master->unique_len = u->unique_len;
228 	master->unique_size = u->unique_len + 1;
229 	master->unique = malloc(master->unique_size, DRM_MEM_DRIVER, M_WAITOK);
230 	if (!master->unique) {
231 		ret = -ENOMEM;
232 		goto err;
233 	}
234 
235 	if (copy_from_user(master->unique, u->unique, master->unique_len)) {
236 		ret = -EFAULT;
237 		goto err;
238 	}
239 
240 	master->unique[master->unique_len] = '\0';
241 
242 	/* Return error if the busid submitted doesn't match the device's actual
243 	 * busid.
244 	 */
245 	ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
246 	if (ret != 3) {
247 		ret = -EINVAL;
248 		goto err;
249 	}
250 
251 	domain = bus >> 8;
252 	bus &= 0xff;
253 
254 	if ((domain != dev->pci_domain) ||
255 	    (bus != dev->pci_bus) ||
256 	    (slot != dev->pci_slot) ||
257 	    (func != dev->pci_func)) {
258 		ret = -EINVAL;
259 		goto err;
260 	}
261 	return 0;
262 err:
263 	return ret;
264 }
265 
266 
267 static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
268 {
269 	if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
270 	    (p->busnum & 0xff) != dev->pci_bus ||
271 	    p->devnum != dev->pci_slot || p->funcnum != dev->pci_func)
272 		return -EINVAL;
273 
274 	p->irq = dev->irq;
275 
276 	DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
277 		  p->irq);
278 	return 0;
279 }
280 
281 int drm_pci_agp_init(struct drm_device *dev)
282 {
283 	if (drm_core_has_AGP(dev)) {
284 		if (drm_pci_device_is_agp(dev))
285 			dev->agp = drm_agp_init(dev);
286 		if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
287 		    && (dev->agp == NULL)) {
288 			DRM_ERROR("Cannot initialize the agpgart module.\n");
289 			return -EINVAL;
290 		}
291 		if (drm_core_has_MTRR(dev)) {
292 			if (dev->agp && dev->agp->agp_info.ai_aperture_base != 0) {
293 				if (drm_mtrr_add(dev->agp->agp_info.ai_aperture_base,
294 				    dev->agp->agp_info.ai_aperture_size, DRM_MTRR_WC) == 0)
295 					dev->agp->agp_mtrr = 1;
296 				else
297 					dev->agp->agp_mtrr = -1;
298 			}
299 		}
300 	}
301 	return 0;
302 }
303 
304 static struct drm_bus drm_pci_bus = {
305 	.bus_type = DRIVER_BUS_PCI,
306 	.get_irq = drm_pci_get_irq,
307 	.free_irq = drm_pci_free_irq,
308 	.get_name = drm_pci_get_name,
309 	.set_busid = drm_pci_set_busid,
310 	.set_unique = drm_pci_set_unique,
311 	.irq_by_busid = drm_pci_irq_by_busid,
312 	.agp_init = drm_pci_agp_init,
313 };
314 
315 /**
316  * Register.
317  *
318  * \param pdev - PCI device structure
319  * \param ent entry from the PCI ID table with device type flags
320  * \return zero on success or a negative number on failure.
321  *
322  * Attempt to gets inter module "drm" information. If we are first
323  * then register the character device and inter module information.
324  * Try and register, if we fail to register, backout previous work.
325  */
326 int drm_get_pci_dev(device_t kdev, struct drm_device *dev,
327 		    struct drm_driver *driver)
328 {
329 	int ret;
330 
331 	DRM_DEBUG("\n");
332 
333 	driver->bus = &drm_pci_bus;
334 
335 	dev->dev = kdev;
336 
337 	dev->pci_domain = pci_get_domain(dev->dev);
338 	dev->pci_bus = pci_get_bus(dev->dev);
339 	dev->pci_slot = pci_get_slot(dev->dev);
340 	dev->pci_func = pci_get_function(dev->dev);
341 
342 	dev->pci_vendor = pci_get_vendor(dev->dev);
343 	dev->pci_device = pci_get_device(dev->dev);
344 	dev->pci_subvendor = pci_get_subvendor(dev->dev);
345 	dev->pci_subdevice = pci_get_subdevice(dev->dev);
346 
347 	sx_xlock(&drm_global_mutex);
348 
349 	if ((ret = drm_fill_in_dev(dev, driver))) {
350 		DRM_ERROR("Failed to fill in dev: %d\n", ret);
351 		goto err_g1;
352 	}
353 
354 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
355 		ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
356 		if (ret)
357 			goto err_g2;
358 	}
359 
360 	if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
361 		goto err_g3;
362 
363 	if (dev->driver->load) {
364 		ret = dev->driver->load(dev,
365 		    dev->id_entry->driver_private);
366 		if (ret)
367 			goto err_g4;
368 	}
369 
370 	/* setup the grouping for the legacy output */
371 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
372 		ret = drm_mode_group_init_legacy_group(dev,
373 						&dev->primary->mode_group);
374 		if (ret)
375 			goto err_g5;
376 	}
377 
378 #ifdef FREEBSD_NOTYET
379 	list_add_tail(&dev->driver_item, &driver->device_list);
380 #endif /* FREEBSD_NOTYET */
381 
382 	DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
383 		 driver->name, driver->major, driver->minor, driver->patchlevel,
384 		 driver->date, device_get_nameunit(dev->dev), dev->primary->index);
385 
386 	sx_xunlock(&drm_global_mutex);
387 	return 0;
388 
389 err_g5:
390 	if (dev->driver->unload)
391 		dev->driver->unload(dev);
392 err_g4:
393 	drm_put_minor(&dev->primary);
394 err_g3:
395 	if (drm_core_check_feature(dev, DRIVER_MODESET))
396 		drm_put_minor(&dev->control);
397 err_g2:
398 	drm_cancel_fill_in_dev(dev);
399 err_g1:
400 	sx_xunlock(&drm_global_mutex);
401 	return ret;
402 }
403 EXPORT_SYMBOL(drm_get_pci_dev);
404 
405 int
406 drm_pci_enable_msi(struct drm_device *dev)
407 {
408 	int msicount, ret;
409 
410 	if (!drm_msi)
411 		return (-ENOENT);
412 
413 	msicount = pci_msi_count(dev->dev);
414 	DRM_DEBUG("MSI count = %d\n", msicount);
415 	if (msicount > 1)
416 		msicount = 1;
417 
418 	ret = pci_alloc_msi(dev->dev, &msicount);
419 	if (ret == 0) {
420 		DRM_INFO("MSI enabled %d message(s)\n", msicount);
421 		dev->msi_enabled = 1;
422 		dev->irqrid = 1;
423 	}
424 
425 	return (-ret);
426 }
427 
428 void
429 drm_pci_disable_msi(struct drm_device *dev)
430 {
431 
432 	if (!dev->msi_enabled)
433 		return;
434 
435 	pci_release_msi(dev->dev);
436 	dev->msi_enabled = 0;
437 	dev->irqrid = 0;
438 }
439 
440 int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask)
441 {
442 	device_t root;
443 	int pos;
444 	u32 lnkcap = 0, lnkcap2 = 0;
445 
446 	*mask = 0;
447 	if (!drm_pci_device_is_pcie(dev))
448 		return -EINVAL;
449 
450 	root =
451 	    device_get_parent( /* pcib             */
452 	    device_get_parent( /* `-- pci          */
453 	    device_get_parent( /*     `-- vgapci   */
454 	    dev->dev)));       /*         `-- drmn */
455 
456 	pos = 0;
457 	pci_find_cap(root, PCIY_EXPRESS, &pos);
458 	if (!pos)
459 		return -EINVAL;
460 
461 	/* we've been informed via and serverworks don't make the cut */
462 	if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA ||
463 	    pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS)
464 		return -EINVAL;
465 
466 	lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4);
467 	lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4);
468 
469 	lnkcap &= PCIEM_LINK_CAP_MAX_SPEED;
470 	lnkcap2 &= 0xfe;
471 
472 #define	PCI_EXP_LNKCAP2_SLS_2_5GB 0x02	/* Supported Link Speed 2.5GT/s */
473 #define	PCI_EXP_LNKCAP2_SLS_5_0GB 0x04	/* Supported Link Speed 5.0GT/s */
474 #define	PCI_EXP_LNKCAP2_SLS_8_0GB 0x08	/* Supported Link Speed 8.0GT/s */
475 
476 	if (lnkcap2) { /* PCIE GEN 3.0 */
477 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
478 			*mask |= DRM_PCIE_SPEED_25;
479 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
480 			*mask |= DRM_PCIE_SPEED_50;
481 		if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
482 			*mask |= DRM_PCIE_SPEED_80;
483 	} else {
484 		if (lnkcap & 1)
485 			*mask |= DRM_PCIE_SPEED_25;
486 		if (lnkcap & 2)
487 			*mask |= DRM_PCIE_SPEED_50;
488 	}
489 
490 	DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", pci_get_vendor(root), pci_get_device(root), lnkcap, lnkcap2);
491 	return 0;
492 }
493 EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask);
494