summaryrefslogtreecommitdiff
path: root/lib/intel_mmio.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/intel_mmio.c')
-rw-r--r--lib/intel_mmio.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/lib/intel_mmio.c b/lib/intel_mmio.c
new file mode 100644
index 00000000..ecb049b7
--- /dev/null
+++ b/lib/intel_mmio.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright © 2008 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:
+ * Eric Anholt <eric@anholt.net>
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include <assert.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "intel_gpu_tools.h"
+
+void *mmio;
+
+static struct _mmio_data {
+ int inited;
+ bool safe;
+ char debugfs_path[FILENAME_MAX];
+ char debugfs_forcewake_path[FILENAME_MAX];
+ uint32_t i915_devid;
+ struct intel_register_map map;
+ int key;
+} mmio_data;
+
+void
+intel_map_file(char *file)
+{
+ int fd;
+ struct stat st;
+
+ fd = open(file, O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "Couldn't open %s: %s\n", file,
+ strerror(errno));
+ exit(1);
+ }
+ fstat(fd, &st);
+ mmio = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (mmio == MAP_FAILED) {
+ fprintf(stderr, "Couldn't mmap %s: %s\n", file,
+ strerror(errno));
+ exit(1);
+ }
+ close(fd);
+}
+
+void
+intel_get_mmio(struct pci_device *pci_dev)
+{
+ uint32_t devid, gen;
+ int mmio_bar, mmio_size;
+ int error;
+
+ devid = pci_dev->device_id;
+ if (IS_GEN2(devid))
+ mmio_bar = 1;
+ else
+ mmio_bar = 0;
+
+ gen = intel_gen(devid);
+ if (gen < 3)
+ mmio_size = 64*1024;
+ else if (gen < 5)
+ mmio_size = 512*1024;
+ else
+ mmio_size = 2*1024*1024;
+
+ error = pci_device_map_range (pci_dev,
+ pci_dev->regions[mmio_bar].base_addr,
+ mmio_size,
+ PCI_DEV_MAP_FLAG_WRITABLE,
+ &mmio);
+
+ if (error != 0) {
+ fprintf(stderr, "Couldn't map MMIO region: %s\n",
+ strerror(error));
+ exit(1);
+ }
+}
+
+/*
+ * If successful, i915_debugfs_path and i915_debugfs_forcewake_path are both
+ * updated with the correct path.
+ */
+static int
+find_debugfs_path(const char *dri_base)
+{
+ char buf[FILENAME_MAX];
+ struct stat sb;
+ int i, ret;
+
+ for (i = 0; i < 16; i++) {
+ snprintf(buf, FILENAME_MAX, "%s/%i/name", dri_base, i);
+
+ snprintf(mmio_data.debugfs_path, FILENAME_MAX,
+ "%s/%i/", dri_base, i);
+ snprintf(mmio_data.debugfs_forcewake_path, FILENAME_MAX,
+ "%s/%i/i915_forcewake_user", dri_base, i);
+
+ ret = stat(mmio_data.debugfs_forcewake_path, &sb);
+ if (ret) {
+ mmio_data.debugfs_path[0] = 0;
+ mmio_data.debugfs_forcewake_path[0] = 0;
+ } else
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+get_forcewake_lock(void)
+{
+ return open(mmio_data.debugfs_forcewake_path, 0);
+}
+
+static void
+release_forcewake_lock(int fd)
+{
+ close(fd);
+}
+
+/*
+ * Initialize register access library.
+ *
+ * @pci_dev: pci device we're mucking with
+ * @safe: use safe register access tables
+ */
+int
+intel_register_access_init(struct pci_device *pci_dev, int safe)
+{
+ int ret;
+
+ /* after old API is deprecated, remove this */
+ if (mmio == NULL)
+ intel_get_mmio(pci_dev);
+
+ assert(mmio != NULL);
+
+ if (mmio_data.inited)
+ return -1;
+
+ mmio_data.safe = safe != 0 ? true : false;
+ mmio_data.i915_devid = pci_dev->device_id;
+ if (mmio_data.safe)
+ mmio_data.map = intel_get_register_map(mmio_data.i915_devid);
+
+ if (!(IS_GEN6(pci_dev->device_id) ||
+ IS_GEN7(pci_dev->device_id)))
+ goto done;
+
+ /* Find where the forcewake lock is */
+ ret = find_debugfs_path("/sys/kernel/debug/dri");
+ if (ret) {
+ ret = find_debugfs_path("/debug/dri");
+ if (ret) {
+ fprintf(stderr, "Couldn't find path to dri/debugfs entry\n");
+ return ret;
+ }
+ }
+ mmio_data.key = get_forcewake_lock();
+
+done:
+ mmio_data.inited++;
+ return 0;
+}
+
+void
+intel_register_access_fini(void)
+{
+ if (mmio_data.key)
+ release_forcewake_lock(mmio_data.key);
+ mmio_data.inited--;
+}
+
+uint32_t
+intel_register_read(uint32_t reg)
+{
+ struct intel_register_range *range;
+ uint32_t ret;
+
+ assert(mmio_data.inited);
+
+ if (intel_gen(mmio_data.i915_devid) >= 6)
+ assert(mmio_data.key != -1);
+
+ if (!mmio_data.safe)
+ goto read_out;
+
+ range = intel_get_register_range(mmio_data.map,
+ reg,
+ INTEL_RANGE_READ);
+
+ if(!range) {
+ fprintf(stderr, "Register read blocked for safety "
+ "(*0x%08x)\n", reg);
+ ret = 0xffffffff;
+ goto out;
+ }
+
+read_out:
+ ret = *(volatile uint32_t *)((volatile char *)mmio + reg);
+out:
+ return ret;
+}
+
+void
+intel_register_write(uint32_t reg, uint32_t val)
+{
+ struct intel_register_range *range;
+
+ assert(mmio_data.inited);
+
+ if (intel_gen(mmio_data.i915_devid) >= 6)
+ assert(mmio_data.key != -1);
+
+ if (!mmio_data.safe)
+ goto write_out;
+
+ range = intel_get_register_range(mmio_data.map,
+ reg,
+ INTEL_RANGE_WRITE);
+
+ if (!range) {
+ fprintf(stderr, "Register write blocked for safety "
+ "(*0x%08x = 0x%x)\n", reg, val);
+ }
+
+write_out:
+ *(volatile uint32_t *)((volatile char *)mmio + reg) = val;
+}