Commit dfda0b6a authored by Jani Nikula's avatar Jani Nikula

intel_reg: introduce one intel_reg tool to rule them all

	Three Tools for the Elven-kings under the sky,
	Seven for the Dwarf-lords in their halls of stone,
	Nine for Mortal Men doomed to die,
	One for the Dark Lord on his dark throne
	In the Land of Mordor where the Shadows lie.
	One Tool to rule them all, One Tool to find them,
	One Tool to bring them all and in the darkness bind them
	In the Land of Mordor where the Shadows lie.

		J.R.R. Tolkien's epigraph to The Lord of The Tools
		 | sed 's/Ring/Tool/g'

Introduce intel_reg as the one Intel graphics register multitool to
replace intel_reg_read, intel_reg_write, intel_iosf_sb_read,
intel_iosf_sb_write, intel_vga_read, intel_vga_write, intel_reg_dumper,
intel_reg_snapshot, and quick_dump.py.
Signed-off-by: Jani Nikula's avatarJani Nikula <jani.nikula@intel.com>
parent e1ce5eac
......@@ -5,6 +5,7 @@ noinst_PROGRAMS = \
bin_PROGRAMS = \
intel_audio_dump \
intel_reg \
intel_backlight \
intel_bios_dumper \
intel_bios_reader \
......@@ -40,6 +41,11 @@ dist_bin_SCRIPTS = intel_gpu_abrt
intel_dump_decode_SOURCES = \
intel_dump_decode.c
intel_reg_SOURCES = \
intel_reg.c \
intel_reg_decode.c \
intel_reg_spec.c
intel_error_decode_SOURCES = \
intel_error_decode.c
......
This diff is collapsed.
This diff is collapsed.
/*
* Copyright © 2015 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.
*/
#include <ctype.h>
#include <errno.h>
#include <regex.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intel_reg_spec.h"
static const struct port_desc port_descs[] = {
{
.name = "mmio",
.port = PORT_MMIO,
.stride = 4,
},
{
.name = "portio-vga",
.port = PORT_PORTIO_VGA,
.stride = 4,
},
{
.name = "mmio-vga",
.port = PORT_MMIO_VGA,
.stride = 4,
},
{
.name = "bunit",
.port = PORT_BUNIT,
.stride = 1,
},
{
.name = "punit",
.port = PORT_PUNIT,
.stride = 1,
},
{
.name = "nc",
.port = PORT_NC,
.stride = 4,
},
{
.name = "dpio",
.port = PORT_DPIO,
.stride = 4,
},
{
.name = "gpio-nc",
.port = PORT_GPIO_NC,
.stride = 4,
},
{
.name = "gpio_nc",
.port = PORT_GPIO_NC,
.stride = 4,
},
{
.name = "cck",
.port = PORT_CCK,
.stride = 1,
},
{
.name = "ccu",
.port = PORT_CCU,
.stride = 4,
},
{
.name = "dpio2",
.port = PORT_DPIO2,
.stride = 4,
},
{
.name = "flisdsi",
.port = PORT_FLISDSI,
.stride = 1,
},
};
/*
* Parse port desc of the form (PORTNAME|PORTNUM|MMIO-OFFSET) into reg. NULL or
* zero length s is regarded as MMIO.
*/
int parse_port_desc(struct reg *reg, const char *s)
{
enum port_addr port = PORT_NONE;
int i;
if (s && *s) {
/* See if port is specified by number. */
char *endp;
unsigned long n = strtoul(s, &endp, 16);
if (endp > s && *endp == 0) {
if (n > PORT_MAX) {
/* Not a sideband port, assume MMIO offset. */
port = PORT_MMIO;
reg->mmio_offset = n;
} else {
port = n;
reg->mmio_offset = 0;
}
} else {
reg->mmio_offset = 0;
}
} else {
/* No port, default to searching for MMIO. */
port = PORT_MMIO;
reg->mmio_offset = 0;
}
for (i = 0; i < ARRAY_SIZE(port_descs); i++) {
if ((port != PORT_NONE && port_descs[i].port == port) ||
(s && strcasecmp(s, port_descs[i].name) == 0)) {
reg->port_desc = port_descs[i];
return 0;
}
}
return -1;
}
static const char *skip_space(const char *line)
{
while (*line && isspace(*line))
line++;
return line;
}
static bool ignore_line(const char *line)
{
line = skip_space(line);
switch (*line) {
case '\0':
case '#':
case ';':
return true;
case '/':
return *(line + 1) == '/';
}
return false;
}
static char *include_file(const char *line, const char *source)
{
char *filename, *p;
line = skip_space(line);
if (*line == '(')
return NULL;
/* this'll be plenty */
filename = malloc(strlen(source) + strlen(line) + 1);
if (!filename)
return NULL;
p = strrchr(source, '/');
if (p && *line != '/') {
int len = p - source + 1;
memcpy(filename, source, len);
strcpy(filename + len, line);
} else {
strcpy(filename, line);
}
p = strchr(filename, '\n');
if (p)
*p = '\0';
return filename;
}
#define SPC "[[:space:]]*"
#define SEP SPC "," SPC
#define BEG "^" SPC "\\(" SPC
#define END SPC "\\)" SPC "$"
#define VALUE "([[:print:]]*)"
#define QVALUE "'" VALUE "'"
#define REGEXP BEG QVALUE SEP QVALUE SEP QVALUE END
static int parse_line(struct reg *reg, const char *line)
{
static regex_t regex;
static bool initialized = false;
regmatch_t match[4];
int i, ret;
if (!initialized) {
if (regcomp (&regex, REGEXP, REG_EXTENDED)) {
fprintf(stderr, "regcomp %s\n", REGEXP);
return -1;
}
initialized = true;
}
memset(reg, 0, sizeof(*reg));
ret = regexec(&regex, line, ARRAY_SIZE(match), match, 0);
if (ret)
ret = -1;
for (i = 1; i < ARRAY_SIZE(match) && ret == 0; i++) {
char *p, *e;
p = strndup(line + match[i].rm_so,
match[i].rm_eo - match[i].rm_so);
if (i == 1) {
reg->name = p;
} else if (i == 2) {
reg->addr = strtoul(p, &e, 16);
free(p);
if (*e)
ret = -1;
} else if (i == 3) {
ret = parse_port_desc(reg, p);
free(p);
}
}
if (ret)
free(reg->name);
return ret;
}
static ssize_t parse_file(struct reg **regs, size_t *nregs,
ssize_t index, const char *filename)
{
FILE *file;
char *line = NULL, *include;
size_t linesize = 0;
int lineno = 0, r;
ssize_t ret = -1;
file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Error: fopen '%s': %s\n",
filename, strerror(errno));
return -1;
}
while (getline(&line, &linesize, file) != -1) {
struct reg reg;
lineno++;
if (ignore_line(line))
continue;
include = include_file(line, filename);
if (include) {
index = parse_file(regs, nregs, index, include);
free(include);
if (index < 0) {
fprintf(stderr, "Error: %s:%d: %s",
filename, lineno, line);
goto out;
}
continue;
}
r = parse_line(&reg, line);
if (r < 0) {
fprintf(stderr, "Error: %s:%d: %s",
filename, lineno, line);
goto out;
} else if (r) {
continue;
}
if (!*regs || index >= *nregs) {
if (!*regs)
*nregs = 64;
else
*nregs *= 2;
*regs = recalloc(*regs, *nregs, sizeof(**regs));
if (!*regs) {
fprintf(stderr, "Error: %s\n", strerror(ENOMEM));
goto out;
}
}
(*regs)[index++] = reg;
}
ret = index;
out:
free(line);
fclose(file);
return ret;
}
/*
* Get register definitions from file.
*/
ssize_t intel_reg_spec_file(struct reg **regs, const char *file)
{
size_t nregs = 0;
*regs = NULL;
return parse_file(regs, &nregs, 0, file);
}
/*
* Free the memory allocated for register definitions.
*/
void intel_reg_spec_free(struct reg *regs, size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
free(regs[i].name);
}
free(regs);
}
/*
* Copyright © 2015 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.
*/
#ifndef __INTEL_REG_SPEC_H__
#define __INTEL_REG_SPEC_H__
enum port_addr {
PORT_NONE = 0,
PORT_MMIO = -1,
PORT_PORTIO_VGA = -2, /* see vga reg read/write */
PORT_MMIO_VGA = -3, /* see vga reg read/write */
/* vlv */
PORT_BUNIT = 0x03,
PORT_PUNIT = 0x04,
PORT_NC = 0x11,
PORT_DPIO = 0x12,
PORT_GPIO_NC = 0x13,
PORT_CCK = 0x14,
PORT_CCU = 0xa9,
PORT_DPIO2 = 0x1a,
PORT_FLISDSI = 0x1b,
/* threshold for interpreting port as mmio offset */
PORT_MAX = 0xff,
};
struct port_desc {
enum port_addr port;
const char *name;
uint32_t stride;
};
struct reg {
struct port_desc port_desc;
uint32_t mmio_offset;
uint32_t addr;
char *name;
};
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#endif
static inline void *recalloc(void *ptr, size_t nmemb, size_t size)
{
return realloc(ptr, nmemb * size);
}
int parse_port_desc(struct reg *reg, const char *s);
ssize_t intel_reg_spec_builtin(struct reg **regs, uint32_t devid);
ssize_t intel_reg_spec_file(struct reg **regs, const char *filename);
void intel_reg_spec_free(struct reg *regs, size_t n);
int intel_reg_spec_decode(char *buf, size_t bufsize, const struct reg *reg,
uint32_t val, uint32_t devid);
#endif /* __INTEL_REG_SPEC_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment