All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH i-g-t v3] tools: Add an intel_dbuf_,map tool
@ 2019-12-04 15:13 Stanislav Lisovskiy
  2019-12-04 16:27 ` [igt-dev] ✓ Fi.CI.BAT: success for tools: Add an intel_dbuf_,map tool (rev3) Patchwork
  0 siblings, 1 reply; 2+ messages in thread
From: Stanislav Lisovskiy @ 2019-12-04 15:13 UTC (permalink / raw)
  To: igt-dev; +Cc: martin.peres, juha-pekka.heikkila

As in modern platforms more Display buffer
slices/pipes are coming, which have different
pipe affinities and other constraints, so BSpec
contains their connection in form of a Graph.

So we can generate optimal DBuf assignment,
from the graph which we have in BSpec, to avoid
manual calculations prone to human error and
copy-pasting. The generated table is in C form
and can be used in i915 driver rightaway and also
for verification.

v2: Removed unused i, j, made some functions static,
    to make CI checkers a bit happier. Also had to
    change IGT_LIST to IGT_LIST_HEAD and other stuff,
    as functions seem to be renamed in latest master.

v3: Added command line arguments "--graph" and
    "slices_per_pipe" which allow to define and
    get DBuf assignment from graph without recompiling
    the tool, but right away.
    Example usage:
    intel_dbuf_map --graph PIPE_A-DBUF_S1-DBUF_S2-PIPE_B-PIPE_C --slices_per_pipe 2

    Generates output:
    Graph:
    Type PIPE id 0
        (1)->
             Type DBUF_SLICE id 0
                (1)->
                    Type DBUF_SLICE id 1
                        (1)->
                            Type PIPE id 1
                                (1)->
                                    Type PIPE id 2
    Combination with least weight 3(total combinations 1):
    { BIT(PIPE_A), { DBUF_S1_BIT | DBUF_S2_BIT, 0, 0, 0 } },
    Combination with least weight 3(total combinations 1):
    { BIT(PIPE_B), { 0, DBUF_S2_BIT | DBUF_S1_BIT, 0, 0 } },
    Combination with least weight 2(total combinations 2):
    { BIT(PIPE_A) | BIT(PIPE_B), { DBUF_S1_BIT, DBUF_S2_BIT, 0, 0 } },
    Combination with least weight 5(total combinations 1):
    { BIT(PIPE_C), { 0, 0, DBUF_S2_BIT | DBUF_S1_BIT, 0 } },
    Combination with least weight 3(total combinations 2):
    { BIT(PIPE_A) | BIT(PIPE_C), { DBUF_S1_BIT, 0, DBUF_S2_BIT, 0 } },
    Combination with least weight 4(total combinations 2):
    { BIT(PIPE_B) | BIT(PIPE_C), { 0, DBUF_S2_BIT, DBUF_S1_BIT, 0 } },
    Combination with least weight 4(total combinations 6):
    { BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C), { DBUF_S1_BIT, DBUF_S2_BIT, DBUF_S2_BIT, 0 } },

Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 tools/intel_dbuf_map.c | 787 +++++++++++++++++++++++++++++++++++++++++
 tools/meson.build      |   1 +
 2 files changed, 788 insertions(+)
 create mode 100644 tools/intel_dbuf_map.c

diff --git a/tools/intel_dbuf_map.c b/tools/intel_dbuf_map.c
new file mode 100644
index 00000000..bb20af9b
--- /dev/null
+++ b/tools/intel_dbuf_map.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright © 2019 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.
+ *
+ * Authors:
+ *    Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
+ *
+ */
+
+#include <stdlib.h>
+#include "igt.h"
+#include "igt_list.h"
+
+enum NodeType {
+	DBUF_SLICE,
+	PIPE
+};
+
+const char *node_type_to_str[] = { "DBUF_SLICE", "PIPE" };
+
+#define MAX_CONNECTIONS 10
+#define MAX_NODES 10
+#define MAX_EDGES (MAX_NODES * 2)
+
+struct GraphEdge;
+
+/*
+ * Graph node, which can be DBuf or Pipe
+ */
+struct GraphNode {
+	int id;
+	enum NodeType type;
+	unsigned int use_count;
+	int visited;
+	struct GraphEdge *connections[MAX_CONNECTIONS];
+	int num_connections;
+};
+
+static struct GraphNode *all_nodes[MAX_NODES];
+static struct GraphEdge *all_edges[MAX_EDGES];
+static int num_nodes;
+static int num_edges;
+
+/*
+ * Graph edge, which connects Graph nodes
+ * and has a weight property.
+ */
+struct GraphEdge {
+	struct igt_list_head elem;
+	unsigned int weight;
+	struct GraphNode *node;
+};
+
+static struct GraphNode *create_graph_node(enum NodeType type, int id)
+{
+	struct GraphNode *node = 0;
+
+	if (num_nodes >= MAX_NODES) {
+		igt_info("Too much nodes %d", num_nodes);
+		return NULL;
+	}
+
+	node = malloc(sizeof(struct GraphNode));
+	node->type = type;
+	node->id = id;
+	node->use_count = 0;
+	node->visited = 0;
+	memset(node->connections, 0,
+			MAX_CONNECTIONS * sizeof(struct GraphEdge *));
+	node->num_connections = 0;
+
+	all_nodes[num_nodes] = node;
+	num_nodes++;
+
+	return node;
+}
+
+static struct GraphEdge *create_graph_edge(int weight, struct GraphNode *node)
+{
+	struct GraphEdge *edge = 0;
+
+	if (num_edges >= MAX_EDGES) {
+		igt_info("Too much edges %d", num_edges);
+		return NULL;
+	}
+
+	edge = malloc(sizeof(struct GraphEdge));
+
+	edge->elem.prev = &edge->elem;
+	edge->elem.next = &edge->elem;
+	edge->node = node;
+	edge->weight = weight;
+
+	all_edges[num_edges] = edge;
+	num_edges++;
+
+	return edge;
+}
+
+static void connect_nodes(struct GraphNode *node1, struct GraphNode *node2, int weight)
+{
+	struct GraphEdge *edge1;
+	struct GraphEdge *edge2;
+
+	if (node1->num_connections >= MAX_CONNECTIONS) {
+		igt_info("Node %d has too much connections\n", node1->id);
+		return;
+	}
+
+	if (node2->num_connections >= MAX_CONNECTIONS) {
+		igt_info("Node %d has too much connections\n", node2->id);
+		return;
+	}
+
+	edge1 = create_graph_edge(weight, node1);
+	edge2 = create_graph_edge(weight, node2);
+
+	node1->connections[node1->num_connections] = edge2;
+	node1->num_connections++;
+	node2->connections[node2->num_connections] = edge1;
+	node2->num_connections++;
+}
+
+static void reset_node(struct GraphNode *node)
+{
+	node->use_count = 0;
+	node->visited = 0;
+	memset(node->connections, 0,
+		MAX_CONNECTIONS * sizeof(struct GraphEdge *));
+	node->num_connections = 0;
+}
+
+static void destroy_node(struct GraphNode *node)
+{
+	free(node);
+}
+
+static void destroy_edge(struct GraphEdge *edge)
+{
+	free(edge);
+}
+
+static void destroy_all_edges(void)
+{
+	int i;
+
+	for (i = 0; i < num_edges; i++) {
+		destroy_edge(all_edges[i]);
+	}
+	num_edges = 0;
+}
+
+static void destroy_all_nodes(void)
+{
+	int i;
+
+	for (i = 0; i < num_nodes; i++) {
+		destroy_node(all_nodes[i]);
+	}
+	num_nodes = 0;
+}
+
+static void reset_all_nodes(void)
+{
+	int i;
+
+	destroy_all_edges();
+
+	for (i = 0; i < num_nodes; i++) {
+		reset_node(all_nodes[i]);
+	}
+}
+
+/*
+ * Traverse and try to print graph in a
+ * somewhat graphical form.
+ */
+static void traverse_graph(struct GraphNode *start_node,
+			   int depth)
+{
+	int i, space;
+
+	if (!depth)
+		igt_info("Graph: \n");
+
+	for (space = 0; space < depth * 4; space++)
+		igt_info(" ");
+
+	start_node->visited++;
+	igt_info("Type %s id %d\n", node_type_to_str[start_node->type],
+		 start_node->id);
+	for (i = 0; i < start_node->num_connections; i++) {
+		if (!start_node->connections[i]->node->visited) {
+			for (space = 0; space < (depth + 1) * 4; space++)
+				igt_info(" ");
+			igt_info("(%d)-> \n", start_node->connections[i]->weight);
+			traverse_graph(start_node->connections[i]->node, depth+2);
+			start_node->connections[i]->node->visited--;
+		}
+	}
+}
+
+/*
+ * This function recursively searches for a free DBuf slice
+ * for correspondent pipe, based on different constraints, like
+ * weight, usage count. This algorithm is "greedy" which means
+ * that it accounts for local optimum only, which means that
+ * total comparison has to be done in the end.
+ */
+static struct GraphNode *find_slice_for_pipe(struct GraphNode *start_node,
+					     int acc_weight, int max_use_count,
+					     unsigned int *total_weight,
+					     int depth,
+					     int skip)
+{
+	int i;
+	unsigned int min_weight = ~0, min_use_count = ~0;
+	struct GraphEdge *min_edge = 0;
+	struct GraphNode *node = NULL;
+	IGT_LIST_HEAD(slice_list);
+
+	start_node->visited++;
+
+	for (i = 0; i < start_node->num_connections; i++) {
+		struct GraphEdge *cur_edge = start_node->connections[i];
+		igt_list_add_tail(&cur_edge->elem, &slice_list);
+	}
+
+	if (igt_list_empty(&slice_list))
+		return NULL;
+
+	/*
+	 * Iterate through neighbouring slices, checking
+	 * if it's use count allows usage and skip if needed,
+	 * skips are needed when we use multiple slices for
+	 * same pipe to prevent algorithm from returning the
+	 * same DBuf.
+	 */
+	igt_list_for_each_entry(min_edge, &slice_list, elem) {
+		if (min_edge->node->type == DBUF_SLICE) {
+			if (min_edge->node->use_count < max_use_count) {
+				if (!skip) {
+					min_edge->node->use_count++;
+					*total_weight = acc_weight + min_edge->weight;
+					if (depth == 0)
+						start_node->visited = 0;
+					return min_edge->node;
+				}
+			}
+			if (skip)
+				skip--;
+		}
+	}
+
+	/*
+	 * If couldn't find suitable DBuf node from our
+	 * neighbours, have to continue further, checking
+	 * visited flag, to prevent loops.
+	 */
+	igt_list_for_each_entry(min_edge, &slice_list, elem) {
+		if (!min_edge->node->visited) {
+			node = find_slice_for_pipe(min_edge->node,
+						   acc_weight + min_edge->weight,
+						   max_use_count, total_weight,
+						   depth + 1, skip);
+			min_edge->node->visited--;
+			if (node) {
+				if (depth == 0)
+					start_node->visited = 0;
+				return node;
+			}
+		}
+	}
+	if (depth == 0)
+		start_node->visited = 0;
+	return NULL;
+}
+
+static int hweight32(int mask)
+{
+	int i;
+	int count = 0;
+
+	for (i = 0; i < 32; i++)
+		if ((1<<i) & mask)
+			count += 1;
+	return count;
+}
+
+#define I915_MAX_PIPES 4
+#define I915_MAX_SLICES_PER_PIPE 4
+#define I915_MAX_SLICES (I915_MAX_PIPES * I915_MAX_SLICES_PER_PIPE)
+
+const char *pipe_names[] = { "PIPE_A", "PIPE_B", "PIPE_C", "PIPE_D" };
+const char *slice_names[] = { "DBUF_S1", "DBUF_S2", "DBUF_S3", "DBUF_S4" };
+
+static int factorial(int n)
+{
+	if (n <= 1)
+		return 1;
+	return n * factorial(n - 1);
+}
+
+static void do_swap(struct GraphNode **pipe_nodes, int m, int n)
+{
+	*((unsigned long *)pipe_nodes + m) ^= *((unsigned long *)pipe_nodes + n);
+	*((unsigned long *)pipe_nodes + n) ^= *((unsigned long *)pipe_nodes + m);
+	*((unsigned long *)pipe_nodes + m) ^= *((unsigned long *)pipe_nodes + n);
+}
+
+struct PipeNodesCombination {
+	unsigned int total_weight;
+	struct GraphNode *pipe_nodes[I915_MAX_PIPES];
+	struct GraphNode *slices[I915_MAX_SLICES];
+};
+
+struct IterateContext {
+	struct PipeNodesCombination min_comb;
+	int max_use_count;
+	int num_pipes;
+	int num_slices;
+	int slices_per_pipe;
+	int max_combinations;
+};
+
+struct PipeDBuf {
+	struct GraphNode *pipe;
+	struct GraphNode *dbuf[I915_MAX_SLICES_PER_PIPE];
+};
+
+static void compare_weight(struct IterateContext *ctx,
+			   struct PipeNodesCombination *comb)
+{
+	unsigned int weight;
+	int j = 0;
+	int pipe = 0;
+	int skip = 0;
+	int slice_num = 0;
+
+	comb->total_weight = 0;
+	/*
+	 * Get a free DBuf slice for each pipe, then
+	 * calculate total weight, which will be
+	 * then compared to minimal weight to find
+	 * combination with total minimal weight.
+	 */
+	while (pipe < I915_MAX_PIPES) {
+		if (comb->pipe_nodes[pipe]) {
+			comb->slices[j] =
+			    find_slice_for_pipe(comb->pipe_nodes[pipe],
+						0, ctx->max_use_count,
+						&weight, 0, skip);
+			if (comb->slices[j]) {
+				if (slice_num < ctx->slices_per_pipe)
+					skip++;
+				comb->total_weight += weight;
+			} else {
+				igt_info("Could not find slice for pipe %d!\n",
+					 comb->pipe_nodes[pipe]->id);
+			}
+			slice_num++;
+
+			if (slice_num >= ctx->slices_per_pipe) {
+				slice_num = 0;
+				pipe++;
+				skip = 0;
+			}
+			j++;
+		} else {
+			pipe++;
+			j += ctx->slices_per_pipe;
+			skip = 0;
+		}
+	}
+
+	for (j = 0; j < I915_MAX_SLICES; j++) {
+		if (comb->slices[j])
+			comb->slices[j]->use_count = 0;
+	}
+
+	if (ctx->min_comb.total_weight > comb->total_weight) {
+		memcpy(&ctx->min_comb, comb,
+		       sizeof(struct PipeNodesCombination));
+	}
+}
+
+/*
+ * Generate all possible combinations for elements in
+ * pipe array(total is calculated as n!).
+ */
+static void iterate_all_combinations(struct IterateContext *ctx,
+				     struct GraphNode **pipe_nodes,
+				     int start, int step,
+				     void (*func)(struct IterateContext *ctx,
+				     struct PipeNodesCombination *comb))
+{
+	int i, j;
+	struct GraphNode *nodes[I915_MAX_PIPES];
+	struct PipeNodesCombination comb;
+
+	memcpy(comb.pipe_nodes, pipe_nodes,
+	       I915_MAX_PIPES * sizeof(struct GraphNode *));
+	memset(comb.slices, 0,
+	       I915_MAX_SLICES * sizeof(struct GraphNode *));
+
+	if (func)
+		(*func)(ctx, &comb);
+
+	if ((step == 0) || (ctx->num_pipes == 1))
+		return;
+
+	for (j = step; j > 0; j--) {
+		for (i = start; i < I915_MAX_PIPES - j; i++) {
+			if (!pipe_nodes[i] || !pipe_nodes[i + j])
+				continue;
+			memcpy(nodes, pipe_nodes,
+			       I915_MAX_PIPES * sizeof(struct GraphNode *));
+			do_swap(nodes, i, i + j);
+			iterate_all_combinations(ctx, nodes, i + 1,
+						 step - 1, func);
+		}
+	}
+}
+
+/*
+ * This function calculates and prints optimal
+ * weight-based DBuf assignment for active pipes.
+ */
+static void
+print_dbuf_mask_for_pipes(int active_pipes,
+			  struct GraphNode **pipe_nodes,
+			  int num_slices)
+{
+	int i;
+	int num_pipes = hweight32(active_pipes);
+	int max_use_count = num_slices < num_pipes ? 2 : 1;
+	int pipe = 0;
+	int slices_per_pipe = max(num_slices / num_pipes, 1);
+	struct IterateContext ctx;
+	struct PipeDBuf pipe_dbuf[I915_MAX_PIPES];
+
+	memcpy(ctx.min_comb.pipe_nodes, pipe_nodes,
+	       sizeof(struct GraphNode *) * I915_MAX_PIPES);
+	memset(ctx.min_comb.slices, 0,
+	       I915_MAX_SLICES * sizeof(struct GraphNode *));
+	ctx.min_comb.total_weight = ~0;
+	ctx.max_use_count = max_use_count;
+	ctx.num_pipes = num_pipes;
+	ctx.num_slices = num_slices;
+	ctx.slices_per_pipe = slices_per_pipe;
+	ctx.max_combinations = factorial(num_pipes);
+
+	iterate_all_combinations(&ctx, pipe_nodes,
+				 0, I915_MAX_PIPES - 1, compare_weight);
+
+	igt_info("Combination with least weight %d(total combinations %d):\n",
+		 ctx.min_comb.total_weight, ctx.max_combinations);
+
+	memset(pipe_dbuf, 0, sizeof(struct PipeDBuf) * I915_MAX_PIPES);
+
+	for (i = 0; i < I915_MAX_PIPES; i++) {
+		if (ctx.min_comb.pipe_nodes[i]) {
+			int pipe_index = ctx.min_comb.pipe_nodes[i]->id;
+
+			pipe_dbuf[pipe_index].pipe = ctx.min_comb.pipe_nodes[i];
+			memcpy(&pipe_dbuf[pipe_index].dbuf,
+			       &ctx.min_comb.slices[i * slices_per_pipe],
+			       sizeof(struct GraphNode *) * slices_per_pipe);
+		}
+	}
+
+	igt_info("{ ");
+	pipe = 0;
+	for (i = 0; i < I915_MAX_PIPES; i++) {
+		if (pipe_dbuf[i].pipe) {
+			igt_info("BIT(%s)", pipe_names[pipe_dbuf[i].pipe->id]);
+			if (pipe < (num_pipes - 1))
+				igt_info(" | ");
+			pipe++;
+		}
+	}
+	igt_info(", { ");
+	for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
+		if (pipe_dbuf[pipe].pipe) {
+			for (i = 0; i < slices_per_pipe; i++) {
+				int slice_index_converted =
+						pipe_dbuf[pipe].dbuf[i]->id;
+
+				if (i < (slices_per_pipe - 1)) {
+					igt_info("DBUF_S%d_BIT | ",
+						 slice_index_converted + 1);
+				} else {
+					igt_info("DBUF_S%d_BIT",
+						 slice_index_converted + 1);
+				}
+			}
+		} else {
+			igt_info("0");
+		}
+		if (pipe < (I915_MAX_PIPES - 1))
+			igt_info(", ");
+		else
+			break;
+	}
+	igt_info(" } },\n");
+}
+
+static void print_table(struct GraphNode **pipes, int num_pipes,
+			struct GraphNode **slices, int num_slices,
+			int slices_per_pipe)
+{
+	unsigned int i, j;
+	int num_combinations = 1 << num_pipes;
+
+	if (num_pipes > I915_MAX_PIPES) {
+		igt_info("Too many pipes %d\n", num_pipes);
+		return;
+	}
+
+	if (num_slices > I915_MAX_SLICES) {
+		igt_info("Too many slices %d\n", num_slices);
+		return;
+	}
+
+	for (i = 1; i < num_combinations; i++) {
+		struct GraphNode *tmp[I915_MAX_PIPES];
+
+		memcpy(tmp, pipes, I915_MAX_PIPES * sizeof(struct GraphNode *));
+
+		for (j = 0; j < I915_MAX_SLICES; j++) {
+			if (slices[j])
+				slices[j]->use_count = 0;
+		}
+
+		for (j = 0; j < I915_MAX_PIPES; j++) {
+			if (!(i & (1 << j))) {
+				tmp[j] = 0;
+			}
+		}
+
+		print_dbuf_mask_for_pipes(i, tmp, slices_per_pipe);
+	}
+}
+
+enum opt {
+	OPT_UNKNOWN = '?',
+	OPT_END = -1,
+	OPT_GEN,
+	OPT_USAGE,
+	OPT_GRAPH,
+	OPT_SLICES_PER_PIPE
+};
+
+static void usage(const char *toolname)
+{
+	fprintf(stderr, "usage: %s", toolname);
+	fprintf(stderr, " [--gen=<GEN>]"
+			" [--slices_per_pipe=<number>]"
+			" [--graph=\"PIPE_A-DBUF_S1-PIPE_B-...\"]"
+			" [--help]\n");
+}
+
+#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
+
+static int pipe_str_to_num(const char *str)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pipe_names); i++) {
+		if (!strcmp(str, pipe_names[i])) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+static int dbuf_str_to_num(const char *str)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(slice_names); i++) {
+		if (!strcmp(str, slice_names[i])) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+#define MAX_GRAPH_STR 80
+
+static void parse_graph_str(const char *graph_str, struct GraphNode **pipes,
+			    struct GraphNode **slices, int *num_slices,
+			    int *num_pipes)
+{
+	char* token = strtok(graph_str, "-");
+	struct GraphNode *cur_node = NULL, *last_node = NULL;
+	int n_pipes = 0, n_slices = 0;
+
+	while (token != NULL) {
+		int index;
+
+		index = pipe_str_to_num(token);
+
+		last_node = cur_node;
+		if (index >= 0) {
+			cur_node = pipes[index];
+			n_pipes++;
+		} else {
+			index = dbuf_str_to_num(token);
+			if (index >= 0) {
+				cur_node = slices[index];
+				n_slices++;
+			}
+		}
+		if (last_node && cur_node)
+			connect_nodes(last_node, cur_node, 1);
+
+		token = strtok(NULL, "-");
+	}
+	*num_slices = n_slices;
+	*num_pipes = n_pipes;
+}
+
+int main(int argc, char **argv)
+{
+	struct GraphNode *pipes[I915_MAX_PIPES];
+	struct GraphNode *slices[I915_MAX_SLICES];
+	struct GraphNode *pipeA, *pipeB, *pipeC, *pipeD;
+	struct GraphNode *slice1, *slice2, *slice3, *slice4;
+	int gen = 12, index;
+	enum opt opt;
+	char *endp;
+	char graph_str[MAX_GRAPH_STR];
+	int slices_per_pipe = I915_MAX_SLICES_PER_PIPE;
+	const char *toolname = argv[0];
+	static struct option options[] = {
+		{ "gen",		required_argument,	NULL,	OPT_GEN },
+		{ "graph",		required_argument,	NULL,	OPT_GRAPH },
+		{ "slices_per_pipe",	required_argument,	NULL,	OPT_SLICES_PER_PIPE },
+		{ "help",		no_argument,		NULL,	OPT_USAGE },
+		{ 0 }
+	};
+
+	num_edges = 0;
+	num_nodes = 0;
+
+	for (opt = 0; opt != OPT_END; ) {
+		opt = getopt_long(argc, argv, "", options, &index);
+
+		switch (opt) {
+		case OPT_GEN:
+			gen = strtoul(optarg, &endp, 0);
+			break;
+		case OPT_SLICES_PER_PIPE:
+			slices_per_pipe = min(strtoul(optarg, &endp, 0),
+					      I915_MAX_SLICES_PER_PIPE);
+			break;
+		case OPT_GRAPH:
+			strncpy(graph_str, optarg, MAX_GRAPH_STR);
+			graph_str[MAX_GRAPH_STR - 1] = 0;
+			gen = 0;
+		case OPT_END:
+			break;
+		case OPT_USAGE: /* fall-through */
+		case OPT_UNKNOWN:
+			usage(toolname);
+			return EXIT_FAILURE;
+		}
+	}
+	pipeA = create_graph_node(PIPE, 0);
+	pipeB = create_graph_node(PIPE, 1);
+	pipeC = create_graph_node(PIPE, 2);
+	pipeD = create_graph_node(PIPE, 3);
+	slice1 = create_graph_node(DBUF_SLICE, 0);
+	slice2 = create_graph_node(DBUF_SLICE, 1);
+	slice3 = create_graph_node(DBUF_SLICE, 2);
+	slice4 = create_graph_node(DBUF_SLICE, 3);
+
+	memset(pipes, 0, I915_MAX_PIPES * sizeof(struct GraphNode *));
+	memset(slices, 0, I915_MAX_SLICES * sizeof(struct GraphNode *));
+
+	if (!gen) {
+		int num_slices = 0, num_pipes = 0;
+		/*
+		 * Prepare to generate assignments for ICL, which
+		 * has 3 pipes and 2 DBuf slices.
+		 */
+		slices[0] = slice1;
+		slices[1] = slice2;
+		slices[2] = slice3;
+		slices[3] = slice4;
+		pipes[0] = pipeA;
+		pipes[1] = pipeB;
+		pipes[2] = pipeC;
+		pipes[3] = pipeD;
+
+		parse_graph_str(graph_str, pipes, slices, &num_slices,
+				&num_pipes);
+
+		traverse_graph(pipes[0], 0);
+
+		print_table(pipes, num_pipes, slices, num_slices, slices_per_pipe);
+
+	} else if (gen == 11) {
+
+		/*
+		 * Prepare to generate assignments for ICL, which
+		 * has 3 pipes and 2 DBuf slices.
+		 */
+		slices[0] = slice1;
+		slices[1] = slice2;
+		pipes[0] = pipeA;
+		pipes[1] = pipeB;
+		pipes[2] = pipeC;
+
+		/*
+		 * BSpec 12716. Generate DBuf Slices table for ICL,
+		 * Graph(each edge assumed to have weight 1):
+		 * PipeA - DBUF_S1 - PipeB - PipeC - DBUF_S2
+		 */
+		connect_nodes(pipeA, slice1, 1);
+		connect_nodes(slice1, pipeB, 1);
+		connect_nodes(pipeB, pipeC, 1);
+		connect_nodes(pipeC, slice2, 1);
+
+		traverse_graph(pipeA, 0);
+
+		print_table(pipes, 3, slices, 2, 2);
+
+	} else if (gen == 12) {
+
+		/*
+		 * Prepare to generate assignments for TGL, which
+		 * has 4 pipes and 2 DBuf slices.
+		 */
+		slices[0] = slice1;
+		slices[1] = slice2;
+		pipes[0] = pipeA;
+		pipes[1] = pipeB;
+		pipes[2] = pipeC;
+		pipes[3] = pipeD;
+
+		/*
+		 * BSpec 49255. Generate DBuf Slices table for TGL.
+		 * Graph(each edge assumed to have weight 1):
+		 * PipeD - DBUF_S2 - PipeC - PipeA - DBUF_S1 - PipeB
+		 */
+		connect_nodes(pipeD, slice2, 1);
+		connect_nodes(slice2, pipeC, 1);
+		connect_nodes(pipeC, pipeA, 1);
+		connect_nodes(pipeA, slice1, 1);
+		connect_nodes(slice1, pipeB, 1);
+
+		traverse_graph(pipeA, 0);
+
+		print_table(pipes, 4, slices, 2, 2);
+	}
+
+	reset_all_nodes();
+
+	/*
+	 * Further platforms can generate table same way.
+	 */
+
+	destroy_all_nodes();
+
+	return  0;
+}
+
diff --git a/tools/meson.build b/tools/meson.build
index eecb122b..2b8df4b4 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -35,6 +35,7 @@ tools_progs = [
 	'intel_watermark',
 	'intel_gem_info',
 	'intel_gvtg_test',
+	'intel_dbuf_map',
 	'dpcd_reg',
 ]
 tool_deps = igt_deps
-- 
2.17.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for tools: Add an intel_dbuf_,map tool (rev3)
  2019-12-04 15:13 [igt-dev] [PATCH i-g-t v3] tools: Add an intel_dbuf_,map tool Stanislav Lisovskiy
@ 2019-12-04 16:27 ` Patchwork
  0 siblings, 0 replies; 2+ messages in thread
