root/drivers/mcb/mcb-parse.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_next_dtype
  2. chameleon_parse_bdd
  3. chameleon_parse_gdd
  4. chameleon_parse_bar
  5. chameleon_get_bar
  6. chameleon_parse_cells

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

/* [<][>][^][v][top][bottom][index][help] */