cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dw-edma-v0-debugfs.c (8109B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
      4 * Synopsys DesignWare eDMA v0 core
      5 *
      6 * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
      7 */
      8
      9#include <linux/debugfs.h>
     10#include <linux/bitfield.h>
     11
     12#include "dw-edma-v0-debugfs.h"
     13#include "dw-edma-v0-regs.h"
     14#include "dw-edma-core.h"
     15
     16#define REGS_ADDR(name) \
     17	((void __force *)&regs->name)
     18#define REGISTER(name) \
     19	{ #name, REGS_ADDR(name) }
     20
     21#define WR_REGISTER(name) \
     22	{ #name, REGS_ADDR(wr_##name) }
     23#define RD_REGISTER(name) \
     24	{ #name, REGS_ADDR(rd_##name) }
     25
     26#define WR_REGISTER_LEGACY(name) \
     27	{ #name, REGS_ADDR(type.legacy.wr_##name) }
     28#define RD_REGISTER_LEGACY(name) \
     29	{ #name, REGS_ADDR(type.legacy.rd_##name) }
     30
     31#define WR_REGISTER_UNROLL(name) \
     32	{ #name, REGS_ADDR(type.unroll.wr_##name) }
     33#define RD_REGISTER_UNROLL(name) \
     34	{ #name, REGS_ADDR(type.unroll.rd_##name) }
     35
     36#define WRITE_STR				"write"
     37#define READ_STR				"read"
     38#define CHANNEL_STR				"channel"
     39#define REGISTERS_STR				"registers"
     40
     41static struct dw_edma				*dw;
     42static struct dw_edma_v0_regs			__iomem *regs;
     43
     44static struct {
     45	void					__iomem *start;
     46	void					__iomem *end;
     47} lim[2][EDMA_V0_MAX_NR_CH];
     48
     49struct debugfs_entries {
     50	const char				*name;
     51	dma_addr_t				*reg;
     52};
     53
     54static int dw_edma_debugfs_u32_get(void *data, u64 *val)
     55{
     56	void __iomem *reg = (void __force __iomem *)data;
     57	if (dw->mf == EDMA_MF_EDMA_LEGACY &&
     58	    reg >= (void __iomem *)&regs->type.legacy.ch) {
     59		void __iomem *ptr = &regs->type.legacy.ch;
     60		u32 viewport_sel = 0;
     61		unsigned long flags;
     62		u16 ch;
     63
     64		for (ch = 0; ch < dw->wr_ch_cnt; ch++)
     65			if (lim[0][ch].start >= reg && reg < lim[0][ch].end) {
     66				ptr += (reg - lim[0][ch].start);
     67				goto legacy_sel_wr;
     68			}
     69
     70		for (ch = 0; ch < dw->rd_ch_cnt; ch++)
     71			if (lim[1][ch].start >= reg && reg < lim[1][ch].end) {
     72				ptr += (reg - lim[1][ch].start);
     73				goto legacy_sel_rd;
     74			}
     75
     76		return 0;
     77legacy_sel_rd:
     78		viewport_sel = BIT(31);
     79legacy_sel_wr:
     80		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
     81
     82		raw_spin_lock_irqsave(&dw->lock, flags);
     83
     84		writel(viewport_sel, &regs->type.legacy.viewport_sel);
     85		*val = readl(ptr);
     86
     87		raw_spin_unlock_irqrestore(&dw->lock, flags);
     88	} else {
     89		*val = readl(reg);
     90	}
     91
     92	return 0;
     93}
     94DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
     95
     96static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
     97				       int nr_entries, struct dentry *dir)
     98{
     99	int i;
    100
    101	for (i = 0; i < nr_entries; i++) {
    102		if (!debugfs_create_file_unsafe(entries[i].name, 0444, dir,
    103						entries[i].reg,	&fops_x32))
    104			break;
    105	}
    106}
    107
    108static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
    109				    struct dentry *dir)
    110{
    111	int nr_entries;
    112	const struct debugfs_entries debugfs_regs[] = {
    113		REGISTER(ch_control1),
    114		REGISTER(ch_control2),
    115		REGISTER(transfer_size),
    116		REGISTER(sar.lsb),
    117		REGISTER(sar.msb),
    118		REGISTER(dar.lsb),
    119		REGISTER(dar.msb),
    120		REGISTER(llp.lsb),
    121		REGISTER(llp.msb),
    122	};
    123
    124	nr_entries = ARRAY_SIZE(debugfs_regs);
    125	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
    126}
    127
    128static void dw_edma_debugfs_regs_wr(struct dentry *dir)
    129{
    130	const struct debugfs_entries debugfs_regs[] = {
    131		/* eDMA global registers */
    132		WR_REGISTER(engine_en),
    133		WR_REGISTER(doorbell),
    134		WR_REGISTER(ch_arb_weight.lsb),
    135		WR_REGISTER(ch_arb_weight.msb),
    136		/* eDMA interrupts registers */
    137		WR_REGISTER(int_status),
    138		WR_REGISTER(int_mask),
    139		WR_REGISTER(int_clear),
    140		WR_REGISTER(err_status),
    141		WR_REGISTER(done_imwr.lsb),
    142		WR_REGISTER(done_imwr.msb),
    143		WR_REGISTER(abort_imwr.lsb),
    144		WR_REGISTER(abort_imwr.msb),
    145		WR_REGISTER(ch01_imwr_data),
    146		WR_REGISTER(ch23_imwr_data),
    147		WR_REGISTER(ch45_imwr_data),
    148		WR_REGISTER(ch67_imwr_data),
    149		WR_REGISTER(linked_list_err_en),
    150	};
    151	const struct debugfs_entries debugfs_unroll_regs[] = {
    152		/* eDMA channel context grouping */
    153		WR_REGISTER_UNROLL(engine_chgroup),
    154		WR_REGISTER_UNROLL(engine_hshake_cnt.lsb),
    155		WR_REGISTER_UNROLL(engine_hshake_cnt.msb),
    156		WR_REGISTER_UNROLL(ch0_pwr_en),
    157		WR_REGISTER_UNROLL(ch1_pwr_en),
    158		WR_REGISTER_UNROLL(ch2_pwr_en),
    159		WR_REGISTER_UNROLL(ch3_pwr_en),
    160		WR_REGISTER_UNROLL(ch4_pwr_en),
    161		WR_REGISTER_UNROLL(ch5_pwr_en),
    162		WR_REGISTER_UNROLL(ch6_pwr_en),
    163		WR_REGISTER_UNROLL(ch7_pwr_en),
    164	};
    165	struct dentry *regs_dir, *ch_dir;
    166	int nr_entries, i;
    167	char name[16];
    168
    169	regs_dir = debugfs_create_dir(WRITE_STR, dir);
    170	if (!regs_dir)
    171		return;
    172
    173	nr_entries = ARRAY_SIZE(debugfs_regs);
    174	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
    175
    176	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
    177		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
    178		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
    179					   regs_dir);
    180	}
    181
    182	for (i = 0; i < dw->wr_ch_cnt; i++) {
    183		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
    184
    185		ch_dir = debugfs_create_dir(name, regs_dir);
    186		if (!ch_dir)
    187			return;
    188
    189		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
    190
    191		lim[0][i].start = &regs->type.unroll.ch[i].wr;
    192		lim[0][i].end = &regs->type.unroll.ch[i].padding_1[0];
    193	}
    194}
    195
    196static void dw_edma_debugfs_regs_rd(struct dentry *dir)
    197{
    198	const struct debugfs_entries debugfs_regs[] = {
    199		/* eDMA global registers */
    200		RD_REGISTER(engine_en),
    201		RD_REGISTER(doorbell),
    202		RD_REGISTER(ch_arb_weight.lsb),
    203		RD_REGISTER(ch_arb_weight.msb),
    204		/* eDMA interrupts registers */
    205		RD_REGISTER(int_status),
    206		RD_REGISTER(int_mask),
    207		RD_REGISTER(int_clear),
    208		RD_REGISTER(err_status.lsb),
    209		RD_REGISTER(err_status.msb),
    210		RD_REGISTER(linked_list_err_en),
    211		RD_REGISTER(done_imwr.lsb),
    212		RD_REGISTER(done_imwr.msb),
    213		RD_REGISTER(abort_imwr.lsb),
    214		RD_REGISTER(abort_imwr.msb),
    215		RD_REGISTER(ch01_imwr_data),
    216		RD_REGISTER(ch23_imwr_data),
    217		RD_REGISTER(ch45_imwr_data),
    218		RD_REGISTER(ch67_imwr_data),
    219	};
    220	const struct debugfs_entries debugfs_unroll_regs[] = {
    221		/* eDMA channel context grouping */
    222		RD_REGISTER_UNROLL(engine_chgroup),
    223		RD_REGISTER_UNROLL(engine_hshake_cnt.lsb),
    224		RD_REGISTER_UNROLL(engine_hshake_cnt.msb),
    225		RD_REGISTER_UNROLL(ch0_pwr_en),
    226		RD_REGISTER_UNROLL(ch1_pwr_en),
    227		RD_REGISTER_UNROLL(ch2_pwr_en),
    228		RD_REGISTER_UNROLL(ch3_pwr_en),
    229		RD_REGISTER_UNROLL(ch4_pwr_en),
    230		RD_REGISTER_UNROLL(ch5_pwr_en),
    231		RD_REGISTER_UNROLL(ch6_pwr_en),
    232		RD_REGISTER_UNROLL(ch7_pwr_en),
    233	};
    234	struct dentry *regs_dir, *ch_dir;
    235	int nr_entries, i;
    236	char name[16];
    237
    238	regs_dir = debugfs_create_dir(READ_STR, dir);
    239	if (!regs_dir)
    240		return;
    241
    242	nr_entries = ARRAY_SIZE(debugfs_regs);
    243	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
    244
    245	if (dw->mf == EDMA_MF_HDMA_COMPAT) {
    246		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
    247		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
    248					   regs_dir);
    249	}
    250
    251	for (i = 0; i < dw->rd_ch_cnt; i++) {
    252		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
    253
    254		ch_dir = debugfs_create_dir(name, regs_dir);
    255		if (!ch_dir)
    256			return;
    257
    258		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
    259
    260		lim[1][i].start = &regs->type.unroll.ch[i].rd;
    261		lim[1][i].end = &regs->type.unroll.ch[i].padding_2[0];
    262	}
    263}
    264
    265static void dw_edma_debugfs_regs(void)
    266{
    267	const struct debugfs_entries debugfs_regs[] = {
    268		REGISTER(ctrl_data_arb_prior),
    269		REGISTER(ctrl),
    270	};
    271	struct dentry *regs_dir;
    272	int nr_entries;
    273
    274	regs_dir = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
    275	if (!regs_dir)
    276		return;
    277
    278	nr_entries = ARRAY_SIZE(debugfs_regs);
    279	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
    280
    281	dw_edma_debugfs_regs_wr(regs_dir);
    282	dw_edma_debugfs_regs_rd(regs_dir);
    283}
    284
    285void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
    286{
    287	dw = chip->dw;
    288	if (!dw)
    289		return;
    290
    291	regs = dw->rg_region.vaddr;
    292	if (!regs)
    293		return;
    294
    295	dw->debugfs = debugfs_create_dir(dw->name, NULL);
    296	if (!dw->debugfs)
    297		return;
    298
    299	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->mf);
    300	debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
    301	debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
    302
    303	dw_edma_debugfs_regs();
    304}
    305
    306void dw_edma_v0_debugfs_off(struct dw_edma_chip *chip)
    307{
    308	dw = chip->dw;
    309	if (!dw)
    310		return;
    311
    312	debugfs_remove_recursive(dw->debugfs);
    313	dw->debugfs = NULL;
    314}