diff options
Diffstat (limited to 'drivers/gpu/drm/drm_ioctl.c')
| -rw-r--r-- | drivers/gpu/drm/drm_ioctl.c | 293 | 
1 files changed, 141 insertions, 152 deletions
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 47db4df37a6..69c61f392e6 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -33,10 +33,14 @@   * OTHER DEALINGS IN THE SOFTWARE.   */ -#include "drmP.h" -#include "drm_core.h" +#include <drm/drmP.h> +#include <drm/drm_core.h> -#include "linux/pci.h" +#include <linux/pci.h> +#include <linux/export.h> +#ifdef CONFIG_X86 +#include <asm/mtrr.h> +#endif  /**   * Get the bus id. @@ -68,9 +72,6 @@ static void  drm_unset_busid(struct drm_device *dev,  		struct drm_master *master)  { -	kfree(dev->devname); -	dev->devname = NULL; -  	kfree(master->unique);  	master->unique = NULL;  	master->unique_len = 0; @@ -89,14 +90,15 @@ drm_unset_busid(struct drm_device *dev,   * Copies the bus id from userspace into drm_device::unique, and verifies that   * it matches the device this DRM is attached to (EINVAL otherwise).  Deprecated   * in interface version 1.1 and will return EBUSY when setversion has requested - * version 1.1 or greater. + * version 1.1 or greater. Also note that KMS is all version 1.1 and later and + * UMS was only ever supported on pci devices.   */  int drm_setunique(struct drm_device *dev, void *data,  		  struct drm_file *file_priv)  {  	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 +106,15 @@ 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); +	if (drm_core_check_feature(dev, DRIVER_MODESET)) +		return 0; -	/* 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 (WARN_ON(!dev->pdev)) +		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 = drm_pci_set_unique(dev, master, u); +	if (ret)  		goto err; -	}  	return 0; @@ -159,77 +126,30 @@ err:  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; +	if (dev->driver->bus && dev->driver->bus->set_busid) { +		ret = dev->driver->bus->set_busid(dev, master); +		if (ret) { +			drm_unset_busid(dev, master); +			return ret;  		} - -		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; -			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); +		if (WARN(dev->unique == NULL, +			 "No drm_bus.set_busid() implementation provided by " +			 "%ps. Use drm_dev_set_unique() to set the unique " +			 "name explicitly.", dev->driver)) +			return -EINVAL; + +		master->unique = kstrdup(dev->unique, GFP_KERNEL); +		if (master->unique) +			master->unique_len = strlen(dev->unique);  	}  	return 0; - -err: -	drm_unset_busid(dev, master); -	return ret;  }  /** @@ -255,14 +175,11 @@ int drm_getmap(struct drm_device *dev, void *data,  	int i;  	idx = map->offset; - -	mutex_lock(&dev->struct_mutex); -	if (idx < 0) { -		mutex_unlock(&dev->struct_mutex); +	if (idx < 0)  		return -EINVAL; -	}  	i = 0; +	mutex_lock(&dev->struct_mutex);  	list_for_each(list, &dev->maplist) {  		if (i == idx) {  			r_list = list_entry(list, struct drm_map_list, head); @@ -280,7 +197,17 @@ int drm_getmap(struct drm_device *dev, void *data,  	map->type = r_list->map->type;  	map->flags = r_list->map->flags;  	map->handle = (void *)(unsigned long) r_list->user_token; -	map->mtrr = r_list->map->mtrr; + +#ifdef CONFIG_X86 +	/* +	 * There appears to be exactly one user of the mtrr index: dritest. +	 * It's easy enough to keep it working on non-PAT systems. +	 */ +	map->mtrr = phys_wc_to_mtrr_index(r_list->map->mtrr); +#else +	map->mtrr = -1; +#endif +  	mutex_unlock(&dev->struct_mutex);  	return 0; @@ -303,29 +230,30 @@ int drm_getclient(struct drm_device *dev, void *data,  		  struct drm_file *file_priv)  {  	struct drm_client *client = data; -	struct drm_file *pt; -	int idx; -	int i; - -	idx = client->idx; -	mutex_lock(&dev->struct_mutex); -	i = 0; -	list_for_each_entry(pt, &dev->filelist, lhead) { -		if (i++ >= idx) { -			client->auth = pt->authenticated; -			client->pid = pt->pid; -			client->uid = pt->uid; -			client->magic = pt->magic; -			client->iocs = pt->ioctl_count; -			mutex_unlock(&dev->struct_mutex); - -			return 0; -		} +	/* +	 * Hollowed-out getclient ioctl to keep some dead old drm tests/tools +	 * not breaking completely. Userspace tools stop enumerating one they +	 * get -EINVAL, hence this is the return value we need to hand back for +	 * no clients tracked. +	 * +	 * Unfortunately some clients (*cough* libva *cough*) use this in a fun +	 * attempt to figure out whether they're authenticated or not. Since +	 * that's the only thing they care about, give it to the directly +	 * instead of walking one giant list. +	 */ +	if (client->idx == 0) { +		client->auth = file_priv->authenticated; +		client->pid = pid_vnr(file_priv->pid); +		client->uid = from_kuid_munged(current_user_ns(), +					       file_priv->uid); +		client->magic = 0; +		client->iocs = 0; + +		return 0; +	} else { +		return -EINVAL;  	} -	mutex_unlock(&dev->struct_mutex); - -	return -EINVAL;  }  /** @@ -342,24 +270,87 @@ int drm_getstats(struct drm_device *dev, void *data,  		 struct drm_file *file_priv)  {  	struct drm_stats *stats = data; -	int i; +	/* Clear stats to prevent userspace from eating its stack garbage. */  	memset(stats, 0, sizeof(*stats)); -	mutex_lock(&dev->struct_mutex); +	return 0; +} -	for (i = 0; i < dev->counters; i++) { -		if (dev->types[i] == _DRM_STAT_LOCK) -			stats->data[i].value = -			    (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0); +/** + * Get device/driver capabilities + */ +int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ +	struct drm_get_cap *req = data; + +	req->value = 0; +	switch (req->capability) { +	case DRM_CAP_DUMB_BUFFER: +		if (dev->driver->dumb_create) +			req->value = 1; +		break; +	case DRM_CAP_VBLANK_HIGH_CRTC: +		req->value = 1; +		break; +	case DRM_CAP_DUMB_PREFERRED_DEPTH: +		req->value = dev->mode_config.preferred_depth; +		break; +	case DRM_CAP_DUMB_PREFER_SHADOW: +		req->value = dev->mode_config.prefer_shadow; +		break; +	case DRM_CAP_PRIME: +		req->value |= dev->driver->prime_fd_to_handle ? DRM_PRIME_CAP_IMPORT : 0; +		req->value |= dev->driver->prime_handle_to_fd ? DRM_PRIME_CAP_EXPORT : 0; +		break; +	case DRM_CAP_TIMESTAMP_MONOTONIC: +		req->value = drm_timestamp_monotonic; +		break; +	case DRM_CAP_ASYNC_PAGE_FLIP: +		req->value = dev->mode_config.async_page_flip; +		break; +	case DRM_CAP_CURSOR_WIDTH: +		if (dev->mode_config.cursor_width) +			req->value = dev->mode_config.cursor_width;  		else -			stats->data[i].value = atomic_read(&dev->counts[i]); -		stats->data[i].type = dev->types[i]; +			req->value = 64; +		break; +	case DRM_CAP_CURSOR_HEIGHT: +		if (dev->mode_config.cursor_height) +			req->value = dev->mode_config.cursor_height; +		else +			req->value = 64; +		break; +	default: +		return -EINVAL;  	} +	return 0; +} -	stats->count = dev->counters; - -	mutex_unlock(&dev->struct_mutex); +/** + * Set device/driver capabilities + */ +int +drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ +	struct drm_set_client_cap *req = data; + +	switch (req->capability) { +	case DRM_CLIENT_CAP_STEREO_3D: +		if (req->value > 1) +			return -EINVAL; +		file_priv->stereo_allowed = req->value; +		break; +	case DRM_CLIENT_CAP_UNIVERSAL_PLANES: +		if (!drm_universal_planes) +			return -EINVAL; +		if (req->value > 1) +			return -EINVAL; +		file_priv->universal_planes = req->value; +		break; +	default: +		return -EINVAL; +	}  	return 0;  } @@ -407,9 +398,6 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri  			retcode = -EINVAL;  			goto done;  		} - -		if (dev->driver->set_version) -			dev->driver->set_version(dev, sv);  	}  done: @@ -428,3 +416,4 @@ int drm_noop(struct drm_device *dev, void *data,  	DRM_DEBUG("\n");  	return 0;  } +EXPORT_SYMBOL(drm_noop);  | 
