Commit 9616e74b authored by Lucas De Marchi's avatar Lucas De Marchi Committed by Rodrigo Vivi
Browse files

drm/xe: Add support for OOB workarounds



There are WAs that, due to their nature, cannot be applied from a
central place like xe_wa.c. Those are peppered around the rest of the
code, as needed. Now they have a new name:  "out-of-band workarounds".

These workarounds have their names and rules still grouped in xe_wa.c,
inside the xe_wa_oob array, which is generated at compile time by
xe_wa_oob.rules and the hostprog xe_gen_wa_oob. The code generation
guarantees that the header xe_wa_oob.h contains the IDs for the
workarounds that match the index in the table. This way the runtime
checks that are spread throughout the code are simple tests against the
bitmap saved during initialization.

v2: Fix prev_name tracking not working when it's empty, i.e. when there
    is more than 1 continuation rule.

Reviewed-by: default avatarMatt Roper <matthew.d.roper@intel.com>
Link: https://lore.kernel.org/r/20230526164358.86393-13-lucas.demarchi@intel.com


Signed-off-by: default avatarLucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent 464f2243
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
*.hdrtest
/generated
/xe_gen_wa_oob
+13 −0
Original line number Diff line number Diff line
@@ -29,6 +29,19 @@ CFLAGS_xe_pci.o = $(call cc-disable-warning, override-init)

subdir-ccflags-y += -I$(obj) -I$(srctree)/$(src)

# generated sources
hostprogs := xe_gen_wa_oob

generated_oob := $(obj)/generated/xe_wa_oob.c $(obj)/generated/xe_wa_oob.h

quiet_cmd_wa_oob = GEN     $(notdir $(generated_oob))
      cmd_wa_oob = mkdir -p $(@D); $^ $(generated_oob)

$(generated_oob) &: $(obj)/xe_gen_wa_oob $(srctree)/$(src)/xe_wa_oob.rules
	$(call cmd,wa_oob)

$(obj)/xe_wa.o: $(generated_oob)

# Please keep these build lists sorted!

# core driver code
+165 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: MIT
/*
 * Copyright © 2023 Intel Corporation
 */

#define _GNU_SOURCE
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#define HEADER \
	"// SPDX-License-Identifier: MIT\n" \
	"\n" \
	"/*\n" \
	" * DO NOT MODIFY.\n" \
	" *\n" \
	" * This file was generated from rules: %s\n" \
	" */\n" \
	"#ifndef _GENERATED_XE_WA_OOB_\n" \
	"#define _GENERATED_XE_WA_OOB_\n" \
	"\n" \
	"enum {\n"

#define FOOTER \
	"};\n" \
	"\n" \
	"#endif\n"

static void print_usage(FILE *f)
{
	fprintf(f, "usage: %s <input-rule-file> <generated-c-source-file> <generated-c-header-file>\n",
		program_invocation_short_name);
}

static void print_parse_error(const char *err_msg, const char *line,
			      unsigned int lineno)
{
	fprintf(stderr, "ERROR: %s\nERROR: %u: %.60s\n",
		err_msg, lineno, line);
}

static char *strip(char *line, size_t linelen)
{
	while (isspace(*(line + linelen)))
		linelen--;

	line[linelen - 1] = '\0';

	return  line + strspn(line, " \f\n\r\t\v");
}

#define MAX_LINE_LEN 4096
static int parse(FILE *input, FILE *csource, FILE *cheader)
{
	char line[MAX_LINE_LEN + 1];
	char *name, *prev_name = NULL, *rules;
	unsigned int lineno = 0, idx = 0;

	while (fgets(line, sizeof(line), input)) {
		size_t linelen;
		bool is_continuation;

		if (line[0] == '\0' || line[0] == '#' || line[0] == '\n') {
			lineno++;
			continue;
		}

		linelen = strlen(line);
		if (linelen == MAX_LINE_LEN) {
			print_parse_error("line too long", line, lineno);
			return -EINVAL;
		}

		is_continuation = isspace(line[0]);
		name = strip(line, linelen);

		if (!is_continuation) {
			name = strtok(name, " \t");
			rules = strtok(NULL, "");
		} else {
			if (!prev_name) {
				print_parse_error("invalid rule continuation",
						  line, lineno);
				return -EINVAL;
			}

			rules = name;
			name = NULL;
		}

		if (rules[0] == '\0') {
			print_parse_error("invalid empty rule\n", line, lineno);
			return -EINVAL;
		}

		if (name) {
			fprintf(cheader, "\tXE_WA_OOB_%s = %u,\n", name, idx);
			fprintf(csource, "{ XE_RTP_NAME(\"%s\"), XE_RTP_RULES(%s) },\n",
				name, rules);
		} else {
			fprintf(csource, "{ XE_RTP_NAME(NULL), XE_RTP_RULES(%s) },\n",
				rules);
		}

		idx++;
		lineno++;
		if (!is_continuation)
			prev_name = name;
	}

	fprintf(cheader, "\t_XE_WA_OOB_COUNT = %u\n", idx);

	return 0;
}

int main(int argc, const char *argv[])
{
	enum {
		ARGS_INPUT,
		ARGS_CSOURCE,
		ARGS_CHEADER,
		_ARGS_COUNT
	};
	struct {
		const char *fn;
		const char *mode;
		FILE *f;
	} args[] = {
		[ARGS_INPUT] = { .fn = argv[1], .mode = "r" },
		[ARGS_CSOURCE] = { .fn = argv[2], .mode = "w" },
		[ARGS_CHEADER] = { .fn = argv[3], .mode = "w" },
	};
	int ret = 1;

	if (argc < 3) {
		fprintf(stderr, "ERROR: wrong arguments\n");
		print_usage(stderr);
		return 1;
	}

	for (int i = 0; i < _ARGS_COUNT; i++) {
		args[i].f = fopen(args[i].fn, args[i].mode);
		if (!args[i].f) {
			fprintf(stderr, "ERROR: Can't open %s: %m\n",
				args[i].fn);
			goto err;
		}
	}

	fprintf(args[ARGS_CHEADER].f, HEADER, args[ARGS_INPUT].fn);
	ret = parse(args[ARGS_INPUT].f, args[ARGS_CSOURCE].f,
		    args[ARGS_CHEADER].f);
	if (!ret)
		fprintf(args[ARGS_CHEADER].f, FOOTER);

err:
	for (int i = 0; i < _ARGS_COUNT; i++) {
		if (args[i].f)
			fclose(args[i].f);
	}

	return ret;
}
+1 −0
Original line number Diff line number Diff line
@@ -321,6 +321,7 @@ int xe_gt_init_early(struct xe_gt *gt)
		return err;

	xe_wa_process_gt(gt);
	xe_wa_process_oob(gt);
	xe_tuning_process_gt(gt);

	return 0;
+2 −0
Original line number Diff line number Diff line
@@ -368,6 +368,8 @@ struct xe_gt {
		unsigned long *engine;
		/** @lrc: bitmap with active LRC workarounds */
		unsigned long *lrc;
		/** @oob: bitmap with active OOB workaroudns */
		unsigned long *oob;
	} wa_active;
};

Loading