1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
|
Index: linux-2.6.19/drivers/net/ixp4xx/Kconfig
===================================================================
--- linux-2.6.19.orig/drivers/net/ixp4xx/Kconfig
+++ linux-2.6.19/drivers/net/ixp4xx/Kconfig
@@ -11,6 +11,7 @@ config IXP4XX_NPE
tristate "IXP4xx NPE support"
depends on ARCH_IXP4XX
depends on NET_ETHERNET
+ select CRC16
help
The IXP4XX NPE driver supports the 3 CPU co-processors called
"Network Processing Engines" (NPE). It adds support fo downloading
@@ -18,7 +19,7 @@ config IXP4XX_NPE
More about this at: Documentation/networking/ixp4xx/README.
You can either use this OR the Intel Access Library (IAL)
-config IXP4XX_FW_LOAD
+config IXP4XX_NPE_FW_LOAD
bool "Use Firmware hotplug for Microcode download"
depends on IXP4XX_NPE
select HOTPLUG
@@ -28,6 +29,13 @@ config IXP4XX_FW_LOAD
/usr/lib/hotplug/firmware/NPE-[ABC]
see Documentation/firmware_class/hotplug-script
+config IXP4XX_NPE_FW_MTD
+ bool "Load firmware from an mtd partition"
+ depends on IXP4XX_NPE && MTD_IXP4XX
+ help
+ With this option, the driver will search for
+ the firmware into an MTD partition.
+
config IXP4XX_MAC
tristate "IXP4xx MAC support"
depends on IXP4XX_NPE
Index: linux-2.6.19/drivers/net/ixp4xx/Makefile
===================================================================
--- linux-2.6.19.orig/drivers/net/ixp4xx/Makefile
+++ linux-2.6.19/drivers/net/ixp4xx/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
obj-$(CONFIG_IXP4XX_NPE) += ixp4xx_npe.o
obj-$(CONFIG_IXP4XX_MAC) += ixp4xx_mac.o
+obj-$(CONFIG_IXP4XX_NPE_FW_MTD) += npe_ucode.o
ixp4xx_npe-objs := ucode_dl.o npe_mh.o
ixp4xx_mac-objs := mac_driver.o qmgr_eth.o phy.o
Index: linux-2.6.19/drivers/net/ixp4xx/npe_ucode.c
===================================================================
--- /dev/null
+++ linux-2.6.19/drivers/net/ixp4xx/npe_ucode.c
@@ -0,0 +1,185 @@
+/*
+ * Provide an NPE platform device for microcode handling
+ *
+ * Copyright (C) 2006 Christian Hohnstaedt <chohnstaedt@innominate.com>
+ *
+ * This file is released under the GPLv2
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/mtd/mtd.h>
+
+#include <linux/ixp_npe.h>
+
+#define DL_MAGIC 0xfeedf00d
+#define DL_MAGIC_SWAP 0x0df0edfe
+
+#define IMG_SIZE(image) (((image)->size * sizeof(u32)) + \
+ sizeof(struct dl_image))
+
+#define IMG_REV_MAJOR(id) (((id) >> 8) & 0x0f)
+#define IMG_REV_MINOR(id) ((id) & 0x0f)
+#define IMG_FUNC(id) (((id) >> 16) & 0xff)
+#define IMG_NPE(id) (((id) >> 24) & 0x0f)
+#define IMG_IXP(id) (((id) >> 28) & 0x0f)
+
+static struct platform_driver ixp4xx_npe_ucode_driver;
+static unsigned char *partition_name = NULL;
+
+static void print_image_info(u32 id, u32 offset, u32 size)
+{
+ unsigned char idx;
+ const char *names[] = { "IXP425", "IXP465", "unknown" };
+
+ idx = IMG_IXP(id) < 2 ? IMG_IXP(id) : 2;
+
+ printk(KERN_INFO "npe: found at 0x%x, %s/NPE-%c func: %02x, rev: %x.%x, "
+ "size: %5d, id: %08x\n", offset, names[idx], IMG_NPE(id) + 'A',
+ IMG_FUNC(id), IMG_REV_MAJOR(id), IMG_REV_MINOR(id), size, id);
+}
+
+void npe_swap_image(struct dl_image *image)
+{
+ unsigned int i;
+
+ image->magic = swab32(image->magic);
+ image->id = swab32(image->id);
+ image->size = swab32(image->size);
+
+ for (i = 0; i < image->size; i++)
+ image->u.data[i] = swab32(image->u.data[i]);
+}
+
+static void npe_find_microcode(struct mtd_info *mtd)
+{
+ u32 buf;
+ u32 magic = htonl(DL_MAGIC);
+ u32 id, size;
+ size_t retlen;
+ int err;
+ unsigned int offset = 0;
+
+ printk("npe: searching for firmware...\n");
+
+ while (offset < mtd->size) {
+
+ err = mtd->read(mtd, offset, 4, &retlen, (u_char *) &buf);
+ offset += retlen;
+
+ if (buf != magic)
+ continue;
+
+ err = mtd->read(mtd, offset, 4, &retlen, (u_char *) &id);
+ offset += retlen;
+
+ if (id == magic)
+ break;
+
+ id = ntohl(id);
+
+ err = mtd->read(mtd, offset, 4, &retlen, (u_char *) &size);
+ offset += retlen;
+
+ size = (ntohl(size) * 4) + 12;
+
+ print_image_info(id, offset - 12, size);
+
+ if (size < 24000 && ( IMG_FUNC(id) == 0x01 || IMG_FUNC(id) == 0x00) ) { // XXX fix size/detection
+
+ struct dl_image *image = kmalloc(size, GFP_KERNEL);
+
+ /* we are going to load it, rewind offset */
+ offset -= 12;
+
+ if (image) {
+ err = mtd->read(mtd, offset, size, &retlen, (u_char *) image);
+
+ if (err == 0 && retlen == size) {
+ if (image->magic == DL_MAGIC_SWAP)
+ npe_swap_image(image);
+
+ store_npe_image(image, NULL);
+ } else {
+ printk(KERN_ERR "unable to read firmware\n");
+ }
+
+ kfree(image);
+ }
+
+ offset += size;
+ }
+ }
+}
+
+static void npe_flash_add(struct mtd_info *mtd)
+{
+ if (partition_name == NULL)
+ return;
+
+ if (strcmp(mtd->name, partition_name) == 0) {
+ npe_find_microcode(mtd);
+ }
+}
+
+static void npe_flash_remove(struct mtd_info *mtd) {
+}
+
+static struct mtd_notifier npe_flash_notifier = {
+ .add = npe_flash_add,
+ .remove = npe_flash_remove,
+};
+
+static int npe_ucode_probe(struct platform_device *pdev)
+{
+ struct npe_ucode_platform_data *data = pdev->dev.platform_data;
+
+ if (partition_name)
+ return -EEXIST;
+
+ if (data && data->mtd_partition) {
+ partition_name = data->mtd_partition;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int npe_ucode_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver ixp4xx_npe_ucode_driver = {
+ .driver = {
+ .name = "ixp4xx_npe_ucode",
+ .owner = THIS_MODULE,
+ },
+ .probe = npe_ucode_probe,
+ .remove = npe_ucode_remove,
+};
+
+static int __init npe_ucode_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&ixp4xx_npe_ucode_driver);
+ register_mtd_user(&npe_flash_notifier);
+
+ return ret;
+}
+
+static void __exit npe_ucode_exit(void)
+{
+ unregister_mtd_user(&npe_flash_notifier);
+ platform_driver_unregister(&ixp4xx_npe_ucode_driver);
+}
+
+module_init(npe_ucode_init);
+module_exit(npe_ucode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
Index: linux-2.6.19/drivers/net/ixp4xx/ucode_dl.c
===================================================================
--- linux-2.6.19.orig/drivers/net/ixp4xx/ucode_dl.c
+++ linux-2.6.19/drivers/net/ixp4xx/ucode_dl.c
@@ -16,6 +16,7 @@
#include <linux/firmware.h>
#include <linux/dma-mapping.h>
#include <linux/byteorder/swab.h>
+#include <linux/crc16.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -30,6 +31,12 @@
#define IMG_SIZE(image) (((image)->size * sizeof(u32)) + \
sizeof(struct dl_image))
+#define IMG_REV_MAJOR(id) (((id) >> 8) & 0x0f)
+#define IMG_REV_MINOR(id) ((id) & 0x0f)
+#define IMG_FUNC(id) (((id) >> 16) & 0xff)
+#define IMG_NPE(id) (((id) >> 24) & 0x0f)
+#define IMG_IXP(id) (((id) >> 28) & 0x0f)
+
#define BT_INSTR 0
#define BT_DATA 1
@@ -38,21 +45,6 @@ enum blk_type {
data,
};
-struct dl_block {
- u32 type;
- u32 offset;
-};
-
-struct dl_image {
- u32 magic;
- u32 id;
- u32 size;
- union {
- u32 data[0];
- struct dl_block block[0];
- } u;
-};
-
struct dl_codeblock {
u32 npe_addr;
u32 size;
@@ -134,23 +126,41 @@ struct device *get_npe_by_id(int id)
&id, match_by_npeid);
}
-static int store_npe_image(struct dl_image *image, struct device *dev)
+int store_npe_image(struct dl_image *image, struct device *dev)
{
struct dl_block *blk;
struct dl_codeblock *cb;
struct npe_info *npe;
- int ret=0;
+ int ret = 0;
+ u16 crc;
if (!dev) {
- dev = get_npe_by_id( (image->id >> 24) & 0xf);
- put_device(dev);
+ dev = get_npe_by_id(IMG_NPE(image->id));
+ if (dev)
+ put_device(dev);
+ // XXX shouldn't this put_device be outside if(!dev) ?
+ else
+ printk(KERN_ERR "npe: cannot find npe for image %x\n", IMG_NPE(image->id));
}
+
if (!dev)
return -ENODEV;
+ if (image->size > 24000) { // XXX fix max size
+ printk(KERN_ERR "npe: firmware too large\n");
+ return -EFBIG;
+ }
+
+ if (IMG_REV_MAJOR(image->id) != 2) {
+ printk(KERN_ERR "npe: only revision 2 is supported at this time\n");
+ return -EINVAL;
+ }
+
+ crc = crc16(0, (u8 *) image, IMG_SIZE(image));
+
npe = dev_get_drvdata(dev);
- if ( npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN) {
+ if (npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN) {
printk(KERN_INFO "Cowardly refusing to reload an Image "
"into the running %s\n", npe->plat->name);
return 0; /* indicate success anyway... */
@@ -173,9 +183,9 @@ static int store_npe_image(struct dl_ima
*(u32*)npe->img_info = cpu_to_be32(image->id);
npe_start(npe);
- printk(KERN_INFO "Image loaded to %s Func:%x, Rel: %x:%x, Status: %x\n",
+ printk(KERN_INFO "npe: firmware loaded to %s, func: %02x, rev: %x.%x, status: %x, crc: %x\n",
npe->plat->name, npe->img_info[1], npe->img_info[2],
- npe->img_info[3], npe_status(npe));
+ npe->img_info[3], npe_status(npe), crc);
return 0;
}
@@ -265,8 +275,7 @@ static ssize_t ucode_write(struct file *
static void npe_firmware_probe(struct device *dev)
{
-#if (defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)) \
- && defined(MODULE)
+#ifdef CONFIG_IXP4XX_NPE_FW_LOADER
const struct firmware *fw_entry;
struct npe_info *npe = dev_get_drvdata(dev);
struct dl_image *image;
@@ -388,7 +397,7 @@ static int npe_probe(struct platform_dev
npe->plat = plat;
disable_npe_irq(npe);
- if (! (npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN))
+ if (!(npe_status(npe) & IX_NPEDL_EXCTL_STATUS_RUN))
npe_firmware_probe(&pdev->dev);
return 0;
@@ -464,3 +473,4 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Hohnstaedt <chohnstaedt@innominate.com>");
EXPORT_SYMBOL(get_npe_by_id);
+EXPORT_SYMBOL(store_npe_image);
Index: linux-2.6.19/include/asm-arm/arch-ixp4xx/platform.h
===================================================================
--- linux-2.6.19.orig/include/asm-arm/arch-ixp4xx/platform.h
+++ linux-2.6.19/include/asm-arm/arch-ixp4xx/platform.h
@@ -86,6 +86,20 @@ struct ixp4xx_i2c_pins {
unsigned long scl_pin;
};
+struct dl_block {
+ u32 type;
+ u32 offset;
+};
+
+struct dl_image {
+ u32 magic;
+ u32 id;
+ u32 size;
+ union {
+ u32 data[0];
+ struct dl_block block[0];
+ } u;
+};
struct npe_plat_data {
const char *name;
int data_size;
@@ -103,6 +117,9 @@ struct mac_plat_info {
unsigned char hwaddr[6]; /* Desired hardware address */
};
+struct npe_ucode_platform_data {
+ unsigned char *mtd_partition;
+};
struct sys_timer;
Index: linux-2.6.19/include/linux/ixp_npe.h
===================================================================
--- linux-2.6.19.orig/include/linux/ixp_npe.h
+++ linux-2.6.19/include/linux/ixp_npe.h
@@ -71,6 +71,7 @@ static inline u32 npe_read_ecs_reg(struc
}
extern struct device *get_npe_by_id(int id);
+extern int store_npe_image(struct dl_image *image, struct device *dev);
/* NPE Messages */
extern int
|