|
@@ -125,6 +125,176 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
|
|
|
EXPORT_SYMBOL(drm_pci_free);
|
|
|
|
|
|
#ifdef CONFIG_PCI
|
|
|
+
|
|
|
+static int drm_get_pci_domain(struct drm_device *dev)
|
|
|
+{
|
|
|
+#ifndef __alpha__
|
|
|
+ /* For historical reasons, drm_get_pci_domain() is busticated
|
|
|
+ * on most archs and has to remain so for userspace interface
|
|
|
+ * < 1.4, except on alpha which was right from the beginning
|
|
|
+ */
|
|
|
+ if (dev->if_version < 0x10004)
|
|
|
+ return 0;
|
|
|
+#endif /* __alpha__ */
|
|
|
+
|
|
|
+ return pci_domain_nr(dev->pdev->bus);
|
|
|
+}
|
|
|
+
|
|
|
+static int drm_pci_get_irq(struct drm_device *dev)
|
|
|
+{
|
|
|
+ return dev->pdev->irq;
|
|
|
+}
|
|
|
+
|
|
|
+static const char *drm_pci_get_name(struct drm_device *dev)
|
|
|
+{
|
|
|
+ struct pci_driver *pdriver = dev->driver->kdriver.pci;
|
|
|
+ return pdriver->name;
|
|
|
+}
|
|
|
+
|
|
|
+int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
|
|
|
+{
|
|
|
+ int len, ret;
|
|
|
+ struct pci_driver *pdriver = dev->driver->kdriver.pci;
|
|
|
+ master->unique_len = 40;
|
|
|
+ master->unique_size = master->unique_len;
|
|
|
+ master->unique = kmalloc(master->unique_size, GFP_KERNEL);
|
|
|
+ if (master->unique == NULL)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+
|
|
|
+ len = snprintf(master->unique, master->unique_len,
|
|
|
+ "pci:%04x:%02x:%02x.%d",
|
|
|
+ drm_get_pci_domain(dev),
|
|
|
+ dev->pdev->bus->number,
|
|
|
+ PCI_SLOT(dev->pdev->devfn),
|
|
|
+ PCI_FUNC(dev->pdev->devfn));
|
|
|
+
|
|
|
+ if (len >= master->unique_len) {
|
|
|
+ DRM_ERROR("buffer overflow");
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto err;
|
|
|
+ } else
|
|
|
+ master->unique_len = len;
|
|
|
+
|
|
|
+ dev->devname =
|
|
|
+ kmalloc(strlen(pdriver->name) +
|
|
|
+ master->unique_len + 2, GFP_KERNEL);
|
|
|
+
|
|
|
+ if (dev->devname == NULL) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ sprintf(dev->devname, "%s@%s", pdriver->name,
|
|
|
+ master->unique);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int drm_pci_set_unique(struct drm_device *dev,
|
|
|
+ struct drm_master *master,
|
|
|
+ struct drm_unique *u)
|
|
|
+{
|
|
|
+ int domain, bus, slot, func, ret;
|
|
|
+ const char *bus_name;
|
|
|
+
|
|
|
+ master->unique_len = u->unique_len;
|
|
|
+ master->unique_size = u->unique_len + 1;
|
|
|
+ master->unique = kmalloc(master->unique_size, GFP_KERNEL);
|
|
|
+ if (!master->unique) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (copy_from_user(master->unique, u->unique, master->unique_len)) {
|
|
|
+ ret = -EFAULT;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ master->unique[master->unique_len] = '\0';
|
|
|
+
|
|
|
+ bus_name = dev->driver->bus->get_name(dev);
|
|
|
+ dev->devname = kmalloc(strlen(bus_name) +
|
|
|
+ strlen(master->unique) + 2, GFP_KERNEL);
|
|
|
+ if (!dev->devname) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ sprintf(dev->devname, "%s@%s", bus_name,
|
|
|
+ master->unique);
|
|
|
+
|
|
|
+ /* Return error if the busid submitted doesn't match the device's actual
|
|
|
+ * busid.
|
|
|
+ */
|
|
|
+ ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
|
|
|
+ if (ret != 3) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ domain = bus >> 8;
|
|
|
+ bus &= 0xff;
|
|
|
+
|
|
|
+ if ((domain != drm_get_pci_domain(dev)) ||
|
|
|
+ (bus != dev->pdev->bus->number) ||
|
|
|
+ (slot != PCI_SLOT(dev->pdev->devfn)) ||
|
|
|
+ (func != PCI_FUNC(dev->pdev->devfn))) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
|
|
|
+{
|
|
|
+ if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
|
|
|
+ (p->busnum & 0xff) != dev->pdev->bus->number ||
|
|
|
+ p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ p->irq = dev->pdev->irq;
|
|
|
+
|
|
|
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
|
|
|
+ p->irq);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int drm_pci_agp_init(struct drm_device *dev)
|
|
|
+{
|
|
|
+ if (drm_core_has_AGP(dev)) {
|
|
|
+ if (drm_pci_device_is_agp(dev))
|
|
|
+ dev->agp = drm_agp_init(dev);
|
|
|
+ if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
|
|
|
+ && (dev->agp == NULL)) {
|
|
|
+ DRM_ERROR("Cannot initialize the agpgart module.\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ if (drm_core_has_MTRR(dev)) {
|
|
|
+ if (dev->agp)
|
|
|
+ dev->agp->agp_mtrr =
|
|
|
+ mtrr_add(dev->agp->agp_info.aper_base,
|
|
|
+ dev->agp->agp_info.aper_size *
|
|
|
+ 1024 * 1024, MTRR_TYPE_WRCOMB, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct drm_bus drm_pci_bus = {
|
|
|
+ .bus_type = DRIVER_BUS_PCI,
|
|
|
+ .get_irq = drm_pci_get_irq,
|
|
|
+ .get_name = drm_pci_get_name,
|
|
|
+ .set_busid = drm_pci_set_busid,
|
|
|
+ .set_unique = drm_pci_set_unique,
|
|
|
+ .agp_init = drm_pci_agp_init,
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* Register.
|
|
|
*
|
|
@@ -219,7 +389,7 @@ err_g1:
|
|
|
EXPORT_SYMBOL(drm_get_pci_dev);
|
|
|
|
|
|
/**
|
|
|
- * PCI device initialization. Called via drm_init at module load time,
|
|
|
+ * PCI device initialization. Called direct from modules at load time.
|
|
|
*
|
|
|
* \return zero on success or a negative number on failure.
|
|
|
*
|
|
@@ -229,18 +399,24 @@ EXPORT_SYMBOL(drm_get_pci_dev);
|
|
|
* Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
|
|
|
* after the initialization for driver customization.
|
|
|
*/
|
|
|
-int drm_pci_init(struct drm_driver *driver)
|
|
|
+int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
|
|
|
{
|
|
|
struct pci_dev *pdev = NULL;
|
|
|
const struct pci_device_id *pid;
|
|
|
int i;
|
|
|
|
|
|
+ DRM_DEBUG("\n");
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&driver->device_list);
|
|
|
+ driver->kdriver.pci = pdriver;
|
|
|
+ driver->bus = &drm_pci_bus;
|
|
|
+
|
|
|
if (driver->driver_features & DRIVER_MODESET)
|
|
|
- return pci_register_driver(&driver->pci_driver);
|
|
|
+ return pci_register_driver(pdriver);
|
|
|
|
|
|
/* If not using KMS, fall back to stealth mode manual scanning. */
|
|
|
- for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
|
|
|
- pid = &driver->pci_driver.id_table[i];
|
|
|
+ for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
|
|
|
+ pid = &pdriver->id_table[i];
|
|
|
|
|
|
/* Loop around setting up a DRM device for each PCI device
|
|
|
* matching our ID and device class. If we had the internal
|
|
@@ -265,10 +441,27 @@ int drm_pci_init(struct drm_driver *driver)
|
|
|
|
|
|
#else
|
|
|
|
|
|
-int drm_pci_init(struct drm_driver *driver)
|
|
|
+int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
|
|
|
{
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
+
|
|
|
+EXPORT_SYMBOL(drm_pci_init);
|
|
|
+
|
|
|
/*@}*/
|
|
|
+void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
|
|
|
+{
|
|
|
+ struct drm_device *dev, *tmp;
|
|
|
+ DRM_DEBUG("\n");
|
|
|
+
|
|
|
+ if (driver->driver_features & DRIVER_MODESET) {
|
|
|
+ pci_unregister_driver(pdriver);
|
|
|
+ } else {
|
|
|
+ list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
|
|
|
+ drm_put_dev(dev);
|
|
|
+ }
|
|
|
+ DRM_INFO("Module unloaded\n");
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(drm_pci_exit);
|