Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mcb: Added bar descriptor support for non PCI bus MCB carrier

Added support for the bar descriptor. This type is used for FPGAs
connect to the LPC or to a non PCI bus.

The Bar descriptor could have a maximum of 6 BARs. Each of the
devices within the FPGA could be mapped to a different BAR.
The BAR descriptor is comparable to the PCI header.

Signed-off-by: Andreas Werner <andreas.werner@men.de>
[ free bar descriptor in the non-error case ]
Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Andreas Werner and committed by
Greg Kroah-Hartman
ffc7bb38 73edc8f7

+121 -14
+9
drivers/mcb/mcb-internal.h
··· 112 112 u32 size; 113 113 } __packed; 114 114 115 + struct chameleon_bar { 116 + u32 addr; 117 + u32 size; 118 + }; 119 + 120 + #define BAR_CNT(x) ((x) & 0x07) 121 + #define CHAMELEON_BAR_MAX 6 122 + #define BAR_DESC_SIZE(x) ((x) * sizeof(struct chameleon_bar) + sizeof(__le32)) 123 + 115 124 int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, 116 125 void __iomem *base); 117 126
+112 -14
drivers/mcb/mcb-parse.c
··· 26 26 } 27 27 28 28 static int chameleon_parse_bdd(struct mcb_bus *bus, 29 - phys_addr_t mapbase, 29 + struct chameleon_bar *cb, 30 30 void __iomem *base) 31 31 { 32 32 return 0; 33 33 } 34 34 35 35 static int chameleon_parse_gdd(struct mcb_bus *bus, 36 - phys_addr_t mapbase, 37 - void __iomem *base) 36 + struct chameleon_bar *cb, 37 + void __iomem *base, int bar_count) 38 38 { 39 39 struct chameleon_gdd __iomem *gdd = 40 40 (struct chameleon_gdd __iomem *) base; 41 41 struct mcb_device *mdev; 42 + u32 dev_mapbase; 42 43 u32 offset; 43 44 u32 size; 44 45 int ret; ··· 62 61 mdev->group = GDD_GRP(reg2); 63 62 mdev->inst = GDD_INS(reg2); 64 63 64 + /* 65 + * If the BAR is missing, dev_mapbase is zero, or if the 66 + * device is IO mapped we just print a warning and go on with the 67 + * next device, instead of completely stop the gdd parser 68 + */ 69 + if (mdev->bar > bar_count - 1) { 70 + pr_info("No BAR for 16z%03d\n", mdev->id); 71 + ret = 0; 72 + goto err; 73 + } 74 + 75 + dev_mapbase = cb[mdev->bar].addr; 76 + if (!dev_mapbase) { 77 + pr_info("BAR not assigned for 16z%03d\n", mdev->id); 78 + ret = 0; 79 + goto err; 80 + } 81 + 82 + if (dev_mapbase & 0x01) { 83 + pr_info("IO mapped Device (16z%03d) not yet supported\n", 84 + mdev->id); 85 + ret = 0; 86 + goto err; 87 + } 88 + 65 89 pr_debug("Found a 16z%03d\n", mdev->id); 66 90 67 91 mdev->irq.start = GDD_IRQ(reg1); 68 92 mdev->irq.end = GDD_IRQ(reg1); 69 93 mdev->irq.flags = IORESOURCE_IRQ; 70 94 71 - mdev->mem.start = mapbase + offset; 95 + mdev->mem.start = dev_mapbase + offset; 96 + 72 97 mdev->mem.end = mdev->mem.start + size - 1; 73 98 mdev->mem.flags = IORESOURCE_MEM; 74 99 ··· 112 85 return ret; 113 86 } 114 87 88 + static void chameleon_parse_bar(void __iomem *base, 89 + struct chameleon_bar *cb, int bar_count) 90 + { 91 + char __iomem *p = base; 92 + int i; 93 + 94 + /* skip reg1 */ 95 + p += sizeof(__le32); 96 + 97 + for (i = 0; i < bar_count; i++) { 98 + cb[i].addr = readl(p); 99 + cb[i].size = readl(p + 4); 100 + 101 + p += sizeof(struct chameleon_bar); 102 + } 103 + } 104 + 105 + static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase, 106 + struct chameleon_bar **cb) 107 + { 108 + struct chameleon_bar *c; 109 + int bar_count; 110 + __le32 reg; 111 + u32 dtype; 112 + 113 + /* 114 + * For those devices which are not connected 115 + * to the PCI Bus (e.g. LPC) there is a bar 116 + * descriptor located directly after the 117 + * chameleon header. This header is comparable 118 + * to a PCI header. 119 + */ 120 + dtype = get_next_dtype(*base); 121 + if (dtype == CHAMELEON_DTYPE_BAR) { 122 + reg = readl(*base); 123 + 124 + bar_count = BAR_CNT(reg); 125 + if (bar_count <= 0 && bar_count > CHAMELEON_BAR_MAX) 126 + return -ENODEV; 127 + 128 + c = kcalloc(bar_count, sizeof(struct chameleon_bar), 129 + GFP_KERNEL); 130 + if (!c) 131 + return -ENOMEM; 132 + 133 + chameleon_parse_bar(*base, c, bar_count); 134 + *base += BAR_DESC_SIZE(bar_count); 135 + } else { 136 + c = kzalloc(sizeof(struct chameleon_bar), GFP_KERNEL); 137 + if (!c) 138 + return -ENOMEM; 139 + 140 + bar_count = 1; 141 + c->addr = mapbase; 142 + } 143 + 144 + *cb = c; 145 + 146 + return bar_count; 147 + } 148 + 115 149 int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, 116 150 void __iomem *base) 117 151 { 118 - char __iomem *p = base; 119 152 struct chameleon_fpga_header *header; 120 - uint32_t dtype; 153 + struct chameleon_bar *cb; 154 + char __iomem *p = base; 121 155 int num_cells = 0; 156 + uint32_t dtype; 157 + int bar_count; 122 158 int ret = 0; 123 159 u32 hsize; 124 160 ··· 198 108 if (header->magic != CHAMELEONV2_MAGIC) { 199 109 pr_err("Unsupported chameleon version 0x%x\n", 200 110 header->magic); 201 - kfree(header); 202 - return -ENODEV; 111 + ret = -ENODEV; 112 + goto free_header; 203 113 } 204 114 p += hsize; 205 115 ··· 209 119 snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s", 210 120 header->filename); 211 121 122 + bar_count = chameleon_get_bar(&p, mapbase, &cb); 123 + if (bar_count < 0) 124 + goto free_header; 125 + 212 126 for_each_chameleon_cell(dtype, p) { 213 127 switch (dtype) { 214 128 case CHAMELEON_DTYPE_GENERAL: 215 - ret = chameleon_parse_gdd(bus, mapbase, p); 129 + ret = chameleon_parse_gdd(bus, cb, p, bar_count); 216 130 if (ret < 0) 217 - goto out; 131 + goto free_bar; 218 132 p += sizeof(struct chameleon_gdd); 219 133 break; 220 134 case CHAMELEON_DTYPE_BRIDGE: 221 - chameleon_parse_bdd(bus, mapbase, p); 135 + chameleon_parse_bdd(bus, cb, p); 222 136 p += sizeof(struct chameleon_bdd); 223 137 break; 224 138 case CHAMELEON_DTYPE_END: ··· 230 136 default: 231 137 pr_err("Invalid chameleon descriptor type 0x%x\n", 232 138 dtype); 233 - kfree(header); 234 - return -EINVAL; 139 + ret = -EINVAL; 140 + goto free_bar; 235 141 } 236 142 num_cells++; 237 143 } ··· 239 145 if (num_cells == 0) 240 146 num_cells = -EINVAL; 241 147 148 + kfree(cb); 242 149 kfree(header); 243 150 return num_cells; 244 151 245 - out: 152 + free_bar: 153 + kfree(cb); 154 + free_header: 246 155 kfree(header); 156 + 247 157 return ret; 248 158 } 249 159 EXPORT_SYMBOL_GPL(chameleon_parse_cells);