Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/gpu/drm/drm_pci.c
15111 views
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 <[email protected]>
12
* \author Leif Delgass <[email protected]>
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 <linux/pci.h>
40
#include <linux/slab.h>
41
#include <linux/dma-mapping.h>
42
#include "drmP.h"
43
44
/**********************************************************************/
45
/** \name PCI memory */
46
/*@{*/
47
48
/**
49
* \brief Allocate a PCI consistent memory block, for DMA.
50
*/
51
drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align)
52
{
53
drm_dma_handle_t *dmah;
54
#if 1
55
unsigned long addr;
56
size_t sz;
57
#endif
58
59
/* pci_alloc_consistent only guarantees alignment to the smallest
60
* PAGE_SIZE order which is greater than or equal to the requested size.
61
* Return NULL here for now to make sure nobody tries for larger alignment
62
*/
63
if (align > size)
64
return NULL;
65
66
dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL);
67
if (!dmah)
68
return NULL;
69
70
dmah->size = size;
71
dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP);
72
73
if (dmah->vaddr == NULL) {
74
kfree(dmah);
75
return NULL;
76
}
77
78
memset(dmah->vaddr, 0, size);
79
80
/* XXX - Is virt_to_page() legal for consistent mem? */
81
/* Reserve */
82
for (addr = (unsigned long)dmah->vaddr, sz = size;
83
sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
84
SetPageReserved(virt_to_page(addr));
85
}
86
87
return dmah;
88
}
89
90
EXPORT_SYMBOL(drm_pci_alloc);
91
92
/**
93
* \brief Free a PCI consistent memory block without freeing its descriptor.
94
*
95
* This function is for internal use in the Linux-specific DRM core code.
96
*/
97
void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
98
{
99
#if 1
100
unsigned long addr;
101
size_t sz;
102
#endif
103
104
if (dmah->vaddr) {
105
/* XXX - Is virt_to_page() legal for consistent mem? */
106
/* Unreserve */
107
for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
108
sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
109
ClearPageReserved(virt_to_page(addr));
110
}
111
dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
112
dmah->busaddr);
113
}
114
}
115
116
/**
117
* \brief Free a PCI consistent memory block
118
*/
119
void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
120
{
121
__drm_pci_free(dev, dmah);
122
kfree(dmah);
123
}
124
125
EXPORT_SYMBOL(drm_pci_free);
126
127
#ifdef CONFIG_PCI
128
129
static int drm_get_pci_domain(struct drm_device *dev)
130
{
131
#ifndef __alpha__
132
/* For historical reasons, drm_get_pci_domain() is busticated
133
* on most archs and has to remain so for userspace interface
134
* < 1.4, except on alpha which was right from the beginning
135
*/
136
if (dev->if_version < 0x10004)
137
return 0;
138
#endif /* __alpha__ */
139
140
return pci_domain_nr(dev->pdev->bus);
141
}
142
143
static int drm_pci_get_irq(struct drm_device *dev)
144
{
145
return dev->pdev->irq;
146
}
147
148
static const char *drm_pci_get_name(struct drm_device *dev)
149
{
150
struct pci_driver *pdriver = dev->driver->kdriver.pci;
151
return pdriver->name;
152
}
153
154
int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
155
{
156
int len, ret;
157
struct pci_driver *pdriver = dev->driver->kdriver.pci;
158
master->unique_len = 40;
159
master->unique_size = master->unique_len;
160
master->unique = kmalloc(master->unique_size, GFP_KERNEL);
161
if (master->unique == NULL)
162
return -ENOMEM;
163
164
165
len = snprintf(master->unique, master->unique_len,
166
"pci:%04x:%02x:%02x.%d",
167
drm_get_pci_domain(dev),
168
dev->pdev->bus->number,
169
PCI_SLOT(dev->pdev->devfn),
170
PCI_FUNC(dev->pdev->devfn));
171
172
if (len >= master->unique_len) {
173
DRM_ERROR("buffer overflow");
174
ret = -EINVAL;
175
goto err;
176
} else
177
master->unique_len = len;
178
179
dev->devname =
180
kmalloc(strlen(pdriver->name) +
181
master->unique_len + 2, GFP_KERNEL);
182
183
if (dev->devname == NULL) {
184
ret = -ENOMEM;
185
goto err;
186
}
187
188
sprintf(dev->devname, "%s@%s", pdriver->name,
189
master->unique);
190
191
return 0;
192
err:
193
return ret;
194
}
195
196
int drm_pci_set_unique(struct drm_device *dev,
197
struct drm_master *master,
198
struct drm_unique *u)
199
{
200
int domain, bus, slot, func, ret;
201
const char *bus_name;
202
203
master->unique_len = u->unique_len;
204
master->unique_size = u->unique_len + 1;
205
master->unique = kmalloc(master->unique_size, GFP_KERNEL);
206
if (!master->unique) {
207
ret = -ENOMEM;
208
goto err;
209
}
210
211
if (copy_from_user(master->unique, u->unique, master->unique_len)) {
212
ret = -EFAULT;
213
goto err;
214
}
215
216
master->unique[master->unique_len] = '\0';
217
218
bus_name = dev->driver->bus->get_name(dev);
219
dev->devname = kmalloc(strlen(bus_name) +
220
strlen(master->unique) + 2, GFP_KERNEL);
221
if (!dev->devname) {
222
ret = -ENOMEM;
223
goto err;
224
}
225
226
sprintf(dev->devname, "%s@%s", bus_name,
227
master->unique);
228
229
/* Return error if the busid submitted doesn't match the device's actual
230
* busid.
231
*/
232
ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
233
if (ret != 3) {
234
ret = -EINVAL;
235
goto err;
236
}
237
238
domain = bus >> 8;
239
bus &= 0xff;
240
241
if ((domain != drm_get_pci_domain(dev)) ||
242
(bus != dev->pdev->bus->number) ||
243
(slot != PCI_SLOT(dev->pdev->devfn)) ||
244
(func != PCI_FUNC(dev->pdev->devfn))) {
245
ret = -EINVAL;
246
goto err;
247
}
248
return 0;
249
err:
250
return ret;
251
}
252
253
254
static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
255
{
256
if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
257
(p->busnum & 0xff) != dev->pdev->bus->number ||
258
p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
259
return -EINVAL;
260
261
p->irq = dev->pdev->irq;
262
263
DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
264
p->irq);
265
return 0;
266
}
267
268
int drm_pci_agp_init(struct drm_device *dev)
269
{
270
if (drm_core_has_AGP(dev)) {
271
if (drm_pci_device_is_agp(dev))
272
dev->agp = drm_agp_init(dev);
273
if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
274
&& (dev->agp == NULL)) {
275
DRM_ERROR("Cannot initialize the agpgart module.\n");
276
return -EINVAL;
277
}
278
if (drm_core_has_MTRR(dev)) {
279
if (dev->agp)
280
dev->agp->agp_mtrr =
281
mtrr_add(dev->agp->agp_info.aper_base,
282
dev->agp->agp_info.aper_size *
283
1024 * 1024, MTRR_TYPE_WRCOMB, 1);
284
}
285
}
286
return 0;
287
}
288
289
static struct drm_bus drm_pci_bus = {
290
.bus_type = DRIVER_BUS_PCI,
291
.get_irq = drm_pci_get_irq,
292
.get_name = drm_pci_get_name,
293
.set_busid = drm_pci_set_busid,
294
.set_unique = drm_pci_set_unique,
295
.irq_by_busid = drm_pci_irq_by_busid,
296
.agp_init = drm_pci_agp_init,
297
};
298
299
/**
300
* Register.
301
*
302
* \param pdev - PCI device structure
303
* \param ent entry from the PCI ID table with device type flags
304
* \return zero on success or a negative number on failure.
305
*
306
* Attempt to gets inter module "drm" information. If we are first
307
* then register the character device and inter module information.
308
* Try and register, if we fail to register, backout previous work.
309
*/
310
int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
311
struct drm_driver *driver)
312
{
313
struct drm_device *dev;
314
int ret;
315
316
DRM_DEBUG("\n");
317
318
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
319
if (!dev)
320
return -ENOMEM;
321
322
ret = pci_enable_device(pdev);
323
if (ret)
324
goto err_g1;
325
326
pci_set_master(pdev);
327
328
dev->pdev = pdev;
329
dev->dev = &pdev->dev;
330
331
dev->pci_device = pdev->device;
332
dev->pci_vendor = pdev->vendor;
333
334
#ifdef __alpha__
335
dev->hose = pdev->sysdata;
336
#endif
337
338
mutex_lock(&drm_global_mutex);
339
340
if ((ret = drm_fill_in_dev(dev, ent, driver))) {
341
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
342
goto err_g2;
343
}
344
345
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
346
pci_set_drvdata(pdev, dev);
347
ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
348
if (ret)
349
goto err_g2;
350
}
351
352
if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
353
goto err_g3;
354
355
if (dev->driver->load) {
356
ret = dev->driver->load(dev, ent->driver_data);
357
if (ret)
358
goto err_g4;
359
}
360
361
/* setup the grouping for the legacy output */
362
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
363
ret = drm_mode_group_init_legacy_group(dev,
364
&dev->primary->mode_group);
365
if (ret)
366
goto err_g4;
367
}
368
369
list_add_tail(&dev->driver_item, &driver->device_list);
370
371
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
372
driver->name, driver->major, driver->minor, driver->patchlevel,
373
driver->date, pci_name(pdev), dev->primary->index);
374
375
mutex_unlock(&drm_global_mutex);
376
return 0;
377
378
err_g4:
379
drm_put_minor(&dev->primary);
380
err_g3:
381
if (drm_core_check_feature(dev, DRIVER_MODESET))
382
drm_put_minor(&dev->control);
383
err_g2:
384
pci_disable_device(pdev);
385
err_g1:
386
kfree(dev);
387
mutex_unlock(&drm_global_mutex);
388
return ret;
389
}
390
EXPORT_SYMBOL(drm_get_pci_dev);
391
392
/**
393
* PCI device initialization. Called direct from modules at load time.
394
*
395
* \return zero on success or a negative number on failure.
396
*
397
* Initializes a drm_device structures,registering the
398
* stubs and initializing the AGP device.
399
*
400
* Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
401
* after the initialization for driver customization.
402
*/
403
int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
404
{
405
struct pci_dev *pdev = NULL;
406
const struct pci_device_id *pid;
407
int i;
408
409
DRM_DEBUG("\n");
410
411
INIT_LIST_HEAD(&driver->device_list);
412
driver->kdriver.pci = pdriver;
413
driver->bus = &drm_pci_bus;
414
415
if (driver->driver_features & DRIVER_MODESET)
416
return pci_register_driver(pdriver);
417
418
/* If not using KMS, fall back to stealth mode manual scanning. */
419
for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
420
pid = &pdriver->id_table[i];
421
422
/* Loop around setting up a DRM device for each PCI device
423
* matching our ID and device class. If we had the internal
424
* function that pci_get_subsys and pci_get_class used, we'd
425
* be able to just pass pid in instead of doing a two-stage
426
* thing.
427
*/
428
pdev = NULL;
429
while ((pdev =
430
pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
431
pid->subdevice, pdev)) != NULL) {
432
if ((pdev->class & pid->class_mask) != pid->class)
433
continue;
434
435
/* stealth mode requires a manual probe */
436
pci_dev_get(pdev);
437
drm_get_pci_dev(pdev, pid, driver);
438
}
439
}
440
return 0;
441
}
442
443
#else
444
445
int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
446
{
447
return -1;
448
}
449
450
#endif
451
452
EXPORT_SYMBOL(drm_pci_init);
453
454
/*@}*/
455
void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
456
{
457
struct drm_device *dev, *tmp;
458
DRM_DEBUG("\n");
459
460
if (driver->driver_features & DRIVER_MODESET) {
461
pci_unregister_driver(pdriver);
462
} else {
463
list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
464
drm_put_dev(dev);
465
}
466
DRM_INFO("Module unloaded\n");
467
}
468
EXPORT_SYMBOL(drm_pci_exit);
469
470