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

mcp251xfd-dump.c (7399B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
      4//
      5// Copyright (c) 2020, 2021 Pengutronix,
      6//               Marc Kleine-Budde <kernel@pengutronix.de>
      7// Copyright (C) 2015-2018 Etnaviv Project
      8//
      9
     10#include <linux/devcoredump.h>
     11
     12#include "mcp251xfd.h"
     13#include "mcp251xfd-dump.h"
     14
     15struct mcp251xfd_dump_iter {
     16	void *start;
     17	struct mcp251xfd_dump_object_header *hdr;
     18	void *data;
     19};
     20
     21struct mcp251xfd_dump_reg_space {
     22	u16 base;
     23	u16 size;
     24};
     25
     26struct mcp251xfd_dump_ring {
     27	enum mcp251xfd_dump_object_ring_key key;
     28	u32 val;
     29};
     30
     31static const struct mcp251xfd_dump_reg_space mcp251xfd_dump_reg_space[] = {
     32	{
     33		.base = MCP251XFD_REG_CON,
     34		.size = MCP251XFD_REG_FLTOBJ(32) - MCP251XFD_REG_CON,
     35	}, {
     36		.base = MCP251XFD_RAM_START,
     37		.size = MCP251XFD_RAM_SIZE,
     38	}, {
     39		.base = MCP251XFD_REG_OSC,
     40		.size = MCP251XFD_REG_DEVID - MCP251XFD_REG_OSC,
     41	},
     42};
     43
     44static void mcp251xfd_dump_header(struct mcp251xfd_dump_iter *iter,
     45				  enum mcp251xfd_dump_object_type object_type,
     46				  const void *data_end)
     47{
     48	struct mcp251xfd_dump_object_header *hdr = iter->hdr;
     49	unsigned int len;
     50
     51	len = data_end - iter->data;
     52	if (!len)
     53		return;
     54
     55	hdr->magic = cpu_to_le32(MCP251XFD_DUMP_MAGIC);
     56	hdr->type = cpu_to_le32(object_type);
     57	hdr->offset = cpu_to_le32(iter->data - iter->start);
     58	hdr->len = cpu_to_le32(len);
     59
     60	iter->hdr++;
     61	iter->data += len;
     62}
     63
     64static void mcp251xfd_dump_registers(const struct mcp251xfd_priv *priv,
     65				     struct mcp251xfd_dump_iter *iter)
     66{
     67	const int val_bytes = regmap_get_val_bytes(priv->map_rx);
     68	struct mcp251xfd_dump_object_reg *reg = iter->data;
     69	unsigned int i, j;
     70	int err;
     71
     72	for (i = 0; i < ARRAY_SIZE(mcp251xfd_dump_reg_space); i++) {
     73		const struct mcp251xfd_dump_reg_space *reg_space;
     74		void *buf;
     75
     76		reg_space = &mcp251xfd_dump_reg_space[i];
     77
     78		buf = kmalloc(reg_space->size, GFP_KERNEL);
     79		if (!buf)
     80			goto out;
     81
     82		err = regmap_bulk_read(priv->map_reg, reg_space->base,
     83				       buf, reg_space->size / val_bytes);
     84		if (err) {
     85			kfree(buf);
     86			continue;
     87		}
     88
     89		for (j = 0; j < reg_space->size; j += sizeof(u32), reg++) {
     90			reg->reg = cpu_to_le32(reg_space->base + j);
     91			reg->val = cpu_to_le32p(buf + j);
     92		}
     93
     94		kfree(buf);
     95	}
     96
     97 out:
     98	mcp251xfd_dump_header(iter, MCP251XFD_DUMP_OBJECT_TYPE_REG, reg);
     99}
    100
    101static void mcp251xfd_dump_ring(struct mcp251xfd_dump_iter *iter,
    102				enum mcp251xfd_dump_object_type object_type,
    103				const struct mcp251xfd_dump_ring *dump_ring,
    104				unsigned int len)
    105{
    106	struct mcp251xfd_dump_object_reg *reg = iter->data;
    107	unsigned int i;
    108
    109	for (i = 0; i < len; i++, reg++) {
    110		reg->reg = cpu_to_le32(dump_ring[i].key);
    111		reg->val = cpu_to_le32(dump_ring[i].val);
    112	}
    113
    114	mcp251xfd_dump_header(iter, object_type, reg);
    115}
    116
    117static void mcp251xfd_dump_tef_ring(const struct mcp251xfd_priv *priv,
    118				    struct mcp251xfd_dump_iter *iter)
    119{
    120	const struct mcp251xfd_tef_ring *tef = priv->tef;
    121	const struct mcp251xfd_tx_ring *tx = priv->tx;
    122	const struct mcp251xfd_dump_ring dump_ring[] = {
    123		{
    124			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
    125			.val = tef->head,
    126		}, {
    127			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
    128			.val = tef->tail,
    129		}, {
    130			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
    131			.val = 0,
    132		}, {
    133			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
    134			.val = 0,
    135		}, {
    136			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
    137			.val = 0,
    138		}, {
    139			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
    140			.val = tx->obj_num,
    141		}, {
    142			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
    143			.val = sizeof(struct mcp251xfd_hw_tef_obj),
    144		},
    145	};
    146
    147	mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_TEF,
    148			    dump_ring, ARRAY_SIZE(dump_ring));
    149}
    150
    151static void mcp251xfd_dump_rx_ring_one(const struct mcp251xfd_priv *priv,
    152				       struct mcp251xfd_dump_iter *iter,
    153				       const struct mcp251xfd_rx_ring *rx)
    154{
    155	const struct mcp251xfd_dump_ring dump_ring[] = {
    156		{
    157			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
    158			.val = rx->head,
    159		}, {
    160			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
    161			.val = rx->tail,
    162		}, {
    163			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
    164			.val = rx->base,
    165		}, {
    166			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
    167			.val = rx->nr,
    168		}, {
    169			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
    170			.val = rx->fifo_nr,
    171		}, {
    172			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
    173			.val = rx->obj_num,
    174		}, {
    175			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
    176			.val = rx->obj_size,
    177		},
    178	};
    179
    180	mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_RX,
    181			    dump_ring, ARRAY_SIZE(dump_ring));
    182}
    183
    184static void mcp251xfd_dump_rx_ring(const struct mcp251xfd_priv *priv,
    185				   struct mcp251xfd_dump_iter *iter)
    186{
    187	struct mcp251xfd_rx_ring *rx_ring;
    188	unsigned int i;
    189
    190	mcp251xfd_for_each_rx_ring(priv, rx_ring, i)
    191		mcp251xfd_dump_rx_ring_one(priv, iter, rx_ring);
    192}
    193
    194static void mcp251xfd_dump_tx_ring(const struct mcp251xfd_priv *priv,
    195				   struct mcp251xfd_dump_iter *iter)
    196{
    197	const struct mcp251xfd_tx_ring *tx = priv->tx;
    198	const struct mcp251xfd_dump_ring dump_ring[] = {
    199		{
    200			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
    201			.val = tx->head,
    202		}, {
    203			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
    204			.val = tx->tail,
    205		}, {
    206			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
    207			.val = tx->base,
    208		}, {
    209			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
    210			.val = tx->nr,
    211		}, {
    212			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
    213			.val = tx->fifo_nr,
    214		}, {
    215			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
    216			.val = tx->obj_num,
    217		}, {
    218			.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
    219			.val = tx->obj_size,
    220		},
    221	};
    222
    223	mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_TX,
    224			    dump_ring, ARRAY_SIZE(dump_ring));
    225}
    226
    227static void mcp251xfd_dump_end(const struct mcp251xfd_priv *priv,
    228			       struct mcp251xfd_dump_iter *iter)
    229{
    230	struct mcp251xfd_dump_object_header *hdr = iter->hdr;
    231
    232	hdr->magic = cpu_to_le32(MCP251XFD_DUMP_MAGIC);
    233	hdr->type = cpu_to_le32(MCP251XFD_DUMP_OBJECT_TYPE_END);
    234	hdr->offset = cpu_to_le32(0);
    235	hdr->len = cpu_to_le32(0);
    236
    237	/* provoke NULL pointer access, if used after END object */
    238	iter->hdr = NULL;
    239}
    240
    241void mcp251xfd_dump(const struct mcp251xfd_priv *priv)
    242{
    243	struct mcp251xfd_dump_iter iter;
    244	unsigned int rings_num, obj_num;
    245	unsigned int file_size = 0;
    246	unsigned int i;
    247
    248	/* register space + end marker */
    249	obj_num = 2;
    250
    251	/* register space */
    252	for (i = 0; i < ARRAY_SIZE(mcp251xfd_dump_reg_space); i++)
    253		file_size += mcp251xfd_dump_reg_space[i].size / sizeof(u32) *
    254			sizeof(struct mcp251xfd_dump_object_reg);
    255
    256	/* TEF ring, RX ring, TX rings */
    257	rings_num = 1 + priv->rx_ring_num + 1;
    258	obj_num += rings_num;
    259	file_size += rings_num * __MCP251XFD_DUMP_OBJECT_RING_KEY_MAX  *
    260		sizeof(struct mcp251xfd_dump_object_reg);
    261
    262	/* size of the headers */
    263	file_size += sizeof(*iter.hdr) * obj_num;
    264
    265	/* allocate the file in vmalloc memory, it's likely to be big */
    266	iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN |
    267			       __GFP_ZERO | __GFP_NORETRY);
    268	if (!iter.start) {
    269		netdev_warn(priv->ndev, "Failed to allocate devcoredump file.\n");
    270		return;
    271	}
    272
    273	/* point the data member after the headers */
    274	iter.hdr = iter.start;
    275	iter.data = &iter.hdr[obj_num];
    276
    277	mcp251xfd_dump_registers(priv, &iter);
    278	mcp251xfd_dump_tef_ring(priv, &iter);
    279	mcp251xfd_dump_rx_ring(priv, &iter);
    280	mcp251xfd_dump_tx_ring(priv, &iter);
    281	mcp251xfd_dump_end(priv, &iter);
    282
    283	dev_coredumpv(&priv->spi->dev, iter.start,
    284		      iter.data - iter.start, GFP_KERNEL);
    285}