0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/devcoredump.h>
0011
0012 #include "mcp251xfd.h"
0013 #include "mcp251xfd-dump.h"
0014
0015 struct mcp251xfd_dump_iter {
0016 void *start;
0017 struct mcp251xfd_dump_object_header *hdr;
0018 void *data;
0019 };
0020
0021 struct mcp251xfd_dump_reg_space {
0022 u16 base;
0023 u16 size;
0024 };
0025
0026 struct mcp251xfd_dump_ring {
0027 enum mcp251xfd_dump_object_ring_key key;
0028 u32 val;
0029 };
0030
0031 static const struct mcp251xfd_dump_reg_space mcp251xfd_dump_reg_space[] = {
0032 {
0033 .base = MCP251XFD_REG_CON,
0034 .size = MCP251XFD_REG_FLTOBJ(32) - MCP251XFD_REG_CON,
0035 }, {
0036 .base = MCP251XFD_RAM_START,
0037 .size = MCP251XFD_RAM_SIZE,
0038 }, {
0039 .base = MCP251XFD_REG_OSC,
0040 .size = MCP251XFD_REG_DEVID - MCP251XFD_REG_OSC,
0041 },
0042 };
0043
0044 static void mcp251xfd_dump_header(struct mcp251xfd_dump_iter *iter,
0045 enum mcp251xfd_dump_object_type object_type,
0046 const void *data_end)
0047 {
0048 struct mcp251xfd_dump_object_header *hdr = iter->hdr;
0049 unsigned int len;
0050
0051 len = data_end - iter->data;
0052 if (!len)
0053 return;
0054
0055 hdr->magic = cpu_to_le32(MCP251XFD_DUMP_MAGIC);
0056 hdr->type = cpu_to_le32(object_type);
0057 hdr->offset = cpu_to_le32(iter->data - iter->start);
0058 hdr->len = cpu_to_le32(len);
0059
0060 iter->hdr++;
0061 iter->data += len;
0062 }
0063
0064 static void mcp251xfd_dump_registers(const struct mcp251xfd_priv *priv,
0065 struct mcp251xfd_dump_iter *iter)
0066 {
0067 const int val_bytes = regmap_get_val_bytes(priv->map_rx);
0068 struct mcp251xfd_dump_object_reg *reg = iter->data;
0069 unsigned int i, j;
0070 int err;
0071
0072 for (i = 0; i < ARRAY_SIZE(mcp251xfd_dump_reg_space); i++) {
0073 const struct mcp251xfd_dump_reg_space *reg_space;
0074 void *buf;
0075
0076 reg_space = &mcp251xfd_dump_reg_space[i];
0077
0078 buf = kmalloc(reg_space->size, GFP_KERNEL);
0079 if (!buf)
0080 goto out;
0081
0082 err = regmap_bulk_read(priv->map_reg, reg_space->base,
0083 buf, reg_space->size / val_bytes);
0084 if (err) {
0085 kfree(buf);
0086 continue;
0087 }
0088
0089 for (j = 0; j < reg_space->size; j += sizeof(u32), reg++) {
0090 reg->reg = cpu_to_le32(reg_space->base + j);
0091 reg->val = cpu_to_le32p(buf + j);
0092 }
0093
0094 kfree(buf);
0095 }
0096
0097 out:
0098 mcp251xfd_dump_header(iter, MCP251XFD_DUMP_OBJECT_TYPE_REG, reg);
0099 }
0100
0101 static void mcp251xfd_dump_ring(struct mcp251xfd_dump_iter *iter,
0102 enum mcp251xfd_dump_object_type object_type,
0103 const struct mcp251xfd_dump_ring *dump_ring,
0104 unsigned int len)
0105 {
0106 struct mcp251xfd_dump_object_reg *reg = iter->data;
0107 unsigned int i;
0108
0109 for (i = 0; i < len; i++, reg++) {
0110 reg->reg = cpu_to_le32(dump_ring[i].key);
0111 reg->val = cpu_to_le32(dump_ring[i].val);
0112 }
0113
0114 mcp251xfd_dump_header(iter, object_type, reg);
0115 }
0116
0117 static void mcp251xfd_dump_tef_ring(const struct mcp251xfd_priv *priv,
0118 struct mcp251xfd_dump_iter *iter)
0119 {
0120 const struct mcp251xfd_tef_ring *tef = priv->tef;
0121 const struct mcp251xfd_tx_ring *tx = priv->tx;
0122 const struct mcp251xfd_dump_ring dump_ring[] = {
0123 {
0124 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
0125 .val = tef->head,
0126 }, {
0127 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
0128 .val = tef->tail,
0129 }, {
0130 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
0131 .val = 0,
0132 }, {
0133 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
0134 .val = 0,
0135 }, {
0136 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
0137 .val = 0,
0138 }, {
0139 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
0140 .val = tx->obj_num,
0141 }, {
0142 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
0143 .val = sizeof(struct mcp251xfd_hw_tef_obj),
0144 },
0145 };
0146
0147 mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_TEF,
0148 dump_ring, ARRAY_SIZE(dump_ring));
0149 }
0150
0151 static void mcp251xfd_dump_rx_ring_one(const struct mcp251xfd_priv *priv,
0152 struct mcp251xfd_dump_iter *iter,
0153 const struct mcp251xfd_rx_ring *rx)
0154 {
0155 const struct mcp251xfd_dump_ring dump_ring[] = {
0156 {
0157 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
0158 .val = rx->head,
0159 }, {
0160 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
0161 .val = rx->tail,
0162 }, {
0163 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
0164 .val = rx->base,
0165 }, {
0166 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
0167 .val = rx->nr,
0168 }, {
0169 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
0170 .val = rx->fifo_nr,
0171 }, {
0172 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
0173 .val = rx->obj_num,
0174 }, {
0175 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
0176 .val = rx->obj_size,
0177 },
0178 };
0179
0180 mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_RX,
0181 dump_ring, ARRAY_SIZE(dump_ring));
0182 }
0183
0184 static void mcp251xfd_dump_rx_ring(const struct mcp251xfd_priv *priv,
0185 struct mcp251xfd_dump_iter *iter)
0186 {
0187 struct mcp251xfd_rx_ring *rx_ring;
0188 unsigned int i;
0189
0190 mcp251xfd_for_each_rx_ring(priv, rx_ring, i)
0191 mcp251xfd_dump_rx_ring_one(priv, iter, rx_ring);
0192 }
0193
0194 static void mcp251xfd_dump_tx_ring(const struct mcp251xfd_priv *priv,
0195 struct mcp251xfd_dump_iter *iter)
0196 {
0197 const struct mcp251xfd_tx_ring *tx = priv->tx;
0198 const struct mcp251xfd_dump_ring dump_ring[] = {
0199 {
0200 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
0201 .val = tx->head,
0202 }, {
0203 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
0204 .val = tx->tail,
0205 }, {
0206 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
0207 .val = tx->base,
0208 }, {
0209 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
0210 .val = tx->nr,
0211 }, {
0212 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
0213 .val = tx->fifo_nr,
0214 }, {
0215 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
0216 .val = tx->obj_num,
0217 }, {
0218 .key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
0219 .val = tx->obj_size,
0220 },
0221 };
0222
0223 mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_TX,
0224 dump_ring, ARRAY_SIZE(dump_ring));
0225 }
0226
0227 static void mcp251xfd_dump_end(const struct mcp251xfd_priv *priv,
0228 struct mcp251xfd_dump_iter *iter)
0229 {
0230 struct mcp251xfd_dump_object_header *hdr = iter->hdr;
0231
0232 hdr->magic = cpu_to_le32(MCP251XFD_DUMP_MAGIC);
0233 hdr->type = cpu_to_le32(MCP251XFD_DUMP_OBJECT_TYPE_END);
0234 hdr->offset = cpu_to_le32(0);
0235 hdr->len = cpu_to_le32(0);
0236
0237
0238 iter->hdr = NULL;
0239 }
0240
0241 void mcp251xfd_dump(const struct mcp251xfd_priv *priv)
0242 {
0243 struct mcp251xfd_dump_iter iter;
0244 unsigned int rings_num, obj_num;
0245 unsigned int file_size = 0;
0246 unsigned int i;
0247
0248
0249 obj_num = 2;
0250
0251
0252 for (i = 0; i < ARRAY_SIZE(mcp251xfd_dump_reg_space); i++)
0253 file_size += mcp251xfd_dump_reg_space[i].size / sizeof(u32) *
0254 sizeof(struct mcp251xfd_dump_object_reg);
0255
0256
0257 rings_num = 1 + priv->rx_ring_num + 1;
0258 obj_num += rings_num;
0259 file_size += rings_num * __MCP251XFD_DUMP_OBJECT_RING_KEY_MAX *
0260 sizeof(struct mcp251xfd_dump_object_reg);
0261
0262
0263 file_size += sizeof(*iter.hdr) * obj_num;
0264
0265
0266 iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN |
0267 __GFP_ZERO | __GFP_NORETRY);
0268 if (!iter.start) {
0269 netdev_warn(priv->ndev, "Failed to allocate devcoredump file.\n");
0270 return;
0271 }
0272
0273
0274 iter.hdr = iter.start;
0275 iter.data = &iter.hdr[obj_num];
0276
0277 mcp251xfd_dump_registers(priv, &iter);
0278 mcp251xfd_dump_tef_ring(priv, &iter);
0279 mcp251xfd_dump_rx_ring(priv, &iter);
0280 mcp251xfd_dump_tx_ring(priv, &iter);
0281 mcp251xfd_dump_end(priv, &iter);
0282
0283 dev_coredumpv(&priv->spi->dev, iter.start,
0284 iter.data - iter.start, GFP_KERNEL);
0285 }