mirror of
				https://github.com/tiagovignatti/intel-gpu-tools.git
				synced 2025-11-04 12:07:12 +00:00 
			
		
		
		
	v2: Repaint with Jani's favorite color Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
		
			
				
	
	
		
			354 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			354 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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 = 1,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		.name = "mmio-vga",
 | 
						|
		.port = PORT_MMIO_VGA,
 | 
						|
		.stride = 1,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		.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 (®ex, REGEXP, REG_EXTENDED)) {
 | 
						|
			fprintf(stderr, "regcomp %s\n", REGEXP);
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
		initialized = true;
 | 
						|
	}
 | 
						|
 | 
						|
	memset(reg, 0, sizeof(*reg));
 | 
						|
 | 
						|
	ret = regexec(®ex, 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(®, 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);
 | 
						|
}
 | 
						|
 | 
						|
void intel_reg_spec_print_ports(void)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < ARRAY_SIZE(port_descs); i++)
 | 
						|
		printf("%s%s", i == 0 ? "" : ", ", port_descs[i].name);
 | 
						|
}
 |