From: Patchwork @ 2019-12-04 16:27 UTC (permalink / raw)
  To: Stanislav Lisovskiy; +Cc: igt-dev

== Series Details ==

Series: tools: Add an intel_dbuf_,map tool (rev3)
URL   : https://patchwork.freedesktop.org/series/70294/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_7482 -> IGTPW_3810
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/index.html

Known issues
------------

  Here are the changes found in IGTPW_3810 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@i915_selftest@live_blt:
    - fi-ivb-3770:        [PASS][1] -> [DMESG-FAIL][2] ([i915#683])
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-ivb-3770/igt@i915_selftest@live_blt.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-ivb-3770/igt@i915_selftest@live_blt.html

  * igt@kms_frontbuffer_tracking@basic:
    - fi-icl-u3:          [PASS][3] -> [FAIL][4] ([i915#49])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-icl-u3/igt@kms_frontbuffer_tracking@basic.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-icl-u3/igt@kms_frontbuffer_tracking@basic.html

  
#### Possible fixes ####

  * igt@gem_exec_gttfill@basic:
    - {fi-tgl-guc}:       [INCOMPLETE][5] ([fdo#111593]) -> [PASS][6]
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-tgl-guc/igt@gem_exec_gttfill@basic.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-tgl-guc/igt@gem_exec_gttfill@basic.html

  * igt@i915_pm_rpm@module-reload:
    - fi-skl-lmem:        [DMESG-WARN][7] ([i915#592]) -> [PASS][8]
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-skl-lmem/igt@i915_pm_rpm@module-reload.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-skl-lmem/igt@i915_pm_rpm@module-reload.html

  * igt@kms_chamelium@dp-crc-fast:
    - fi-icl-u2:          [DMESG-WARN][9] ([i915#109]) -> [PASS][10]
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-icl-u2/igt@kms_chamelium@dp-crc-fast.html
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-icl-u2/igt@kms_chamelium@dp-crc-fast.html

  * igt@kms_frontbuffer_tracking@basic:
    - fi-icl-guc:         [FAIL][11] ([i915#49]) -> [PASS][12]
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-icl-guc/igt@kms_frontbuffer_tracking@basic.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-icl-guc/igt@kms_frontbuffer_tracking@basic.html

  
#### Warnings ####

  * igt@gem_exec_suspend@basic-s4-devices:
    - fi-kbl-x1275:       [DMESG-WARN][13] ([fdo#107139] / [i915#62] / [i915#92]) -> [DMESG-WARN][14] ([fdo#107139] / [i915#62] / [i915#92] / [i915#95])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-kbl-x1275/igt@gem_exec_suspend@basic-s4-devices.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-kbl-x1275/igt@gem_exec_suspend@basic-s4-devices.html

  * igt@kms_chamelium@hdmi-hpd-fast:
    - fi-kbl-7500u:       [FAIL][15] ([fdo#111407]) -> [FAIL][16] ([fdo#111096] / [i915#323])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-kbl-7500u/igt@kms_chamelium@hdmi-hpd-fast.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-kbl-7500u/igt@kms_chamelium@hdmi-hpd-fast.html

  * igt@kms_pipe_crc_basic@hang-read-crc-pipe-a:
    - fi-kbl-x1275:       [DMESG-WARN][17] ([i915#62] / [i915#92]) -> [DMESG-WARN][18] ([i915#62] / [i915#92] / [i915#95]) +2 similar issues
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-kbl-x1275/igt@kms_pipe_crc_basic@hang-read-crc-pipe-a.html
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-kbl-x1275/igt@kms_pipe_crc_basic@hang-read-crc-pipe-a.html

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
    - fi-kbl-x1275:       [DMESG-WARN][19] ([i915#62] / [i915#92] / [i915#95]) -> [DMESG-WARN][20] ([i915#62] / [i915#92]) +7 similar issues
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_7482/fi-kbl-x1275/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/fi-kbl-x1275/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#107139]: https://bugs.freedesktop.org/show_bug.cgi?id=107139
  [fdo#111096]: https://bugs.freedesktop.org/show_bug.cgi?id=111096
  [fdo#111407]: https://bugs.freedesktop.org/show_bug.cgi?id=111407
  [fdo#111593]: https://bugs.freedesktop.org/show_bug.cgi?id=111593
  [i915#109]: https://gitlab.freedesktop.org/drm/intel/issues/109
  [i915#323]: https://gitlab.freedesktop.org/drm/intel/issues/323
  [i915#49]: https://gitlab.freedesktop.org/drm/intel/issues/49
  [i915#591]: https://gitlab.freedesktop.org/drm/intel/issues/591
  [i915#592]: https://gitlab.freedesktop.org/drm/intel/issues/592
  [i915#62]: https://gitlab.freedesktop.org/drm/intel/issues/62
  [i915#683]: https://gitlab.freedesktop.org/drm/intel/issues/683
  [i915#710]: https://gitlab.freedesktop.org/drm/intel/issues/710
  [i915#92]: https://gitlab.freedesktop.org/drm/intel/issues/92
  [i915#95]: https://gitlab.freedesktop.org/drm/intel/issues/95


Participating hosts (53 -> 46)
------------------------------

  Additional (1): fi-kbl-soraka 
  Missing    (8): fi-icl-1065g7 fi-ilk-m540 fi-hsw-4200u fi-byt-squawks fi-bsw-cyan fi-ctg-p8600 fi-byt-clapper fi-bdw-samus 


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_5326 -> IGTPW_3810

  CI-20190529: 20190529
  CI_DRM_7482: d26326880831f6220ffd322f763a04df2f2a3b1f @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_3810: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/index.html
  IGT_5326: 694804c6fcd91452f614710818a250b1da696398 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_3810/index.html
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-12-04 16:27 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-04 15:13 [igt-dev] [PATCH i-g-t v3] tools: Add an intel_dbuf_,map tool Stanislav Lisovskiy
2019-12-04 16:27 ` [igt-dev] ✓ Fi.CI.BAT: success for tools: Add an intel_dbuf_,map tool (rev3) Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.