+++ /dev/null
-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
-@@ -100,6 +100,7 @@ struct mac_plat_info {
- int phy_id; /* ID of the connected PHY (PCB/platform dependent) */
- int rxq_id; /* Queue ID of the RX-free q*/
- int txq_id; /* Where to push the outgoing packets */
-+ unsigned char hwaddr[6]; /* Desired hardware address */
- };
-
-
-Index: linux-2.6.19/drivers/net/ixp4xx/mac_driver.c
-===================================================================
---- linux-2.6.19.orig/drivers/net/ixp4xx/mac_driver.c
-+++ linux-2.6.19/drivers/net/ixp4xx/mac_driver.c
-@@ -189,6 +189,24 @@ static int ixmac_open (struct net_device
- }
- mac->rxq_pkt += RX_QUEUE_PREFILL;
-
-+ /* printk(KERN_INFO "...Platform MAC=0x%02x%02x%02x%02x%02x%02x\n",
-+ mac->plat->hwaddr[0],
-+ mac->plat->hwaddr[1],
-+ mac->plat->hwaddr[2],
-+ mac->plat->hwaddr[3],
-+ mac->plat->hwaddr[4],
-+ mac->plat->hwaddr[5]
-+ ); */
-+ /* Only use platform or random if there's currently no device hw addr */
-+ if (is_zero_ether_addr(dev->dev_addr)) {
-+ if (is_zero_ether_addr(mac->plat->hwaddr)) {
-+ random_ether_addr(dev->dev_addr);
-+ dev->dev_addr[5] = mac->plat->phy_id;
-+ }
-+ else
-+ memcpy(dev->dev_addr, mac->plat->hwaddr, 6);
-+ }
-+
- mac_init(mac);
- npe_mh_set_rxqid(npe, mac->plat, RX_DONE_QID);
- mac_set_uniaddr(dev);
-@@ -434,9 +452,15 @@ static int mac_probe(struct platform_dev
- * following commands:
- * "ip link set address 02:03:04:04:04:01 dev eth0"
- * "ifconfig eth0 hw ether 02:03:04:04:04:07"
-- */
-- random_ether_addr(dev->dev_addr);
-- dev->dev_addr[5] = plat->phy_id;
-+ */
-+/* Note: moved to ixmac_open to allow notifiers to run for compiled in modules
-+ if (is_zero_ether_addr(plat->hwaddr)) {
-+ random_ether_addr(dev->dev_addr);
-+ dev->dev_addr[5] = plat->phy_id;
-+ }
-+ else
-+ memcpy(dev->dev_addr, plat->hwaddr, 6);
-+*/
-
- printk(KERN_INFO IXMAC_NAME " driver " IXMAC_VERSION
- ": %s on %s with PHY[%d] initialized\n",
--- /dev/null
+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
+@@ -100,6 +100,7 @@ struct mac_plat_info {
+ int phy_id; /* ID of the connected PHY (PCB/platform dependent) */
+ int rxq_id; /* Queue ID of the RX-free q*/
+ int txq_id; /* Where to push the outgoing packets */
++ unsigned char hwaddr[6]; /* Desired hardware address */
+ };
+
+
+Index: linux-2.6.19/drivers/net/ixp4xx/mac_driver.c
+===================================================================
+--- linux-2.6.19.orig/drivers/net/ixp4xx/mac_driver.c
++++ linux-2.6.19/drivers/net/ixp4xx/mac_driver.c
+@@ -189,6 +189,24 @@ static int ixmac_open (struct net_device
+ }
+ mac->rxq_pkt += RX_QUEUE_PREFILL;
+
++ /* printk(KERN_INFO "...Platform MAC=0x%02x%02x%02x%02x%02x%02x\n",
++ mac->plat->hwaddr[0],
++ mac->plat->hwaddr[1],
++ mac->plat->hwaddr[2],
++ mac->plat->hwaddr[3],
++ mac->plat->hwaddr[4],
++ mac->plat->hwaddr[5]
++ ); */
++ /* Only use platform or random if there's currently no device hw addr */
++ if (is_zero_ether_addr(dev->dev_addr)) {
++ if (is_zero_ether_addr(mac->plat->hwaddr)) {
++ random_ether_addr(dev->dev_addr);
++ dev->dev_addr[5] = mac->plat->phy_id;
++ }
++ else
++ memcpy(dev->dev_addr, mac->plat->hwaddr, 6);
++ }
++
+ mac_init(mac);
+ npe_mh_set_rxqid(npe, mac->plat, RX_DONE_QID);
+ mac_set_uniaddr(dev);
+@@ -434,9 +452,15 @@ static int mac_probe(struct platform_dev
+ * following commands:
+ * "ip link set address 02:03:04:04:04:01 dev eth0"
+ * "ifconfig eth0 hw ether 02:03:04:04:04:07"
+- */
+- random_ether_addr(dev->dev_addr);
+- dev->dev_addr[5] = plat->phy_id;
++ */
++/* Note: moved to ixmac_open to allow notifiers to run for compiled in modules
++ if (is_zero_ether_addr(plat->hwaddr)) {
++ random_ether_addr(dev->dev_addr);
++ dev->dev_addr[5] = plat->phy_id;
++ }
++ else
++ memcpy(dev->dev_addr, plat->hwaddr, 6);
++*/
+
+ printk(KERN_INFO IXMAC_NAME " driver " IXMAC_VERSION
+ ": %s on %s with PHY[%d] initialized\n",
+++ /dev/null
-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
--- /dev/null
+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
+++ /dev/null
----
- arch/arm/mach-ixp4xx/nas100d-setup.c | 27 +++++++++++++++++++++++++++
- 1 file changed, 27 insertions(+)
-
-Index: linux-2.6.19/arch/arm/mach-ixp4xx/nas100d-setup.c
-===================================================================
---- linux-2.6.19.orig/arch/arm/mach-ixp4xx/nas100d-setup.c
-+++ linux-2.6.19/arch/arm/mach-ixp4xx/nas100d-setup.c
-@@ -16,6 +16,7 @@
- #include <linux/serial.h>
- #include <linux/serial_8250.h>
- #include <linux/leds.h>
-+#include <linux/mtd/mtd.h>
-
- #include <asm/mach-types.h>
- #include <asm/mach/arch.h>
-@@ -165,6 +166,30 @@ static struct platform_device *nas100d_d
- &nas100d_npe_ucode,
- };
-
-+static void nas100d_flash_add(struct mtd_info *mtd)
-+{
-+ if (strcmp(mtd->name, "RedBoot config") == 0) {
-+ size_t retlen;
-+ u_char mac[6];
-+
-+ if (mtd->read(mtd, 0x0FD8, 6, &retlen, mac) == 0 && retlen == 6) {
-+ printk(KERN_INFO "nas100d mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-+ memcpy(plat_mac0.hwaddr, mac, 6);
-+ } else {
-+ printk(KERN_ERR "nas100d mac: read failed\n");
-+ }
-+ }
-+}
-+
-+static void nas100d_flash_remove(struct mtd_info *mtd) {
-+}
-+
-+static struct mtd_notifier nas100d_flash_notifier = {
-+ .add = nas100d_flash_add,
-+ .remove = nas100d_flash_remove,
-+};
-+
- static void nas100d_power_off(void)
- {
- /* This causes the box to drop the power and go dead. */
-@@ -196,6 +221,8 @@ static void __init nas100d_init(void)
- (void)platform_device_register(&nas100d_uart);
-
- platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
-+
-+ register_mtd_user(&nas100d_flash_notifier);
- }
-
- MACHINE_START(NAS100D, "Iomega NAS 100d")
--- /dev/null
+---
+ arch/arm/mach-ixp4xx/nas100d-setup.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+Index: linux-2.6.19/arch/arm/mach-ixp4xx/nas100d-setup.c
+===================================================================
+--- linux-2.6.19.orig/arch/arm/mach-ixp4xx/nas100d-setup.c
++++ linux-2.6.19/arch/arm/mach-ixp4xx/nas100d-setup.c
+@@ -16,6 +16,7 @@
+ #include <linux/serial.h>
+ #include <linux/serial_8250.h>
+ #include <linux/leds.h>
++#include <linux/mtd/mtd.h>
+
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+@@ -165,6 +166,30 @@ static struct platform_device *nas100d_d
+ &nas100d_npe_ucode,
+ };
+
++static void nas100d_flash_add(struct mtd_info *mtd)
++{
++ if (strcmp(mtd->name, "RedBoot config") == 0) {
++ size_t retlen;
++ u_char mac[6];
++
++ if (mtd->read(mtd, 0x0FD8, 6, &retlen, mac) == 0 && retlen == 6) {
++ printk(KERN_INFO "nas100d mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++ memcpy(plat_mac0.hwaddr, mac, 6);
++ } else {
++ printk(KERN_ERR "nas100d mac: read failed\n");
++ }
++ }
++}
++
++static void nas100d_flash_remove(struct mtd_info *mtd) {
++}
++
++static struct mtd_notifier nas100d_flash_notifier = {
++ .add = nas100d_flash_add,
++ .remove = nas100d_flash_remove,
++};
++
+ static void nas100d_power_off(void)
+ {
+ /* This causes the box to drop the power and go dead. */
+@@ -196,6 +221,8 @@ static void __init nas100d_init(void)
+ (void)platform_device_register(&nas100d_uart);
+
+ platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
++
++ register_mtd_user(&nas100d_flash_notifier);
+ }
+
+ MACHINE_START(NAS100D, "Iomega NAS 100d")