@@ -26,29 +26,83 @@
*/
#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
#include <sys/types.h>
+#include <sys/ioctl.h>
#include <pciaccess.h>
#include "intel_chipset.h"
#include "intel_reg.h"
+#include "i915_drm.h"
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
extern void *mmio;
+extern int mmio_fd;
+extern int use_ioctl_mmio;
void intel_get_mmio(struct pci_device *pci_dev);
+#define INREG(reg) \
+ (use_ioctl_mmio ? INREG_IOCTL(reg) : INREG_PCI(reg))
+
+#define OUTREG(reg, val) \
+ (use_ioctl_mmio ? OUTREG_IOCTL(reg, val) : OUTREG_PCI(reg, val))
+
static inline uint32_t
-INREG(uint32_t reg)
+INREG_PCI(uint32_t reg)
{
return *(volatile uint32_t *)((volatile char *)mmio + reg);
}
+/*
+ * Try to read a register using the i915 IOCTL interface. The operations should
+ * not fall back to the normal pci mmio method to avoid confusion. IOCTL usage
+ * should be explicitly specified.
+ */
+static inline uint32_t
+INREG_IOCTL(uint32_t reg)
+{
+ int err;
+ struct drm_intel_read_reg reg_read = {
+ .offset = reg,
+ .size = 0
+ };
+
+ assert(mmio_fd >= 0);
+ err = ioctl(mmio_fd, DRM_IOCTL_I915_READ_REGISTER, ®_read);
+ if (err)
+ fprintf(stderr, "read 0x%08x fail %s\n", reg, strerror(err));
+ return (uint32_t)reg_read.value;
+}
+
static inline void
-OUTREG(uint32_t reg, uint32_t val)
+OUTREG_PCI(uint32_t reg, uint32_t val)
{
*(volatile uint32_t *)((volatile char *)mmio + reg) = val;
}
+/*
+ * See INREG_IOCTL()
+ */
+
+static inline void
+OUTREG_IOCTL(uint32_t reg, uint32_t val)
+{
+ int err;
+ struct drm_intel_write_reg reg_write = {
+ .offset = reg,
+ .size = 4,
+ .value = (uint64_t)val
+ };
+
+ assert(mmio_fd >= 0);
+ err = ioctl(mmio_fd, DRM_IOCTL_I915_WRITE_REGISTER, ®_write);
+ if (err)
+ fprintf(stderr, "write 0x%08x fail %s\n", reg, strerror(err));
+}
+
struct pci_device *intel_get_pci_device(void);
uint32_t intel_get_drm_devid(int fd);
@@ -40,6 +40,9 @@
#include "intel_gpu_tools.h"
void *mmio;
+int mmio_fd = -1;
+/* ioctls are not default */
+int use_ioctl_mmio = 0;
void
intel_map_file(char *file)
@@ -60,6 +63,9 @@ intel_map_file(char *file)
strerror(errno));
exit(1);
}
+
+ mmio_fd = fd;
+
close(fd);
}
@@ -87,5 +93,17 @@ intel_get_mmio(struct pci_device *pci_dev)
strerror(err));
exit(1);
}
+
+ if (!use_ioctl_mmio)
+ return;
+
+ /* XXX: this is major lame, we need to have the device file match the
+ * pci_dev, any good way to do that? */
+ mmio_fd = drm_open_any();
+ if (mmio_fd == -1) {
+ fprintf(stderr, "Couldn't get an fd for gen6 device\n");
+ exit(1);
+ }
+
}
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
+#include <string.h>
#include <sys/ioctl.h>
#include "intel_gpu_tools.h"
#include "instdone.h"
@@ -297,33 +298,6 @@ struct ring {
int idle;
};
-static void gen6_force_wake_get(void)
-{
- int count;
-
- if (!IS_GEN6(devid))
- return;
-
- /* This will probably have undesirable side-effects upon the system. */
- count = 0;
- while (count++ < 50 && (INREG(FORCEWAKE_ACK) & 1))
- usleep(10);
-
- OUTREG(FORCEWAKE, 1);
-
- count = 0;
- while (count++ < 50 && (INREG(FORCEWAKE_ACK) & 1) == 0)
- usleep(10);
-}
-
-static void gen6_force_wake_put(void)
-{
- if (!IS_GEN6(devid))
- return;
-
- OUTREG(FORCEWAKE, 0);
-}
-
static uint32_t ring_read(struct ring *ring, uint32_t reg)
{
return INREG(ring->mmio + reg);
@@ -331,9 +305,7 @@ static uint32_t ring_read(struct ring *ring, uint32_t reg)
static void ring_init(struct ring *ring)
{
- gen6_force_wake_get();
ring->size = (((ring_read(ring, RING_LEN) & RING_NR_PAGES) >> 12) + 1) * 4096;
- gen6_force_wake_put();
}
static void ring_reset(struct ring *ring)
@@ -348,10 +320,8 @@ static void ring_sample(struct ring *ring)
if (!ring->size)
return;
- gen6_force_wake_get();
ring->head = ring_read(ring, RING_HEAD) & HEAD_ADDR;
ring->tail = ring_read(ring, RING_TAIL) & TAIL_ADDR;
- gen6_force_wake_put();
if (ring->tail == ring->head)
ring->idle++;
@@ -397,11 +367,24 @@ int main(int argc, char **argv)
};
int i;
+ if (argc == 2) {
+ if ((strlen(argv[1]) == 2) &&
+ !strncmp(argv[1], "-i", 2)) {
+ printf("using ioctl mmio access\n");
+ use_ioctl_mmio = 1;
+ }
+ }
+
pci_dev = intel_get_pci_device();
devid = pci_dev->device_id;
intel_get_mmio(pci_dev);
init_instdone_definitions(devid);
+ if (IS_GEN6(devid) && !use_ioctl_mmio)
+ fprintf(stderr, "using ioctl for mmio "
+ " read/write is recommended (%s -i)\n",
+ argv[0]);
+
for (i = 0; i < num_instdone_bits; i++) {
top_bits[i].bit = &instdone_bits[i];
top_bits[i].count = 0;
Added the mechnanism to communicate with the i915 IOCTL interface, and removed the existing forcewake code, as it is not reliable. Modified gpu_top to take a flag -i, to use the IOCTL interface. Previous gpu_top behavior with no args is maintained from previous version. Signed-off-by: Ben Widawsky <ben@bwidawsk.net> --- lib/intel_gpu_tools.h | 58 +++++++++++++++++++++++++++++++++++++++++++++++- lib/intel_mmio.c | 18 +++++++++++++++ tools/intel_gpu_top.c | 45 +++++++++++-------------------------- 3 files changed, 88 insertions(+), 33 deletions(-)