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

debugfs.c (7075B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3#include <linux/mtd/spi-nor.h>
      4#include <linux/spi/spi.h>
      5#include <linux/spi/spi-mem.h>
      6#include <linux/debugfs.h>
      7
      8#include "core.h"
      9
     10#define SPI_NOR_DEBUGFS_ROOT "spi-nor"
     11
     12#define SNOR_F_NAME(name) [ilog2(SNOR_F_##name)] = #name
     13static const char *const snor_f_names[] = {
     14	SNOR_F_NAME(HAS_SR_TB),
     15	SNOR_F_NAME(NO_OP_CHIP_ERASE),
     16	SNOR_F_NAME(BROKEN_RESET),
     17	SNOR_F_NAME(4B_OPCODES),
     18	SNOR_F_NAME(HAS_4BAIT),
     19	SNOR_F_NAME(HAS_LOCK),
     20	SNOR_F_NAME(HAS_16BIT_SR),
     21	SNOR_F_NAME(NO_READ_CR),
     22	SNOR_F_NAME(HAS_SR_TB_BIT6),
     23	SNOR_F_NAME(HAS_4BIT_BP),
     24	SNOR_F_NAME(HAS_SR_BP3_BIT6),
     25	SNOR_F_NAME(IO_MODE_EN_VOLATILE),
     26	SNOR_F_NAME(SOFT_RESET),
     27	SNOR_F_NAME(SWP_IS_VOLATILE),
     28};
     29#undef SNOR_F_NAME
     30
     31static const char *spi_nor_protocol_name(enum spi_nor_protocol proto)
     32{
     33	switch (proto) {
     34	case SNOR_PROTO_1_1_1:     return "1S-1S-1S";
     35	case SNOR_PROTO_1_1_2:     return "1S-1S-2S";
     36	case SNOR_PROTO_1_1_4:     return "1S-1S-4S";
     37	case SNOR_PROTO_1_1_8:     return "1S-1S-8S";
     38	case SNOR_PROTO_1_2_2:     return "1S-2S-2S";
     39	case SNOR_PROTO_1_4_4:     return "1S-4S-4S";
     40	case SNOR_PROTO_1_8_8:     return "1S-8S-8S";
     41	case SNOR_PROTO_2_2_2:     return "2S-2S-2S";
     42	case SNOR_PROTO_4_4_4:     return "4S-4S-4S";
     43	case SNOR_PROTO_8_8_8:     return "8S-8S-8S";
     44	case SNOR_PROTO_1_1_1_DTR: return "1D-1D-1D";
     45	case SNOR_PROTO_1_2_2_DTR: return "1D-2D-2D";
     46	case SNOR_PROTO_1_4_4_DTR: return "1D-4D-4D";
     47	case SNOR_PROTO_1_8_8_DTR: return "1D-8D-8D";
     48	case SNOR_PROTO_8_8_8_DTR: return "8D-8D-8D";
     49	}
     50
     51	return "<unknown>";
     52}
     53
     54static void spi_nor_print_flags(struct seq_file *s, unsigned long flags,
     55				const char *const *names, int names_len)
     56{
     57	bool sep = false;
     58	int i;
     59
     60	for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) {
     61		if (!(flags & BIT(i)))
     62			continue;
     63		if (sep)
     64			seq_puts(s, " | ");
     65		sep = true;
     66		if (i < names_len && names[i])
     67			seq_puts(s, names[i]);
     68		else
     69			seq_printf(s, "1<<%d", i);
     70	}
     71}
     72
     73static int spi_nor_params_show(struct seq_file *s, void *data)
     74{
     75	struct spi_nor *nor = s->private;
     76	struct spi_nor_flash_parameter *params = nor->params;
     77	struct spi_nor_erase_map *erase_map = &params->erase_map;
     78	struct spi_nor_erase_region *region;
     79	const struct flash_info *info = nor->info;
     80	char buf[16], *str;
     81	int i;
     82
     83	seq_printf(s, "name\t\t%s\n", info->name);
     84	seq_printf(s, "id\t\t%*ph\n", info->id_len, info->id);
     85	string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
     86	seq_printf(s, "size\t\t%s\n", buf);
     87	seq_printf(s, "write size\t%u\n", params->writesize);
     88	seq_printf(s, "page size\t%u\n", params->page_size);
     89	seq_printf(s, "address width\t%u\n", nor->addr_width);
     90
     91	seq_puts(s, "flags\t\t");
     92	spi_nor_print_flags(s, nor->flags, snor_f_names, sizeof(snor_f_names));
     93	seq_puts(s, "\n");
     94
     95	seq_puts(s, "\nopcodes\n");
     96	seq_printf(s, " read\t\t0x%02x\n", nor->read_opcode);
     97	seq_printf(s, "  dummy cycles\t%u\n", nor->read_dummy);
     98	seq_printf(s, " erase\t\t0x%02x\n", nor->erase_opcode);
     99	seq_printf(s, " program\t0x%02x\n", nor->program_opcode);
    100
    101	switch (nor->cmd_ext_type) {
    102	case SPI_NOR_EXT_NONE:
    103		str = "none";
    104		break;
    105	case SPI_NOR_EXT_REPEAT:
    106		str = "repeat";
    107		break;
    108	case SPI_NOR_EXT_INVERT:
    109		str = "invert";
    110		break;
    111	default:
    112		str = "<unknown>";
    113		break;
    114	}
    115	seq_printf(s, " 8D extension\t%s\n", str);
    116
    117	seq_puts(s, "\nprotocols\n");
    118	seq_printf(s, " read\t\t%s\n",
    119		   spi_nor_protocol_name(nor->read_proto));
    120	seq_printf(s, " write\t\t%s\n",
    121		   spi_nor_protocol_name(nor->write_proto));
    122	seq_printf(s, " register\t%s\n",
    123		   spi_nor_protocol_name(nor->reg_proto));
    124
    125	seq_puts(s, "\nerase commands\n");
    126	for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
    127		struct spi_nor_erase_type *et = &erase_map->erase_type[i];
    128
    129		if (et->size) {
    130			string_get_size(et->size, 1, STRING_UNITS_2, buf,
    131					sizeof(buf));
    132			seq_printf(s, " %02x (%s) [%d]\n", et->opcode, buf, i);
    133		}
    134	}
    135
    136	if (!(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
    137		string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
    138		seq_printf(s, " %02x (%s)\n", SPINOR_OP_CHIP_ERASE, buf);
    139	}
    140
    141	seq_puts(s, "\nsector map\n");
    142	seq_puts(s, " region (in hex)   | erase mask | flags\n");
    143	seq_puts(s, " ------------------+------------+----------\n");
    144	for (region = erase_map->regions;
    145	     region;
    146	     region = spi_nor_region_next(region)) {
    147		u64 start = region->offset & ~SNOR_ERASE_FLAGS_MASK;
    148		u64 flags = region->offset & SNOR_ERASE_FLAGS_MASK;
    149		u64 end = start + region->size - 1;
    150
    151		seq_printf(s, " %08llx-%08llx |     [%c%c%c%c] | %s\n",
    152			   start, end,
    153			   flags & BIT(0) ? '0' : ' ',
    154			   flags & BIT(1) ? '1' : ' ',
    155			   flags & BIT(2) ? '2' : ' ',
    156			   flags & BIT(3) ? '3' : ' ',
    157			   flags & SNOR_OVERLAID_REGION ? "overlaid" : "");
    158	}
    159
    160	return 0;
    161}
    162DEFINE_SHOW_ATTRIBUTE(spi_nor_params);
    163
    164static void spi_nor_print_read_cmd(struct seq_file *s, u32 cap,
    165				   struct spi_nor_read_command *cmd)
    166{
    167	seq_printf(s, " %s%s\n", spi_nor_protocol_name(cmd->proto),
    168		   cap == SNOR_HWCAPS_READ_FAST ? " (fast read)" : "");
    169	seq_printf(s, "  opcode\t0x%02x\n", cmd->opcode);
    170	seq_printf(s, "  mode cycles\t%u\n", cmd->num_mode_clocks);
    171	seq_printf(s, "  dummy cycles\t%u\n", cmd->num_wait_states);
    172}
    173
    174static void spi_nor_print_pp_cmd(struct seq_file *s,
    175				 struct spi_nor_pp_command *cmd)
    176{
    177	seq_printf(s, " %s\n", spi_nor_protocol_name(cmd->proto));
    178	seq_printf(s, "  opcode\t0x%02x\n", cmd->opcode);
    179}
    180
    181static int spi_nor_capabilities_show(struct seq_file *s, void *data)
    182{
    183	struct spi_nor *nor = s->private;
    184	struct spi_nor_flash_parameter *params = nor->params;
    185	u32 hwcaps = params->hwcaps.mask;
    186	int i, cmd;
    187
    188	seq_puts(s, "Supported read modes by the flash\n");
    189	for (i = 0; i < sizeof(hwcaps) * BITS_PER_BYTE; i++) {
    190		if (!(hwcaps & BIT(i)))
    191			continue;
    192
    193		cmd = spi_nor_hwcaps_read2cmd(BIT(i));
    194		if (cmd < 0)
    195			continue;
    196
    197		spi_nor_print_read_cmd(s, BIT(i), &params->reads[cmd]);
    198		hwcaps &= ~BIT(i);
    199	}
    200
    201	seq_puts(s, "\nSupported page program modes by the flash\n");
    202	for (i = 0; i < sizeof(hwcaps) * BITS_PER_BYTE; i++) {
    203		if (!(hwcaps & BIT(i)))
    204			continue;
    205
    206		cmd = spi_nor_hwcaps_pp2cmd(BIT(i));
    207		if (cmd < 0)
    208			continue;
    209
    210		spi_nor_print_pp_cmd(s, &params->page_programs[cmd]);
    211		hwcaps &= ~BIT(i);
    212	}
    213
    214	if (hwcaps)
    215		seq_printf(s, "\nunknown hwcaps 0x%x\n", hwcaps);
    216
    217	return 0;
    218}
    219DEFINE_SHOW_ATTRIBUTE(spi_nor_capabilities);
    220
    221static void spi_nor_debugfs_unregister(void *data)
    222{
    223	struct spi_nor *nor = data;
    224
    225	debugfs_remove(nor->debugfs_root);
    226	nor->debugfs_root = NULL;
    227}
    228
    229void spi_nor_debugfs_register(struct spi_nor *nor)
    230{
    231	struct dentry *rootdir, *d;
    232	int ret;
    233
    234	/* Create rootdir once. Will never be deleted again. */
    235	rootdir = debugfs_lookup(SPI_NOR_DEBUGFS_ROOT, NULL);
    236	if (!rootdir)
    237		rootdir = debugfs_create_dir(SPI_NOR_DEBUGFS_ROOT, NULL);
    238
    239	ret = devm_add_action(nor->dev, spi_nor_debugfs_unregister, nor);
    240	if (ret)
    241		return;
    242
    243	d = debugfs_create_dir(dev_name(nor->dev), rootdir);
    244	nor->debugfs_root = d;
    245
    246	debugfs_create_file("params", 0444, d, nor, &spi_nor_params_fops);
    247	debugfs_create_file("capabilities", 0444, d, nor,
    248			    &spi_nor_capabilities_fops);
    249}