--- drivers/net/ixp4xx/Kconfig | 10 + drivers/net/ixp4xx/Makefile | 1 drivers/net/ixp4xx/npe_ucode.c | 185 +++++++++++++++++++++++++++++++++ drivers/net/ixp4xx/ucode_dl.c | 43 ++++--- include/asm-arm/arch-ixp4xx/platform.h | 19 +++ include/linux/ixp_npe.h | 1 6 files changed, 239 insertions(+), 20 deletions(-) Index: linux-2.6.21.7/drivers/net/ixp4xx/Kconfig =================================================================== --- linux-2.6.21.7.orig/drivers/net/ixp4xx/Kconfig +++ linux-2.6.21.7/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.21.7/drivers/net/ixp4xx/Makefile =================================================================== --- linux-2.6.21.7.orig/drivers/net/ixp4xx/Makefile +++ linux-2.6.21.7/drivers/net/ixp4xx/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o obj-$(CONFIG_IXP4XX_NPE) += ixp4xx_npe.o +obj-$(CONFIG_IXP4XX_NPE_FW_MTD) += npe_ucode.o obj-$(CONFIG_IXP4XX_MAC) += ixp4xx_mac.o obj-$(CONFIG_IXP4XX_CRYPTO) += ixp4xx_crypto.o Index: linux-2.6.21.7/drivers/net/ixp4xx/npe_ucode.c =================================================================== --- /dev/null +++ linux-2.6.21.7/drivers/net/ixp4xx/npe_ucode.c @@ -0,0 +1,185 @@ +/* + * Provide an NPE platform device for microcode handling + * + * Copyright (C) 2006 Christian Hohnstaedt + * + * This file is released under the GPLv2 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#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) || IMG_FUNC(id) == 0x05 ) { // 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 "); Index: linux-2.6.21.7/drivers/net/ixp4xx/ucode_dl.c =================================================================== --- linux-2.6.21.7.orig/drivers/net/ixp4xx/ucode_dl.c +++ linux-2.6.21.7/drivers/net/ixp4xx/ucode_dl.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,12 @@ #define DL_MAGIC 0xfeedf00d #define DL_MAGIC_SWAP 0x0df0edfe +#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 EOF_BLOCK 0xf #define IMG_SIZE(image) (((image)->size * sizeof(u32)) + \ sizeof(struct dl_image)) @@ -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; @@ -127,20 +119,33 @@ download_block(struct npe_info *npe, str return 0; } -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; + u16 crc; if (!dev) { - dev = get_npe_by_id( (image->id >> 24) & 0xf); + dev = get_npe_by_id(IMG_NPE(image->id)); return_npe_dev(dev); } 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->loaded && (npe->usage > 0)) { printk(KERN_INFO "Cowardly refusing to reload an Image " @@ -267,8 +272,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; @@ -477,3 +481,4 @@ MODULE_AUTHOR("Christian Hohnstaedt