diff options
Diffstat (limited to 'drivers/gpu/drm/drm_ioctl.c')
| -rw-r--r-- | drivers/gpu/drm/drm_ioctl.c | 154 |
1 files changed, 105 insertions, 49 deletions
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index e77bd8b57df..69c61f392e6 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -38,6 +38,9 @@ #include <linux/pci.h> #include <linux/export.h> +#ifdef CONFIG_X86 +#include <asm/mtrr.h> +#endif /** * Get the bus id. @@ -69,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; @@ -90,7 +90,8 @@ 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) @@ -105,10 +106,13 @@ int drm_setunique(struct drm_device *dev, void *data, if (!u->unique_len || u->unique_len > 1024) return -EINVAL; - if (!dev->driver->bus->set_unique) + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + if (WARN_ON(!dev->pdev)) return -EINVAL; - ret = dev->driver->bus->set_unique(dev, master, u); + ret = drm_pci_set_unique(dev, master, u); if (ret) goto err; @@ -127,13 +131,25 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) if (master->unique != NULL) drm_unset_busid(dev, master); - ret = dev->driver->bus->set_busid(dev, master); - if (ret) - 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; + } + } else { + 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; } /** @@ -181,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; @@ -204,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; - i = 0; - mutex_lock(&dev->struct_mutex); - list_for_each_entry(pt, &dev->filelist, lhead) { - if (i++ >= idx) { - client->auth = pt->authenticated; - client->pid = pid_vnr(pt->pid); - client->uid = from_kuid_munged(current_user_ns(), 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; } /** @@ -243,21 +270,10 @@ 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)); - 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); - else - stats->data[i].value = atomic_read(&dev->counts[i]); - stats->data[i].type = dev->types[i]; - } - - stats->count = dev->counters; - return 0; } @@ -290,6 +306,21 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) 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 + 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; } @@ -297,6 +328,34 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) } /** + * 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; +} + +/** * Setversion ioctl. * * \param inode device inode. @@ -339,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: |
