Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
0004 //
0005 // Copyright (c) 2020, 2021 Pengutronix,
0006 //               Marc Kleine-Budde <kernel@pengutronix.de>
0007 // Copyright (C) 2015-2018 Etnaviv Project
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     /* provoke NULL pointer access, if used after END object */
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     /* register space + end marker */
0249     obj_num = 2;
0250 
0251     /* register space */
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     /* TEF ring, RX rings, TX ring */
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     /* size of the headers */
0263     file_size += sizeof(*iter.hdr) * obj_num;
0264 
0265     /* allocate the file in vmalloc memory, it's likely to be big */
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     /* point the data member after the headers */
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 }