[Intel-gfx] [PATCH v4] drm/i915: read/write ioctls for userspace
Ben Widawsky
ben at bwidawsk.net
Tue Apr 5 03:30:10 CEST 2011
Straight forward IOCTLs which allow userspace to read and write
registers. This is needed because on newer generation products,
registers may become inaccessible due to specific power modes.
To manage this, created a set of register ranges for the different
products which can give fine grained control over what we permit
userspace to read and write. This list was created by hand, so expect
issues/bugs.
The fields in the calls allow register widths to be defined, although
currently this is not used by any products. There is also a rsvd field
which can be used for giving a list of register reads/writes to perform
in the future.
Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
---
drivers/gpu/drm/i915/Makefile | 1 +
drivers/gpu/drm/i915/i915_debugfs.c | 19 +++++
drivers/gpu/drm/i915/i915_dma.c | 87 ++++++++++++++++++++
drivers/gpu/drm/i915/i915_drv.h | 25 ++++++
drivers/gpu/drm/i915/i915_reg_maps.c | 143 ++++++++++++++++++++++++++++++++++
include/drm/i915_drm.h | 30 +++++++
6 files changed, 305 insertions(+), 0 deletions(-)
create mode 100644 drivers/gpu/drm/i915/i915_reg_maps.c
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0ae6a7c..6544076 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -13,6 +13,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
i915_gem_gtt.o \
i915_gem_tiling.o \
i915_trace_points.o \
+ i915_reg_maps.o \
intel_display.o \
intel_crt.o \
intel_lvds.o \
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 87c8e29..81f49d0 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1186,6 +1186,24 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
return 0;
}
+static int i915_user_tainted_info(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct i915_register_range *range = dev_priv->register_map.map;
+
+ while (!(range->flags & I915_RANGE_END)) {
+ if (range->flags & I915_RANGE_TAINTED) {
+ seq_printf(m, "tainted register range 0x%08x->0x%08x\n",
+ range->base, range->size);
+ }
+ range++;
+ }
+
+ return 0;
+}
+
static int
i915_wedged_open(struct inode *inode,
struct file *filp)
@@ -1324,6 +1342,7 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_sr_status", i915_sr_status, 0},
{"i915_opregion", i915_opregion, 0},
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
+ {"i915_user_tainted", i915_user_tainted_info, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 7273037..cce61a8 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1846,6 +1846,89 @@ out_unlock:
}
EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
+static struct i915_register_range *
+get_register_range(struct drm_device *dev, u32 offset, int mode)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct i915_register_range *range = dev_priv->register_map.map;
+ u8 align = dev_priv->register_map.alignment_mask;
+
+ if (offset & dev_priv->register_map.alignment_mask)
+ return NULL;
+
+ if (offset >= dev_priv->register_map.top)
+ return NULL;
+
+ while (!(range->flags & I915_RANGE_END)) {
+ /* list is assumed to be in order */
+ if (offset < range->base)
+ break;
+
+ if ( (offset >= range->base) &&
+ (offset + align) <= (range->base + range->size)) {
+ if ((mode & range->flags) == mode)
+ return range;
+ }
+ range++;
+ }
+
+ return NULL;
+}
+
+static int
+i915_read_register_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_intel_write_reg *args = data;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
+
+ if (dev_priv->register_map.map == NULL)
+ return -ENOTSUPP;
+
+ if (get_register_range(dev, args->offset, I915_RANGE_READ) == NULL) {
+ args->value = 0xffffffff;
+ return -EINVAL;
+ }
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+
+ args->value = (u32)i915_gt_read(dev_priv, args->offset);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+static int
+i915_write_register_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_intel_read_reg *args = data;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct i915_register_range *range;
+ int ret;
+
+ if (dev_priv->register_map.map == NULL)
+ return -ENOTSUPP;
+
+ range = get_register_range(dev, args->offset, I915_RANGE_WRITE);
+ if (!range)
+ return -EINVAL;
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+
+ DRM_INFO("User space write %x %x\n", args->offset, (u32)args->value);
+ range->flags |= I915_RANGE_TAINTED;
+ i915_gt_write(dev_priv, args->offset, (u32)args->value);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
/**
* Tells the intel_ips driver that the i915 driver is now loaded, if
* IPS got loaded first.
@@ -2062,6 +2145,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
ips_ping_for_i915_load();
+ i915_init_register_map(dev);
+
return 0;
out_gem_unload:
@@ -2276,6 +2361,8 @@ struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF_DRV(I915_READ_REGISTER, i915_read_register_ioctl, DRM_UNLOCKED),
+ DRM_IOCTL_DEF_DRV(I915_WRITE_REGISTER, i915_write_register_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 5004724..ab48a1b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -703,6 +703,14 @@ typedef struct drm_i915_private {
struct intel_fbdev *fbdev;
struct drm_property *broadcast_rgb_property;
+
+ /* User visible register map */
+ struct {
+ struct i915_register_range *map;
+ u32 length;
+ u32 top;
+ u8 alignment_mask;
+ } register_map;
} drm_i915_private_t;
struct drm_i915_gem_object {
@@ -1385,4 +1393,21 @@ static inline void i915_gt_write(struct drm_i915_private *dev_priv,
__gen6_gt_wait_for_fifo(dev_priv);
I915_WRITE(reg, val);
}
+
+/* Register range interface */
+struct i915_register_range {
+ u32 base;
+ u32 size;
+ u32 flags; /* protected by struct_mutex */
+};
+
+#define I915_RANGE_RSVD (0<<0) /* Shouldn't be read or written */
+#define I915_RANGE_READ (1<<0)
+#define I915_RANGE_WRITE (1<<1)
+#define I915_RANGE_RW (I915_RANGE_READ | I915_RANGE_WRITE)
+#define I915_RANGE_TAINTED (1<<30)
+#define I915_RANGE_END (1<<31)
+
+extern int i915_init_register_map(struct drm_device *dev);
+
#endif
diff --git a/drivers/gpu/drm/i915/i915_reg_maps.c b/drivers/gpu/drm/i915/i915_reg_maps.c
new file mode 100644
index 0000000..21f008d
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_reg_maps.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Ben Widawsky <ben at bwidawsk.net>
+ *
+ */
+
+#include "i915_drv.h"
+
+static struct i915_register_range gen_bwcl_register_map[] = {
+ {0x00000000, 0x00000fff, I915_RANGE_RW},
+ {0x00001000, 0x00000fff, I915_RANGE_RSVD},
+ {0x00002000, 0x00000fff, I915_RANGE_RW},
+ {0x00003000, 0x000001ff, I915_RANGE_RW},
+ {0x00003200, 0x00000dff, I915_RANGE_RW},
+ {0x00004000, 0x000003ff, I915_RANGE_RSVD},
+ {0x00004400, 0x00000bff, I915_RANGE_RSVD},
+ {0x00005000, 0x00000fff, I915_RANGE_RW},
+ {0x00006000, 0x00000fff, I915_RANGE_RW},
+ {0x00007000, 0x000003ff, I915_RANGE_RW},
+ {0x00007400, 0x000014ff, I915_RANGE_RW},
+ {0x00008900, 0x000006ff, I915_RANGE_RSVD},
+ {0x00009000, 0x00000fff, I915_RANGE_RSVD},
+ {0x0000a000, 0x00000fff, I915_RANGE_RW},
+ {0x0000b000, 0x00004fff, I915_RANGE_RSVD},
+ {0x00010000, 0x00003fff, I915_RANGE_RW},
+ {0x00014000, 0x0001bfff, I915_RANGE_RSVD},
+ {0x00030000, 0x0000ffff, I915_RANGE_RW},
+ {0x00040000, 0x0001ffff, I915_RANGE_RSVD},
+ {0x00060000, 0x0000ffff, I915_RANGE_RW},
+ {0x00070000, 0x00002fff, I915_RANGE_RW},
+ {0x00073000, 0x00000fff, I915_RANGE_RW},
+ {0x00074000, 0x0000bfff, I915_RANGE_RSVD},
+ {0x00000000, 0x00000000, I915_RANGE_END}
+};
+
+static struct i915_register_range gen4_register_map[] = {
+ {0x00000000, 0x00000fff, I915_RANGE_RW},
+ {0x00001000, 0x00000fff, I915_RANGE_RSVD},
+ {0x00002000, 0x00000fff, I915_RANGE_RW},
+ {0x00003000, 0x000001ff, I915_RANGE_RW},
+ {0x00003200, 0x00000dff, I915_RANGE_RW},
+ {0x00004000, 0x000003ff, I915_RANGE_RW},
+ {0x00004400, 0x00000bff, I915_RANGE_RW},
+ {0x00005000, 0x00000fff, I915_RANGE_RW},
+ {0x00006000, 0x00000fff, I915_RANGE_RW},
+ {0x00007000, 0x000003ff, I915_RANGE_RW},
+ {0x00007400, 0x000014ff, I915_RANGE_RW},
+ {0x00008900, 0x000006ff, I915_RANGE_RSVD},
+ {0x00009000, 0x00000fff, I915_RANGE_RSVD},
+ {0x0000a000, 0x00000fff, I915_RANGE_RW},
+ {0x0000b000, 0x00004fff, I915_RANGE_RSVD},
+ {0x00010000, 0x00003fff, I915_RANGE_RW},
+ {0x00014000, 0x0001bfff, I915_RANGE_RSVD},
+ {0x00030000, 0x0000ffff, I915_RANGE_RW},
+ {0x00040000, 0x0001ffff, I915_RANGE_RSVD},
+ {0x00060000, 0x0000ffff, I915_RANGE_RW},
+ {0x00070000, 0x00002fff, I915_RANGE_RW},
+ {0x00073000, 0x00000fff, I915_RANGE_RW},
+ {0x00074000, 0x0000bfff, I915_RANGE_RSVD},
+ {0x00000000, 0x00000000, I915_RANGE_END}
+};
+
+/* The documentation is a little sketchy on these register ranges. */
+static struct i915_register_range gen6_gt_register_map[] = {
+ {0x00000000, 0x00000fff, I915_RANGE_RW},
+ {0x00001000, 0x00000fff, I915_RANGE_RSVD},
+ {0x00002000, 0x00000fff, I915_RANGE_RW},
+ {0x00003000, 0x000001ff, I915_RANGE_RW},
+ {0x00003200, 0x00000dff, I915_RANGE_RW},
+ {0x00004000, 0x00000fff, I915_RANGE_RW},
+ {0x00005000, 0x0000017f, I915_RANGE_RW},
+ {0x00005180, 0x00000e7f, I915_RANGE_RW},
+ {0x00006000, 0x00001fff, I915_RANGE_RW},
+ {0x00008000, 0x000007ff, I915_RANGE_RW},
+ {0x00008800, 0x000000ff, I915_RANGE_RSVD},
+ {0x00008900, 0x000006ff, I915_RANGE_RW},
+ {0x00009000, 0x00000fff, I915_RANGE_RSVD},
+ {0x0000a000, 0x00000fff, I915_RANGE_RW},
+ {0x0000b000, 0x00004fff, I915_RANGE_RSVD},
+ {0x00010000, 0x00001fff, I915_RANGE_RW},
+ {0x00012000, 0x000003ff, I915_RANGE_RW},
+ {0x00012400, 0x00000bff, I915_RANGE_RW},
+ {0x00013000, 0x00000fff, I915_RANGE_RW},
+ {0x00014000, 0x00000fff, I915_RANGE_RW},
+ {0x00015000, 0x0000cfff, I915_RANGE_RW},
+ {0x00022000, 0x00000fff, I915_RANGE_RW},
+ {0x00023000, 0x00000fff, I915_RANGE_RSVD},
+ {0x00024000, 0x00000fff, I915_RANGE_RW},
+ {0x00025000, 0x0000afff, I915_RANGE_RSVD},
+ {0x00030000, 0x0000ffff, I915_RANGE_RW},
+ {0x00040000, 0x0001ffff, I915_RANGE_RSVD},
+ {0x00060000, 0x0000ffff, I915_RANGE_RW},
+ {0x00070000, 0x00002fff, I915_RANGE_RW},
+ {0x00073000, 0x00000fff, I915_RANGE_RW},
+ {0x00074000, 0x0008bfff, I915_RANGE_RSVD},
+ {0x00100000, 0x00007fff, I915_RANGE_RW},
+ {0x00108000, 0x00037fff, I915_RANGE_RSVD},
+ {0x00140000, 0x0003ffff, I915_RANGE_RW},
+ {0x00000000, 0x00000000, I915_RANGE_END}
+};
+
+int i915_init_register_map(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (IS_GEN6(dev)) {
+ dev_priv->register_map.map = gen6_gt_register_map;
+ dev_priv->register_map.top = 0x180000;
+ } else if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) {
+ dev_priv->register_map.map = gen_bwcl_register_map;
+ dev_priv->register_map.top = 0x80000;
+ } else if (INTEL_INFO(dev)->gen >= 4) {
+ dev_priv->register_map.map = gen4_register_map;
+ dev_priv->register_map.top = 0x80000;
+ } else {
+ dev_priv->register_map.map = NULL;;
+ }
+
+ dev_priv->register_map.alignment_mask = 0x3;
+
+ return 0;
+}
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index c4d6dbf..ff136af 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -198,6 +198,8 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_OVERLAY_PUT_IMAGE 0x27
#define DRM_I915_OVERLAY_ATTRS 0x28
#define DRM_I915_GEM_EXECBUFFER2 0x29
+#define DRM_I915_READ_REGISTER 0x2a
+#define DRM_I915_WRITE_REGISTER 0x2b
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -239,6 +241,8 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise)
#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_IOCTL_I915_OVERLAY_ATTRS, struct drm_intel_overlay_put_image)
#define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
+#define DRM_IOCTL_I915_READ_REGISTER DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_READ_REGISTER, struct drm_intel_read_reg)
+#define DRM_IOCTL_I915_WRITE_REGISTER DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_WRITE_REGISTER, struct drm_intel_write_reg)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -844,4 +848,30 @@ struct drm_intel_overlay_attrs {
__u32 gamma5;
};
+struct drm_intel_read_reg {
+ /* register offset to read */
+ __u32 offset;
+
+ /* register size */
+ __u32 size;
+
+ /* return value, high 4 bytes RFU */
+ __u64 value;
+
+ __u64 rsvd;
+};
+
+struct drm_intel_write_reg {
+ /* register offset to read */
+ __u32 offset;
+
+ /* register size */
+ __u32 size;
+
+ /* value to write, high 4 bytes RFU */
+ __u64 value;
+
+ __u64 rsvd;
+};
+
#endif /* _I915_DRM_H_ */
--
1.7.3.4
More information about the Intel-gfx
mailing list