Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd601b80 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: synx: Add a debugging framework for synx"

parents 5f7570bb 81eb341c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only

ccflags-$(CONFIG_SPECTRA_CAMERA) += -Idrivers/media/platform/msm/camera/cam_sync
obj-$(CONFIG_MSM_GLOBAL_SYNX) += synx.o synx_util.o
obj-$(CONFIG_MSM_GLOBAL_SYNX) += synx.o synx_util.o synx_debugfs.o
+3 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include "synx_api.h"
#include "synx_util.h"
#include "synx_debugfs.h"

struct synx_device *synx_dev;

@@ -1478,6 +1479,8 @@ static int __init synx_init(void)
	INIT_LIST_HEAD(&synx_dev->client_list);
	synx_dev->dma_context = dma_fence_context_alloc(1);

	synx_dev->debugfs_root = init_synx_debug_dir(synx_dev);

	synx_bind_ops_register(synx_dev);

	pr_info("synx device init success\n");
+192 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */

#include <linux/io.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/list.h>

#include "synx_api.h"
#include "synx_private.h"
#include "synx_util.h"
#include "synx_debugfs.h"

#define MAX_DBG_BUF_SIZE (36 * SYNX_MAX_OBJS)

struct dentry *my_direc;
const char delim[] = ",";
int columns = NAME_COLUMN | ID_COLUMN |
	BOUND_COLUMN | STATE_COLUMN | ERROR_CODES;

void populate_bound_rows(
	struct synx_table_row *row,
	char *cur,
	char *end)
{
	int j;
	int state = SYNX_STATE_INVALID;

	for (j = 0; j < row->num_bound_synxs;
		j++) {
		cur += scnprintf(cur, end - cur,
			"\n\tID: %d State: %s",
			row->bound_synxs[j].external_data->synx_obj,
			state);
	}
}
static ssize_t synx_table_read(struct file *file,
		char *buf,
		size_t count,
		loff_t *ppos)
{

	struct synx_device *dev = file->private_data;
	struct error_node *err_node, *err_node_tmp;
	struct synx_table_row *row;
	char *dbuf, *cur, *end;

	int i = 0;
	int state = SYNX_STATE_INVALID;
	ssize_t len = 0;

	dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL);
	if (!dbuf)
		return -ENOMEM;
	cur = dbuf;
	end = cur + MAX_DBG_BUF_SIZE;
	if (columns & NAME_COLUMN)
		cur += scnprintf(cur, end - cur, "|   Name   |");
	if (columns & ID_COLUMN)
		cur += scnprintf(cur, end - cur, "|    ID    |");
	if (columns & BOUND_COLUMN)
		cur += scnprintf(cur, end - cur, "|   Bound   |");
	if (columns & STATE_COLUMN)
		cur += scnprintf(cur, end - cur, "|  Status  |");
	cur += scnprintf(cur, end - cur, "\n");
	for (i = 0; i < SYNX_MAX_OBJS; i++) {
		row = &dev->synx_table[i];

		if (!row || !row->synx_obj)
			continue;

		spin_lock_bh(&dev->row_spinlocks[row->index]);
		if (columns & NAME_COLUMN)
			cur += scnprintf(cur, end - cur,
				"|%10s|", row->name);
		if (columns & ID_COLUMN)
			cur += scnprintf(cur, end - cur,
				"|%10d|", row->synx_obj);
		if (columns & BOUND_COLUMN)
			cur += scnprintf(cur, end - cur,
				"|%11d|", row->num_bound_synxs);
		if (columns & STATE_COLUMN) {
			state = synx_status_locked(row);
			cur += scnprintf(cur, end - cur,
				"|%10d|", state);
		}
		if ((columns & BOUND_COLUMN) &&
			(row->num_bound_synxs > 0)) {
			cur += scnprintf(
				cur, end - cur, "\nBound synx: ");
			populate_bound_rows(row,
				cur,
				end);
		}
		spin_unlock_bh(&dev->row_spinlocks[row->index]);
		cur += scnprintf(cur, end - cur, "\n");
	}
	if (columns & ERROR_CODES && !list_empty(
		&synx_dev->synx_debug_head)) {
		cur += scnprintf(
			cur, end - cur, "\nError(s): ");

		spin_lock_bh(&synx_dev->synx_node_list_lock);
		list_for_each_entry_safe(
			err_node, err_node_tmp,
			&synx_dev->synx_debug_head,
			node) {
			if (err_node->timestamp != NULL) {
				cur += scnprintf(cur, end - cur,
				"\n\tTime: %s - ID: %d - Code: %d",
				err_node->timestamp,
				err_node->synx_obj,
				err_node->error_code);
			}
			list_del(&err_node->node);
			kfree(err_node);
		}
		spin_unlock_bh(&synx_dev->synx_node_list_lock);
	}

	cur += scnprintf(cur, end - cur,
			"\n=================================================\n");

	len = simple_read_from_buffer(buf, count, ppos,
		dbuf, cur - dbuf);
	kfree(dbuf);
	return len;
}

