Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8410ea3b authored by Dave Airlie's avatar Dave Airlie Committed by Dave Airlie
Browse files

drm: rework PCI/platform driver interface.



This abstracts the pci/platform interface out a step further,
we can go further but this is far enough for now to allow USB
to be plugged in.

The drivers now just call the init code directly for their
device type.

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent ff72145b
Loading
Loading
Loading
Loading
+0 −43
Original line number Diff line number Diff line
@@ -237,49 +237,6 @@ int drm_lastclose(struct drm_device * dev)
	return 0;
}

/**
 * Module initialization. Called via init_module at module load time, or via
 * linux/init/main.c (this is not currently supported).
 *
 * \return zero on success or a negative number on failure.
 *
 * Initializes an array of drm_device structures, and attempts to
 * initialize all available devices, using consecutive minors, registering the
 * stubs and initializing the device.
 *
 * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
 * after the initialization for driver customization.
 */
int drm_init(struct drm_driver *driver)
{
	DRM_DEBUG("\n");
	INIT_LIST_HEAD(&driver->device_list);

	if (driver->driver_features & DRIVER_USE_PLATFORM_DEVICE)
		return drm_platform_init(driver);
	else
		return drm_pci_init(driver);
}

EXPORT_SYMBOL(drm_init);

void drm_exit(struct drm_driver *driver)
{
	struct drm_device *dev, *tmp;
	DRM_DEBUG("\n");

	if (driver->driver_features & DRIVER_MODESET) {
		pci_unregister_driver(&driver->pci_driver);
	} 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_exit);

/** File operations structure */
static const struct file_operations drm_stub_fops = {
	.owner = THIS_MODULE,
+8 −19
Original line number Diff line number Diff line
@@ -47,30 +47,19 @@ int drm_name_info(struct seq_file *m, void *data)
	struct drm_minor *minor = node->minor;
	struct drm_device *dev = minor->dev;
	struct drm_master *master = minor->master;

	const char *bus_name;
	if (!master)
		return 0;

	if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
	bus_name = dev->driver->bus->get_name(dev);
	if (master->unique) {
		seq_printf(m, "%s %s %s\n",
					dev->driver->platform_device->name,
			   bus_name,
			   dev_name(dev->dev), master->unique);
	} else {
			seq_printf(m, "%s\n",
				dev->driver->platform_device->name);
		seq_printf(m, "%s %s\n",
			   bus_name, dev_name(dev->dev));
	}
	} else {
		if (master->unique) {
			seq_printf(m, "%s %s %s\n",
				dev->driver->pci_driver.name,
				dev_name(dev->dev), master->unique);
		} else {
			seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
				dev_name(dev->dev));
		}
	}

	return 0;
}

+9 −106
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ int drm_setunique(struct drm_device *dev, void *data,
{
	struct drm_unique *u = data;
	struct drm_master *master = file_priv->master;
	int domain, bus, slot, func, ret;
	int ret;

	if (master->unique_len || master->unique)
		return -EBUSY;
@@ -104,50 +104,12 @@ int drm_setunique(struct drm_device *dev, void *data,
	if (!u->unique_len || u->unique_len > 1024)
		return -EINVAL;

	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';

	dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
			       strlen(master->unique) + 2, GFP_KERNEL);
	if (!dev->devname) {
		ret = -ENOMEM;
		goto err;
	}

	sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.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 (!dev->driver->bus->set_unique)
		return -EINVAL;

	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;
	ret = dev->driver->bus->set_unique(dev, master, u);
	if (ret)
		goto err;
	}

	return 0;

@@ -159,74 +121,15 @@ int drm_setunique(struct drm_device *dev, void *data,
static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
{
	struct drm_master *master = file_priv->master;
	int len, ret;
	int ret;

	if (master->unique != NULL)
		drm_unset_busid(dev, master);

	if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
		master->unique_len = 10 + strlen(dev->platformdev->name);
		master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);

		if (master->unique == NULL)
			return -ENOMEM;

		len = snprintf(master->unique, master->unique_len,
			"platform:%s", dev->platformdev->name);

		if (len > master->unique_len) {
			DRM_ERROR("Unique buffer overflowed\n");
			ret = -EINVAL;
			goto err;
		}

		dev->devname =
			kmalloc(strlen(dev->platformdev->name) +
				master->unique_len + 2, GFP_KERNEL);

		if (dev->devname == NULL) {
			ret = -ENOMEM;
			goto err;
		}

		sprintf(dev->devname, "%s@%s", dev->platformdev->name,
			master->unique);

	} else {
		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;
	ret = dev->driver->bus->set_busid(dev, master);
	if (ret)
		goto err;
		} else
			master->unique_len = len;

		dev->devname =
			kmalloc(strlen(dev->driver->pci_driver.name) +
				master->unique_len + 2, GFP_KERNEL);

		if (dev->devname == NULL) {
			ret = -ENOMEM;
			goto err;
		}

		sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
			master->unique);
	}

	return 0;

err:
	drm_unset_busid(dev, master);
	return ret;
+2 −12
Original line number Diff line number Diff line
@@ -74,23 +74,13 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
{
	struct drm_irq_busid *p = data;

	if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
	if (!dev->driver->bus->irq_by_busid)
		return -EINVAL;

	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
		return -EINVAL;

	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;
	return dev->driver->bus->irq_by_busid(dev, p);
}

/*
+199 −6
Original line number Diff line number Diff line
@@ -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 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
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);
Loading