diff options
Diffstat (limited to 'drivers/gpu/drm/drm_pci.c')
-rw-r--r-- | drivers/gpu/drm/drm_pci.c | 205 |
1 files changed, 199 insertions, 6 deletions
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index f5bd9e590c8..e1aee4f6a7c 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c | |||
@@ -125,6 +125,176 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) | |||
125 | EXPORT_SYMBOL(drm_pci_free); | 125 | EXPORT_SYMBOL(drm_pci_free); |
126 | 126 | ||
127 | #ifdef CONFIG_PCI | 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 | 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 | .agp_init = drm_pci_agp_init, | ||
296 | }; | ||
297 | |||
128 | /** | 298 | /** |
129 | * Register. | 299 | * Register. |
130 | * | 300 | * |
@@ -219,7 +389,7 @@ err_g1: | |||
219 | EXPORT_SYMBOL(drm_get_pci_dev); | 389 | EXPORT_SYMBOL(drm_get_pci_dev); |
220 | 390 | ||
221 | /** | 391 | /** |
222 | * PCI device initialization. Called via drm_init at module load time, | 392 | * PCI device initialization. Called direct from modules at load time. |
223 | * | 393 | * |
224 | * \return zero on success or a negative number on failure. | 394 | * \return zero on success or a negative number on failure. |
225 | * | 395 | * |
@@ -229,18 +399,24 @@ EXPORT_SYMBOL(drm_get_pci_dev); | |||
229 | * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and | 399 | * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and |
230 | * after the initialization for driver customization. | 400 | * after the initialization for driver customization. |
231 | */ | 401 | */ |
232 | int drm_pci_init(struct drm_driver *driver) | 402 | int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) |
233 | { | 403 | { |
234 | struct pci_dev *pdev = NULL; | 404 | struct pci_dev *pdev = NULL; |
235 | const struct pci_device_id *pid; | 405 | const struct pci_device_id *pid; |
236 | int i; | 406 | int i; |
237 | 407 | ||
408 | DRM_DEBUG("\n"); | ||
409 | |||
410 | INIT_LIST_HEAD(&driver->device_list); | ||
411 | driver->kdriver.pci = pdriver; | ||
412 | driver->bus = &drm_pci_bus; | ||
413 | |||
238 | if (driver->driver_features & DRIVER_MODESET) | 414 | if (driver->driver_features & DRIVER_MODESET) |
239 | return pci_register_driver(&driver->pci_driver); | 415 | return pci_register_driver(pdriver); |
240 | 416 | ||
241 | /* If not using KMS, fall back to stealth mode manual scanning. */ | 417 | /* If not using KMS, fall back to stealth mode manual scanning. */ |
242 | for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) { | 418 | for (i = 0; pdriver->id_table[i].vendor != 0; i++) { |
243 | pid = &driver->pci_driver.id_table[i]; | 419 | pid = &pdriver->id_table[i]; |
244 | 420 | ||
245 | /* Loop around setting up a DRM device for each PCI device | 421 | /* Loop around setting up a DRM device for each PCI device |
246 | * matching our ID and device class. If we had the internal | 422 | * matching our ID and device class. If we had the internal |
@@ -265,10 +441,27 @@ int drm_pci_init(struct drm_driver *driver) | |||
265 | 441 | ||
266 | #else | 442 | #else |
267 | 443 | ||
268 | int drm_pci_init(struct drm_driver *driver) | 444 | int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) |
269 | { | 445 | { |
270 | return -1; | 446 | return -1; |
271 | } | 447 | } |
272 | 448 | ||
273 | #endif | 449 | #endif |
450 | |||
451 | EXPORT_SYMBOL(drm_pci_init); | ||
452 | |||
274 | /*@}*/ | 453 | /*@}*/ |
454 | void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver) | ||
455 | { | ||
456 | struct drm_device *dev, *tmp; | ||
457 | DRM_DEBUG("\n"); | ||
458 | |||
459 | if (driver->driver_features & DRIVER_MODESET) { | ||
460 | pci_unregister_driver(pdriver); | ||
461 | } else { | ||
462 | list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item) | ||
463 | drm_put_dev(dev); | ||
464 | } | ||
465 | DRM_INFO("Module unloaded\n"); | ||
466 | } | ||
467 | EXPORT_SYMBOL(drm_pci_exit); | ||