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