^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/mcb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "mcb-internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct mcb_parse_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) phys_addr_t mapbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define for_each_chameleon_cell(dtype, p) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) for ((dtype) = get_next_dtype((p)); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) (dtype) != CHAMELEON_DTYPE_END; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) (dtype) = get_next_dtype((p)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static inline uint32_t get_next_dtype(void __iomem *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) uint32_t dtype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) dtype = readl(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) return dtype >> 28;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static int chameleon_parse_bdd(struct mcb_bus *bus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct chameleon_bar *cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) void __iomem *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static int chameleon_parse_gdd(struct mcb_bus *bus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct chameleon_bar *cb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) void __iomem *base, int bar_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct chameleon_gdd __iomem *gdd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) (struct chameleon_gdd __iomem *) base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct mcb_device *mdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) u32 dev_mapbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u32 offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) u32 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) __le32 reg1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) __le32 reg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) mdev = mcb_alloc_dev(bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (!mdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) reg1 = readl(&gdd->reg1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) reg2 = readl(&gdd->reg2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) offset = readl(&gdd->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) size = readl(&gdd->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) mdev->id = GDD_DEV(reg1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) mdev->rev = GDD_REV(reg1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) mdev->var = GDD_VAR(reg1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) mdev->bar = GDD_BAR(reg2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) mdev->group = GDD_GRP(reg2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) mdev->inst = GDD_INS(reg2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * If the BAR is missing, dev_mapbase is zero, or if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * device is IO mapped we just print a warning and go on with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * next device, instead of completely stop the gdd parser
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (mdev->bar > bar_count - 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) pr_info("No BAR for 16z%03d\n", mdev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) dev_mapbase = cb[mdev->bar].addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (!dev_mapbase) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) pr_info("BAR not assigned for 16z%03d\n", mdev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (dev_mapbase & 0x01) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) pr_info("IO mapped Device (16z%03d) not yet supported\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) mdev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) pr_debug("Found a 16z%03d\n", mdev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) mdev->irq.start = GDD_IRQ(reg1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) mdev->irq.end = GDD_IRQ(reg1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) mdev->irq.flags = IORESOURCE_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) mdev->mem.start = dev_mapbase + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) mdev->mem.end = mdev->mem.start + size - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) mdev->mem.flags = IORESOURCE_MEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) mdev->is_added = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) ret = mcb_device_register(bus, mdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) mcb_free_dev(mdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static void chameleon_parse_bar(void __iomem *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct chameleon_bar *cb, int bar_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) char __iomem *p = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /* skip reg1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) p += sizeof(__le32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) for (i = 0; i < bar_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) cb[i].addr = readl(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) cb[i].size = readl(p + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) p += sizeof(struct chameleon_bar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct chameleon_bar **cb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct chameleon_bar *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) int bar_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) __le32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) u32 dtype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * For those devices which are not connected
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * to the PCI Bus (e.g. LPC) there is a bar
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * descriptor located directly after the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * chameleon header. This header is comparable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * to a PCI header.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) dtype = get_next_dtype(*base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (dtype == CHAMELEON_DTYPE_BAR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) reg = readl(*base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) bar_count = BAR_CNT(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (bar_count <= 0 || bar_count > CHAMELEON_BAR_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) c = kcalloc(bar_count, sizeof(struct chameleon_bar),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (!c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) chameleon_parse_bar(*base, c, bar_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) *base += BAR_DESC_SIZE(bar_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) c = kzalloc(sizeof(struct chameleon_bar), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (!c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) bar_count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) c->addr = mapbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) *cb = c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return bar_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) void __iomem *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct chameleon_fpga_header *header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) struct chameleon_bar *cb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) char __iomem *p = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) int num_cells = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) uint32_t dtype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) int bar_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) u32 hsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) hsize = sizeof(struct chameleon_fpga_header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) header = kzalloc(hsize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (!header)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /* Extract header information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) memcpy_fromio(header, p, hsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /* We only support chameleon v2 at the moment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) header->magic = le16_to_cpu(header->magic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (header->magic != CHAMELEONV2_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) pr_err("Unsupported chameleon version 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) header->magic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) goto free_header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) p += hsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) bus->revision = header->revision;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) bus->model = header->model;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) bus->minor = header->minor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) header->filename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) bar_count = chameleon_get_bar(&p, mapbase, &cb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (bar_count < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) ret = bar_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) goto free_header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) for_each_chameleon_cell(dtype, p) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) switch (dtype) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) case CHAMELEON_DTYPE_GENERAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) ret = chameleon_parse_gdd(bus, cb, p, bar_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) goto free_bar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) p += sizeof(struct chameleon_gdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) case CHAMELEON_DTYPE_BRIDGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) chameleon_parse_bdd(bus, cb, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) p += sizeof(struct chameleon_bdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) case CHAMELEON_DTYPE_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) pr_err("Invalid chameleon descriptor type 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) dtype);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) goto free_bar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) num_cells++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (num_cells == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) num_cells = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) kfree(cb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) kfree(header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return num_cells;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) free_bar:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) kfree(cb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) free_header:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) kfree(header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) EXPORT_SYMBOL_NS_GPL(chameleon_parse_cells, MCB);