static ssize_t synx_table_write(struct file *file,
		const char __user *buf,
		size_t count,
		loff_t *ppos)
{
	char *ptr;
	char *kbuffer = kzalloc(48, GFP_KERNEL);
	int stat = -1;

	if (!kbuffer)
		return -ENOMEM;
	stat = copy_from_user(kbuffer, buf, 48);
	if (stat != 0) {
		kfree(kbuffer);
		return -EFAULT;
	}
	while ((ptr = strsep(&kbuffer, delim)) != NULL) {
		ptr += '\0';
		if (strcmp(ptr, "bound\n") == 0)
			columns = columns ^ BOUND_COLUMN;
		else if (strcmp(ptr, "name\n") == 0)
			columns = columns ^ NAME_COLUMN;
		else if (strcmp(ptr, "synxid\n") == 0)
			columns = columns ^ ID_COLUMN;
		else if (strcmp(ptr, "status\n") == 0)
			columns = columns ^ STATE_COLUMN;
		else if (strcmp(ptr, "errors\n") == 0)
			columns = columns ^ ERROR_CODES;
	}
	kfree(kbuffer);
	return count;
}

static const struct file_operations synx_table_fops = {
	.owner = THIS_MODULE,
	.read = synx_table_read,
	.write = synx_table_write,
	.open = simple_open,
};

struct dentry *init_synx_debug_dir(struct synx_device *dev)
{
	struct dentry *dir = NULL;

	dir = debugfs_create_dir("synx_debug", NULL);

	if (!dir) {
		pr_debug("Failed to create debugfs for synx\n");
		return NULL;
	}
	if (!debugfs_create_file("synx_table",
		0644, dir, dev, &synx_table_fops)) {
		pr_debug("Failed to create debugfs file for synx\n");
		return NULL;
	}
	spin_lock_init(&dev->synx_node_list_lock);
	INIT_LIST_HEAD(&dev->synx_debug_head);
	return dir;
}
+17 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */

#include <linux/debugfs.h>
#include <linux/delay.h>

#include "synx_private.h"

struct dentry *init_synx_debug_dir(struct synx_device *dev);

#define NAME_COLUMN 0x0001
#define ID_COLUMN 0x0002
#define BOUND_COLUMN 0x0004
#define STATE_COLUMN  0x0008
#define ERROR_CODES  0x8000
+22 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/idr.h>
#include <linux/workqueue.h>

#define MAX_TIMESTAMP_SIZE          32
#define SYNX_OBJ_NAME_LEN           64
#define SYNX_MAX_OBJS               1024
#define SYNX_MAX_REF_COUNTS         2048
@@ -45,6 +46,21 @@ struct synx_bind_desc {
	struct synx_external_data *external_data;
};

/**
 * struct error_node - Single error node related to a table_row
 *
 * @timestamp       : Time that the error occurred
 * @error_code      : Code related to the error
 * @node            : List member used to append
 *                    this node to a linked list
 */
struct error_node {
	char timestamp[MAX_TIMESTAMP_SIZE];
	s32 error_code;
	s32 synx_obj;
	struct list_head node;
};

/**
 * struct synx_callback_info - Single node of information about a kernel
 * callback registered on a sync object
@@ -158,6 +174,9 @@ struct bind_operations {
 * dma_context    : dma context id
 * bind_vtbl      : Table with bind ops for supported external sync objects
 * client_list    : All the synx clients
 * debugfs_root   : Root directory for debugfs
 * synx_node_head : list head for synx nodes
 * synx_node_list_lock : Spinlock for synx nodes
 */
struct synx_device {
	struct cdev cdev;
@@ -173,6 +192,9 @@ struct synx_device {
	u64 dma_context;
	struct bind_operations bind_vtbl[SYNX_MAX_BIND_TYPES];
	struct list_head client_list;
	struct dentry *debugfs_root;
	struct list_head synx_debug_head;
	spinlock_t synx_node_list_lock;
};

/**
Loading