xref: /openbsd-src/sys/dev/pci/drm/radeon/mkregtable.c (revision 7f4dd37977dc50fdbac8c09deb3ed9ed9b8d0c87)
1*2b2f65d7Sjsg // SPDX-License-Identifier: MIT
21099013bSjsg /* utility to create the register check tables
31099013bSjsg  * this includes inlined list.h safe for userspace.
41099013bSjsg  *
51099013bSjsg  * Copyright 2009 Jerome Glisse
61099013bSjsg  * Copyright 2009 Red Hat Inc.
71099013bSjsg  *
81099013bSjsg  * Authors:
91099013bSjsg  * 	Jerome Glisse
101099013bSjsg  * 	Dave Airlie
111099013bSjsg  */
121099013bSjsg 
131099013bSjsg #include <sys/types.h>
141099013bSjsg #include <stdlib.h>
151099013bSjsg #include <string.h>
161099013bSjsg #include <stdio.h>
171099013bSjsg #include <regex.h>
181099013bSjsg #include <libgen.h>
191099013bSjsg 
201099013bSjsg #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
211099013bSjsg /**
221099013bSjsg  * container_of - cast a member of a structure out to the containing structure
231099013bSjsg  * @ptr:    the pointer to the member.
241099013bSjsg  * @type:   the type of the container struct this is embedded in.
251099013bSjsg  * @member: the name of the member within the struct.
261099013bSjsg  *
271099013bSjsg  */
281099013bSjsg #define container_of(ptr, type, member) ({          \
291099013bSjsg 	const typeof(((type *)0)->member)*__mptr = (ptr);    \
301099013bSjsg 		     (type *)((char *)__mptr - offsetof(type, member)); })
311099013bSjsg 
321099013bSjsg /*
331099013bSjsg  * Simple doubly linked list implementation.
341099013bSjsg  *
351099013bSjsg  * Some of the internal functions ("__xxx") are useful when
361099013bSjsg  * manipulating whole lists rather than single entries, as
371099013bSjsg  * sometimes we already know the next/prev entries and we can
381099013bSjsg  * generate better code by using them directly rather than
391099013bSjsg  * using the generic single-entry routines.
401099013bSjsg  */
411099013bSjsg 
421099013bSjsg struct list_head {
431099013bSjsg 	struct list_head *next, *prev;
441099013bSjsg };
451099013bSjsg 
461099013bSjsg 
INIT_LIST_HEAD(struct list_head * list)471099013bSjsg static inline void INIT_LIST_HEAD(struct list_head *list)
481099013bSjsg {
491099013bSjsg 	list->next = list;
501099013bSjsg 	list->prev = list;
511099013bSjsg }
521099013bSjsg 
531099013bSjsg /*
541099013bSjsg  * Insert a new entry between two known consecutive entries.
551099013bSjsg  *
561099013bSjsg  * This is only for internal list manipulation where we know
571099013bSjsg  * the prev/next entries already!
581099013bSjsg  */
591099013bSjsg #ifndef CONFIG_DEBUG_LIST
__list_add(struct list_head * new,struct list_head * prev,struct list_head * next)601099013bSjsg static inline void __list_add(struct list_head *new,
611099013bSjsg 			      struct list_head *prev, struct list_head *next)
621099013bSjsg {
631099013bSjsg 	next->prev = new;
641099013bSjsg 	new->next = next;
651099013bSjsg 	new->prev = prev;
661099013bSjsg 	prev->next = new;
671099013bSjsg }
681099013bSjsg #else
691099013bSjsg extern void __list_add(struct list_head *new,
701099013bSjsg 		       struct list_head *prev, struct list_head *next);
711099013bSjsg #endif
721099013bSjsg 
731099013bSjsg /**
741099013bSjsg  * list_add_tail - add a new entry
751099013bSjsg  * @new: new entry to be added
761099013bSjsg  * @head: list head to add it before
771099013bSjsg  *
781099013bSjsg  * Insert a new entry before the specified head.
791099013bSjsg  * This is useful for implementing queues.
801099013bSjsg  */
list_add_tail(struct list_head * new,struct list_head * head)811099013bSjsg static inline void list_add_tail(struct list_head *new, struct list_head *head)
821099013bSjsg {
831099013bSjsg 	__list_add(new, head->prev, head);
841099013bSjsg }
851099013bSjsg 
861099013bSjsg /**
871099013bSjsg  * list_entry - get the struct for this entry
881099013bSjsg  * @ptr:	the &struct list_head pointer.
891099013bSjsg  * @type:	the type of the struct this is embedded in.
907ccd5a2cSjsg  * @member:	the name of the list_head within the struct.
911099013bSjsg  */
921099013bSjsg #define list_entry(ptr, type, member) \
931099013bSjsg 	container_of(ptr, type, member)
941099013bSjsg 
951099013bSjsg /**
961099013bSjsg  * list_for_each_entry	-	iterate over list of given type
971099013bSjsg  * @pos:	the type * to use as a loop cursor.
981099013bSjsg  * @head:	the head for your list.
997ccd5a2cSjsg  * @member:	the name of the list_head within the struct.
1001099013bSjsg  */
1011099013bSjsg #define list_for_each_entry(pos, head, member)				\
1021099013bSjsg 	for (pos = list_entry((head)->next, typeof(*pos), member);	\
1031099013bSjsg 	     &pos->member != (head); 	\
1041099013bSjsg 	     pos = list_entry(pos->member.next, typeof(*pos), member))
1051099013bSjsg 
1061099013bSjsg struct offset {
1071099013bSjsg 	struct list_head list;
1081099013bSjsg 	unsigned offset;
1091099013bSjsg };
1101099013bSjsg 
1111099013bSjsg struct table {
1121099013bSjsg 	struct list_head offsets;
1131099013bSjsg 	unsigned offset_max;
1141099013bSjsg 	unsigned nentry;
1151099013bSjsg 	unsigned *table;
1161099013bSjsg 	char *gpu_prefix;
1171099013bSjsg };
1181099013bSjsg 
offset_new(unsigned o)1191099013bSjsg static struct offset *offset_new(unsigned o)
1201099013bSjsg {
1211099013bSjsg 	struct offset *offset;
1221099013bSjsg 
1231099013bSjsg 	offset = (struct offset *)malloc(sizeof(struct offset));
1241099013bSjsg 	if (offset) {
1251099013bSjsg 		INIT_LIST_HEAD(&offset->list);
1261099013bSjsg 		offset->offset = o;
1271099013bSjsg 	}
1281099013bSjsg 	return offset;
1291099013bSjsg }
1301099013bSjsg 
table_offset_add(struct table * t,struct offset * offset)1311099013bSjsg static void table_offset_add(struct table *t, struct offset *offset)
1321099013bSjsg {
1331099013bSjsg 	list_add_tail(&offset->list, &t->offsets);
1341099013bSjsg }
1351099013bSjsg 
table_init(struct table * t)1361099013bSjsg static void table_init(struct table *t)
1371099013bSjsg {
1381099013bSjsg 	INIT_LIST_HEAD(&t->offsets);
1391099013bSjsg 	t->offset_max = 0;
1401099013bSjsg 	t->nentry = 0;
1411099013bSjsg 	t->table = NULL;
1421099013bSjsg }
1431099013bSjsg 
table_print(struct table * t)1441099013bSjsg static void table_print(struct table *t)
1451099013bSjsg {
1461099013bSjsg 	unsigned nlloop, i, j, n, c, id;
1471099013bSjsg 
1481099013bSjsg 	nlloop = (t->nentry + 3) / 4;
1491099013bSjsg 	c = t->nentry;
1501099013bSjsg 	printf("static const unsigned %s_reg_safe_bm[%d] = {\n", t->gpu_prefix,
1511099013bSjsg 	       t->nentry);
1521099013bSjsg 	for (i = 0, id = 0; i < nlloop; i++) {
1531099013bSjsg 		n = 4;
1541099013bSjsg 		if (n > c)
1551099013bSjsg 			n = c;
1561099013bSjsg 		c -= n;
1571099013bSjsg 		for (j = 0; j < n; j++) {
1581099013bSjsg 			if (j == 0)
1591099013bSjsg 				printf("\t");
1601099013bSjsg 			else
1611099013bSjsg 				printf(" ");
1621099013bSjsg 			printf("0x%08X,", t->table[id++]);
1631099013bSjsg 		}
1641099013bSjsg 		printf("\n");
1651099013bSjsg 	}
1661099013bSjsg 	printf("};\n");
1671099013bSjsg }
1681099013bSjsg 
table_build(struct table * t)1691099013bSjsg static int table_build(struct table *t)
1701099013bSjsg {
1711099013bSjsg 	struct offset *offset;
1721099013bSjsg 	unsigned i, m;
1731099013bSjsg 
1741099013bSjsg 	t->nentry = ((t->offset_max >> 2) + 31) / 32;
1751099013bSjsg 	t->table = (unsigned *)malloc(sizeof(unsigned) * t->nentry);
1761099013bSjsg 	if (t->table == NULL)
1771099013bSjsg 		return -1;
1781099013bSjsg 	memset(t->table, 0xff, sizeof(unsigned) * t->nentry);
1791099013bSjsg 	list_for_each_entry(offset, &t->offsets, list) {
1801099013bSjsg 		i = (offset->offset >> 2) / 32;
1811099013bSjsg 		m = (offset->offset >> 2) & 31;
1821099013bSjsg 		m = 1 << m;
1831099013bSjsg 		t->table[i] ^= m;
1841099013bSjsg 	}
1851099013bSjsg 	return 0;
1861099013bSjsg }
1871099013bSjsg 
1881099013bSjsg static char gpu_name[10];
parser_auth(struct table * t,const char * filename)1891099013bSjsg static int parser_auth(struct table *t, const char *filename)
1901099013bSjsg {
1911099013bSjsg 	FILE *file;
1921099013bSjsg 	regex_t mask_rex;
1931099013bSjsg 	regmatch_t match[4];
1941099013bSjsg 	char buf[1024];
1951099013bSjsg 	size_t end;
1961099013bSjsg 	int len;
1971099013bSjsg 	int done = 0;
1981099013bSjsg 	int r;
1991099013bSjsg 	unsigned o;
2001099013bSjsg 	struct offset *offset;
2011099013bSjsg 	char last_reg_s[10];
2021099013bSjsg 	int last_reg;
2031099013bSjsg 
2041099013bSjsg 	if (regcomp
2051099013bSjsg 	    (&mask_rex, "(0x[0-9a-fA-F]*) *([_a-zA-Z0-9]*)", REG_EXTENDED)) {
2061099013bSjsg 		fprintf(stderr, "Failed to compile regular expression\n");
2071099013bSjsg 		return -1;
2081099013bSjsg 	}
2091099013bSjsg 	file = fopen(filename, "r");
2101099013bSjsg 	if (file == NULL) {
2111099013bSjsg 		fprintf(stderr, "Failed to open: %s\n", filename);
2121099013bSjsg 		return -1;
2131099013bSjsg 	}
2141099013bSjsg 	fseek(file, 0, SEEK_END);
2151099013bSjsg 	end = ftell(file);
2161099013bSjsg 	fseek(file, 0, SEEK_SET);
2171099013bSjsg 
2181099013bSjsg 	/* get header */
2191099013bSjsg 	if (fgets(buf, 1024, file) == NULL) {
2201099013bSjsg 		fclose(file);
2211099013bSjsg 		return -1;
2221099013bSjsg 	}
2231099013bSjsg 
2241099013bSjsg 	/* first line will contain the last register
2251099013bSjsg 	 * and gpu name */
2267ccd5a2cSjsg 	sscanf(buf, "%9s %9s", gpu_name, last_reg_s);
2271099013bSjsg 	t->gpu_prefix = gpu_name;
2281099013bSjsg 	last_reg = strtol(last_reg_s, NULL, 16);
2291099013bSjsg 
2301099013bSjsg 	do {
2311099013bSjsg 		if (fgets(buf, 1024, file) == NULL) {
2321099013bSjsg 			fclose(file);
2331099013bSjsg 			return -1;
2341099013bSjsg 		}
2351099013bSjsg 		len = strlen(buf);
2361099013bSjsg 		if (ftell(file) == end)
2371099013bSjsg 			done = 1;
2381099013bSjsg 		if (len) {
2391099013bSjsg 			r = regexec(&mask_rex, buf, 4, match, 0);
2401099013bSjsg 			if (r == REG_NOMATCH) {
2411099013bSjsg 			} else if (r) {
2421099013bSjsg 				fprintf(stderr,
2431099013bSjsg 					"Error matching regular expression %d in %s\n",
2441099013bSjsg 					r, filename);
2451099013bSjsg 				fclose(file);
2461099013bSjsg 				return -1;
2471099013bSjsg 			} else {
2481099013bSjsg 				buf[match[0].rm_eo] = 0;
2491099013bSjsg 				buf[match[1].rm_eo] = 0;
2501099013bSjsg 				buf[match[2].rm_eo] = 0;
2511099013bSjsg 				o = strtol(&buf[match[1].rm_so], NULL, 16);
2521099013bSjsg 				offset = offset_new(o);
2531099013bSjsg 				table_offset_add(t, offset);
2541099013bSjsg 				if (o > t->offset_max)
2551099013bSjsg 					t->offset_max = o;
2561099013bSjsg 			}
2571099013bSjsg 		}
2581099013bSjsg 	} while (!done);
2591099013bSjsg 	fclose(file);
2601099013bSjsg 	if (t->offset_max < last_reg)
2611099013bSjsg 		t->offset_max = last_reg;
2621099013bSjsg 	return table_build(t);
2631099013bSjsg }
2641099013bSjsg 
main(int argc,char * argv[])2651099013bSjsg int main(int argc, char *argv[])
2661099013bSjsg {
2671099013bSjsg 	struct table t;
2681099013bSjsg 
2691099013bSjsg 	if (argc != 2) {
2701099013bSjsg 		fprintf(stderr, "Usage: %s <authfile>\n", argv[0]);
2711099013bSjsg 		exit(1);
2721099013bSjsg 	}
2731099013bSjsg 	table_init(&t);
2741099013bSjsg 	if (parser_auth(&t, argv[1])) {
2751099013bSjsg 		fprintf(stderr, "Failed to parse file %s\n", argv[1]);
2761099013bSjsg 		return -1;
2771099013bSjsg 	}
2781099013bSjsg 	table_print(&t);
2791099013bSjsg 	return 0;
2801099013bSjsg }
281