0001
0002 #include <linux/types.h>
0003 #include <linux/ioport.h>
0004 #include <linux/slab.h>
0005 #include <linux/export.h>
0006 #include <linux/io.h>
0007 #include <linux/mcb.h>
0008
0009 #include "mcb-internal.h"
0010
0011 struct mcb_parse_priv {
0012 phys_addr_t mapbase;
0013 void __iomem *base;
0014 };
0015
0016 #define for_each_chameleon_cell(dtype, p) \
0017 for ((dtype) = get_next_dtype((p)); \
0018 (dtype) != CHAMELEON_DTYPE_END; \
0019 (dtype) = get_next_dtype((p)))
0020
0021 static inline uint32_t get_next_dtype(void __iomem *p)
0022 {
0023 uint32_t dtype;
0024
0025 dtype = readl(p);
0026 return dtype >> 28;
0027 }
0028
0029 static int chameleon_parse_bdd(struct mcb_bus *bus,
0030 struct chameleon_bar *cb,
0031 void __iomem *base)
0032 {
0033 return 0;
0034 }
0035
0036 static int chameleon_parse_gdd(struct mcb_bus *bus,
0037 struct chameleon_bar *cb,
0038 void __iomem *base, int bar_count)
0039 {
0040 struct chameleon_gdd __iomem *gdd =
0041 (struct chameleon_gdd __iomem *) base;
0042 struct mcb_device *mdev;
0043 u32 dev_mapbase;
0044 u32 offset;
0045 u32 size;
0046 int ret;
0047 __le32 reg1;
0048 __le32 reg2;
0049
0050 mdev = mcb_alloc_dev(bus);
0051 if (!mdev)
0052 return -ENOMEM;
0053
0054 reg1 = readl(&gdd->reg1);
0055 reg2 = readl(&gdd->reg2);
0056 offset = readl(&gdd->offset);
0057 size = readl(&gdd->size);
0058
0059 mdev->id = GDD_DEV(reg1);
0060 mdev->rev = GDD_REV(reg1);
0061 mdev->var = GDD_VAR(reg1);
0062 mdev->bar = GDD_BAR(reg2);
0063 mdev->group = GDD_GRP(reg2);
0064 mdev->inst = GDD_INS(reg2);
0065
0066
0067
0068
0069
0070
0071 if (mdev->bar > bar_count - 1) {
0072 pr_info("No BAR for 16z%03d\n", mdev->id);
0073 ret = 0;
0074 goto err;
0075 }
0076
0077 dev_mapbase = cb[mdev->bar].addr;
0078 if (!dev_mapbase) {
0079 pr_info("BAR not assigned for 16z%03d\n", mdev->id);
0080 ret = 0;
0081 goto err;
0082 }
0083
0084 if (dev_mapbase & 0x01) {
0085 pr_info("IO mapped Device (16z%03d) not yet supported\n",
0086 mdev->id);
0087 ret = 0;
0088 goto err;
0089 }
0090
0091 pr_debug("Found a 16z%03d\n", mdev->id);
0092
0093 mdev->irq.start = GDD_IRQ(reg1);
0094 mdev->irq.end = GDD_IRQ(reg1);
0095 mdev->irq.flags = IORESOURCE_IRQ;
0096
0097 mdev->mem.start = dev_mapbase + offset;
0098
0099 mdev->mem.end = mdev->mem.start + size - 1;
0100 mdev->mem.flags = IORESOURCE_MEM;
0101
0102 mdev->is_added = false;
0103
0104 ret = mcb_device_register(bus, mdev);
0105 if (ret < 0)
0106 goto err;
0107
0108 return 0;
0109
0110 err:
0111 mcb_free_dev(mdev);
0112
0113 return ret;
0114 }
0115
0116 static void chameleon_parse_bar(void __iomem *base,
0117 struct chameleon_bar *cb, int bar_count)
0118 {
0119 char __iomem *p = base;
0120 int i;
0121
0122
0123 p += sizeof(__le32);
0124
0125 for (i = 0; i < bar_count; i++) {
0126 cb[i].addr = readl(p);
0127 cb[i].size = readl(p + 4);
0128
0129 p += sizeof(struct chameleon_bar);
0130 }
0131 }
0132
0133 static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase,
0134 struct chameleon_bar **cb)
0135 {
0136 struct chameleon_bar *c;
0137 int bar_count;
0138 __le32 reg;
0139 u32 dtype;
0140
0141
0142
0143
0144
0145
0146
0147
0148 dtype = get_next_dtype(*base);
0149 if (dtype == CHAMELEON_DTYPE_BAR) {
0150 reg = readl(*base);
0151
0152 bar_count = BAR_CNT(reg);
0153 if (bar_count <= 0 || bar_count > CHAMELEON_BAR_MAX)
0154 return -ENODEV;
0155
0156 c = kcalloc(bar_count, sizeof(struct chameleon_bar),
0157 GFP_KERNEL);
0158 if (!c)
0159 return -ENOMEM;
0160
0161 chameleon_parse_bar(*base, c, bar_count);
0162 *base += BAR_DESC_SIZE(bar_count);
0163 } else {
0164 c = kzalloc(sizeof(struct chameleon_bar), GFP_KERNEL);
0165 if (!c)
0166 return -ENOMEM;
0167
0168 bar_count = 1;
0169 c->addr = mapbase;
0170 }
0171
0172 *cb = c;
0173
0174 return bar_count;
0175 }
0176
0177 int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
0178 void __iomem *base)
0179 {
0180 struct chameleon_fpga_header *header;
0181 struct chameleon_bar *cb;
0182 char __iomem *p = base;
0183 int num_cells = 0;
0184 uint32_t dtype;
0185 int bar_count;
0186 int ret;
0187 u32 hsize;
0188
0189 hsize = sizeof(struct chameleon_fpga_header);
0190
0191 header = kzalloc(hsize, GFP_KERNEL);
0192 if (!header)
0193 return -ENOMEM;
0194
0195
0196 memcpy_fromio(header, p, hsize);
0197
0198 header->magic = le16_to_cpu(header->magic);
0199 if (header->magic != CHAMELEONV2_MAGIC) {
0200 pr_err("Unsupported chameleon version 0x%x\n",
0201 header->magic);
0202 ret = -ENODEV;
0203 goto free_header;
0204 }
0205 p += hsize;
0206
0207 bus->revision = header->revision;
0208 bus->model = header->model;
0209 bus->minor = header->minor;
0210 snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s",
0211 header->filename);
0212
0213 bar_count = chameleon_get_bar(&p, mapbase, &cb);
0214 if (bar_count < 0) {
0215 ret = bar_count;
0216 goto free_header;
0217 }
0218
0219 for_each_chameleon_cell(dtype, p) {
0220 switch (dtype) {
0221 case CHAMELEON_DTYPE_GENERAL:
0222 ret = chameleon_parse_gdd(bus, cb, p, bar_count);
0223 if (ret < 0)
0224 goto free_bar;
0225 p += sizeof(struct chameleon_gdd);
0226 break;
0227 case CHAMELEON_DTYPE_BRIDGE:
0228 chameleon_parse_bdd(bus, cb, p);
0229 p += sizeof(struct chameleon_bdd);
0230 break;
0231 case CHAMELEON_DTYPE_END:
0232 break;
0233 default:
0234 pr_err("Invalid chameleon descriptor type 0x%x\n",
0235 dtype);
0236 ret = -EINVAL;
0237 goto free_bar;
0238 }
0239 num_cells++;
0240 }
0241
0242 if (num_cells == 0)
0243 num_cells = -EINVAL;
0244
0245 kfree(cb);
0246 kfree(header);
0247 return num_cells;
0248
0249 free_bar:
0250 kfree(cb);
0251 free_header:
0252 kfree(header);
0253
0254 return ret;
0255 }
0256 EXPORT_SYMBOL_NS_GPL(chameleon_parse_cells, MCB);