Path: blob/master/arch/arm/mach-ixp4xx/ixp4xx_npe.c
10817 views
/*1* Intel IXP4xx Network Processor Engine driver for Linux2*3* Copyright (C) 2007 Krzysztof Halasa <[email protected]>4*5* This program is free software; you can redistribute it and/or modify it6* under the terms of version 2 of the GNU General Public License7* as published by the Free Software Foundation.8*9* The code is based on publicly available information:10* - Intel IXP4xx Developer's Manual and other e-papers11* - Intel IXP400 Access Library Software (BSD license)12* - previous works by Christian Hohnstaedt <[email protected]>13* Thanks, Christian.14*/1516#include <linux/delay.h>17#include <linux/dma-mapping.h>18#include <linux/firmware.h>19#include <linux/io.h>20#include <linux/kernel.h>21#include <linux/module.h>22#include <mach/npe.h>2324#define DEBUG_MSG 025#define DEBUG_FW 02627#define NPE_COUNT 328#define MAX_RETRIES 1000 /* microseconds */29#define NPE_42X_DATA_SIZE 0x800 /* in dwords */30#define NPE_46X_DATA_SIZE 0x100031#define NPE_A_42X_INSTR_SIZE 0x100032#define NPE_B_AND_C_42X_INSTR_SIZE 0x80033#define NPE_46X_INSTR_SIZE 0x100034#define REGS_SIZE 0x10003536#define NPE_PHYS_REG 323738#define FW_MAGIC 0xFEEDF00D39#define FW_BLOCK_TYPE_INSTR 0x040#define FW_BLOCK_TYPE_DATA 0x141#define FW_BLOCK_TYPE_EOF 0xF4243/* NPE exec status (read) and command (write) */44#define CMD_NPE_STEP 0x0145#define CMD_NPE_START 0x0246#define CMD_NPE_STOP 0x0347#define CMD_NPE_CLR_PIPE 0x0448#define CMD_CLR_PROFILE_CNT 0x0C49#define CMD_RD_INS_MEM 0x10 /* instruction memory */50#define CMD_WR_INS_MEM 0x1151#define CMD_RD_DATA_MEM 0x12 /* data memory */52#define CMD_WR_DATA_MEM 0x1353#define CMD_RD_ECS_REG 0x14 /* exec access register */54#define CMD_WR_ECS_REG 0x155556#define STAT_RUN 0x8000000057#define STAT_STOP 0x4000000058#define STAT_CLEAR 0x2000000059#define STAT_ECS_K 0x00800000 /* pipeline clean */6061#define NPE_STEVT 0x1B62#define NPE_STARTPC 0x1C63#define NPE_REGMAP 0x1E64#define NPE_CINDEX 0x1F6566#define INSTR_WR_REG_SHORT 0x0000C00067#define INSTR_WR_REG_BYTE 0x0000400068#define INSTR_RD_FIFO 0x0F88822069#define INSTR_RESET_MBOX 0x0FAC82107071#define ECS_BG_CTXT_REG_0 0x00 /* Background Executing Context */72#define ECS_BG_CTXT_REG_1 0x01 /* Stack level */73#define ECS_BG_CTXT_REG_2 0x0274#define ECS_PRI_1_CTXT_REG_0 0x04 /* Priority 1 Executing Context */75#define ECS_PRI_1_CTXT_REG_1 0x05 /* Stack level */76#define ECS_PRI_1_CTXT_REG_2 0x0677#define ECS_PRI_2_CTXT_REG_0 0x08 /* Priority 2 Executing Context */78#define ECS_PRI_2_CTXT_REG_1 0x09 /* Stack level */79#define ECS_PRI_2_CTXT_REG_2 0x0A80#define ECS_DBG_CTXT_REG_0 0x0C /* Debug Executing Context */81#define ECS_DBG_CTXT_REG_1 0x0D /* Stack level */82#define ECS_DBG_CTXT_REG_2 0x0E83#define ECS_INSTRUCT_REG 0x11 /* NPE Instruction Register */8485#define ECS_REG_0_ACTIVE 0x80000000 /* all levels */86#define ECS_REG_0_NEXTPC_MASK 0x1FFF0000 /* BG/PRI1/PRI2 levels */87#define ECS_REG_0_LDUR_BITS 888#define ECS_REG_0_LDUR_MASK 0x00000700 /* all levels */89#define ECS_REG_1_CCTXT_BITS 1690#define ECS_REG_1_CCTXT_MASK 0x000F0000 /* all levels */91#define ECS_REG_1_SELCTXT_BITS 092#define ECS_REG_1_SELCTXT_MASK 0x0000000F /* all levels */93#define ECS_DBG_REG_2_IF 0x00100000 /* debug level */94#define ECS_DBG_REG_2_IE 0x00080000 /* debug level */9596/* NPE watchpoint_fifo register bit */97#define WFIFO_VALID 0x800000009899/* NPE messaging_status register bit definitions */100#define MSGSTAT_OFNE 0x00010000 /* OutFifoNotEmpty */101#define MSGSTAT_IFNF 0x00020000 /* InFifoNotFull */102#define MSGSTAT_OFNF 0x00040000 /* OutFifoNotFull */103#define MSGSTAT_IFNE 0x00080000 /* InFifoNotEmpty */104#define MSGSTAT_MBINT 0x00100000 /* Mailbox interrupt */105#define MSGSTAT_IFINT 0x00200000 /* InFifo interrupt */106#define MSGSTAT_OFINT 0x00400000 /* OutFifo interrupt */107#define MSGSTAT_WFINT 0x00800000 /* WatchFifo interrupt */108109/* NPE messaging_control register bit definitions */110#define MSGCTL_OUT_FIFO 0x00010000 /* enable output FIFO */111#define MSGCTL_IN_FIFO 0x00020000 /* enable input FIFO */112#define MSGCTL_OUT_FIFO_WRITE 0x01000000 /* enable FIFO + WRITE */113#define MSGCTL_IN_FIFO_WRITE 0x02000000114115/* NPE mailbox_status value for reset */116#define RESET_MBOX_STAT 0x0000F0F0117118const char *npe_names[] = { "NPE-A", "NPE-B", "NPE-C" };119120#define print_npe(pri, npe, fmt, ...) \121printk(pri "%s: " fmt, npe_name(npe), ## __VA_ARGS__)122123#if DEBUG_MSG124#define debug_msg(npe, fmt, ...) \125print_npe(KERN_DEBUG, npe, fmt, ## __VA_ARGS__)126#else127#define debug_msg(npe, fmt, ...)128#endif129130static struct {131u32 reg, val;132} ecs_reset[] = {133{ ECS_BG_CTXT_REG_0, 0xA0000000 },134{ ECS_BG_CTXT_REG_1, 0x01000000 },135{ ECS_BG_CTXT_REG_2, 0x00008000 },136{ ECS_PRI_1_CTXT_REG_0, 0x20000080 },137{ ECS_PRI_1_CTXT_REG_1, 0x01000000 },138{ ECS_PRI_1_CTXT_REG_2, 0x00008000 },139{ ECS_PRI_2_CTXT_REG_0, 0x20000080 },140{ ECS_PRI_2_CTXT_REG_1, 0x01000000 },141{ ECS_PRI_2_CTXT_REG_2, 0x00008000 },142{ ECS_DBG_CTXT_REG_0, 0x20000000 },143{ ECS_DBG_CTXT_REG_1, 0x00000000 },144{ ECS_DBG_CTXT_REG_2, 0x001E0000 },145{ ECS_INSTRUCT_REG, 0x1003C00F },146};147148static struct npe npe_tab[NPE_COUNT] = {149{150.id = 0,151.regs = (struct npe_regs __iomem *)IXP4XX_NPEA_BASE_VIRT,152.regs_phys = IXP4XX_NPEA_BASE_PHYS,153}, {154.id = 1,155.regs = (struct npe_regs __iomem *)IXP4XX_NPEB_BASE_VIRT,156.regs_phys = IXP4XX_NPEB_BASE_PHYS,157}, {158.id = 2,159.regs = (struct npe_regs __iomem *)IXP4XX_NPEC_BASE_VIRT,160.regs_phys = IXP4XX_NPEC_BASE_PHYS,161}162};163164int npe_running(struct npe *npe)165{166return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;167}168169static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)170{171__raw_writel(data, &npe->regs->exec_data);172__raw_writel(addr, &npe->regs->exec_addr);173__raw_writel(cmd, &npe->regs->exec_status_cmd);174}175176static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)177{178__raw_writel(addr, &npe->regs->exec_addr);179__raw_writel(cmd, &npe->regs->exec_status_cmd);180/* Iintroduce extra read cycles after issuing read command to NPE181so that we read the register after the NPE has updated it.182This is to overcome race condition between XScale and NPE */183__raw_readl(&npe->regs->exec_data);184__raw_readl(&npe->regs->exec_data);185return __raw_readl(&npe->regs->exec_data);186}187188static void npe_clear_active(struct npe *npe, u32 reg)189{190u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);191npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);192}193194static void npe_start(struct npe *npe)195{196/* ensure only Background Context Stack Level is active */197npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);198npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);199npe_clear_active(npe, ECS_DBG_CTXT_REG_0);200201__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);202__raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);203}204205static void npe_stop(struct npe *npe)206{207__raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);208__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/209}210211static int __must_check npe_debug_instr(struct npe *npe, u32 instr, u32 ctx,212u32 ldur)213{214u32 wc;215int i;216217/* set the Active bit, and the LDUR, in the debug level */218npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,219ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));220221/* set CCTXT at ECS DEBUG L3 to specify in which context to execute222the instruction, and set SELCTXT at ECS DEBUG Level to specify223which context store to access.224Debug ECS Level Reg 1 has form 0x000n000n, where n = context number225*/226npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,227(ctx << ECS_REG_1_CCTXT_BITS) |228(ctx << ECS_REG_1_SELCTXT_BITS));229230/* clear the pipeline */231__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);232233/* load NPE instruction into the instruction register */234npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);235236/* we need this value later to wait for completion of NPE execution237step */238wc = __raw_readl(&npe->regs->watch_count);239240/* issue a Step One command via the Execution Control register */241__raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);242243/* Watch Count register increments when NPE completes an instruction */244for (i = 0; i < MAX_RETRIES; i++) {245if (wc != __raw_readl(&npe->regs->watch_count))246return 0;247udelay(1);248}249250print_npe(KERN_ERR, npe, "reset: npe_debug_instr(): timeout\n");251return -ETIMEDOUT;252}253254static int __must_check npe_logical_reg_write8(struct npe *npe, u32 addr,255u8 val, u32 ctx)256{257/* here we build the NPE assembler instruction: mov8 d0, #0 */258u32 instr = INSTR_WR_REG_BYTE | /* OpCode */259addr << 9 | /* base Operand */260(val & 0x1F) << 4 | /* lower 5 bits to immediate data */261(val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */262return npe_debug_instr(npe, instr, ctx, 1); /* execute it */263}264265static int __must_check npe_logical_reg_write16(struct npe *npe, u32 addr,266u16 val, u32 ctx)267{268/* here we build the NPE assembler instruction: mov16 d0, #0 */269u32 instr = INSTR_WR_REG_SHORT | /* OpCode */270addr << 9 | /* base Operand */271(val & 0x1F) << 4 | /* lower 5 bits to immediate data */272(val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */273return npe_debug_instr(npe, instr, ctx, 1); /* execute it */274}275276static int __must_check npe_logical_reg_write32(struct npe *npe, u32 addr,277u32 val, u32 ctx)278{279/* write in 16 bit steps first the high and then the low value */280if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))281return -ETIMEDOUT;282return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);283}284285static int npe_reset(struct npe *npe)286{287u32 val, ctl, exec_count, ctx_reg2;288int i;289290ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &2910x3F3FFFFF;292293/* disable parity interrupt */294__raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);295296/* pre exec - debug instruction */297/* turn off the halt bit by clearing Execution Count register. */298exec_count = __raw_readl(&npe->regs->exec_count);299__raw_writel(0, &npe->regs->exec_count);300/* ensure that IF and IE are on (temporarily), so that we don't end up301stepping forever */302ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);303npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |304ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);305306/* clear the FIFOs */307while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)308;309while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)310/* read from the outFIFO until empty */311print_npe(KERN_DEBUG, npe, "npe_reset: read FIFO = 0x%X\n",312__raw_readl(&npe->regs->in_out_fifo));313314while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)315/* step execution of the NPE intruction to read inFIFO using316the Debug Executing Context stack */317if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))318return -ETIMEDOUT;319320/* reset the mailbox reg from the XScale side */321__raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);322/* from NPE side */323if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))324return -ETIMEDOUT;325326/* Reset the physical registers in the NPE register file */327for (val = 0; val < NPE_PHYS_REG; val++) {328if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))329return -ETIMEDOUT;330/* address is either 0 or 4 */331if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))332return -ETIMEDOUT;333}334335/* Reset the context store = each context's Context Store registers */336337/* Context 0 has no STARTPC. Instead, this value is used to set NextPC338for Background ECS, to set where NPE starts executing code */339val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);340val &= ~ECS_REG_0_NEXTPC_MASK;341val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;342npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);343344for (i = 0; i < 16; i++) {345if (i) { /* Context 0 has no STEVT nor STARTPC */346/* STEVT = off, 0x80 */347if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))348return -ETIMEDOUT;349if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))350return -ETIMEDOUT;351}352/* REGMAP = d0->p0, d8->p2, d16->p4 */353if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))354return -ETIMEDOUT;355if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))356return -ETIMEDOUT;357}358359/* post exec */360/* clear active bit in debug level */361npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);362/* clear the pipeline */363__raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);364/* restore previous values */365__raw_writel(exec_count, &npe->regs->exec_count);366npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);367368/* write reset values to Execution Context Stack registers */369for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)370npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,371ecs_reset[val].val);372373/* clear the profile counter */374__raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);375376__raw_writel(0, &npe->regs->exec_count);377__raw_writel(0, &npe->regs->action_points[0]);378__raw_writel(0, &npe->regs->action_points[1]);379__raw_writel(0, &npe->regs->action_points[2]);380__raw_writel(0, &npe->regs->action_points[3]);381__raw_writel(0, &npe->regs->watch_count);382383val = ixp4xx_read_feature_bits();384/* reset the NPE */385ixp4xx_write_feature_bits(val &386~(IXP4XX_FEATURE_RESET_NPEA << npe->id));387/* deassert reset */388ixp4xx_write_feature_bits(val |389(IXP4XX_FEATURE_RESET_NPEA << npe->id));390for (i = 0; i < MAX_RETRIES; i++) {391if (ixp4xx_read_feature_bits() &392(IXP4XX_FEATURE_RESET_NPEA << npe->id))393break; /* NPE is back alive */394udelay(1);395}396if (i == MAX_RETRIES)397return -ETIMEDOUT;398399npe_stop(npe);400401/* restore NPE configuration bus Control Register - parity settings */402__raw_writel(ctl, &npe->regs->messaging_control);403return 0;404}405406407int npe_send_message(struct npe *npe, const void *msg, const char *what)408{409const u32 *send = msg;410int cycles = 0;411412debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",413what, send[0], send[1]);414415if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {416debug_msg(npe, "NPE input FIFO not empty\n");417return -EIO;418}419420__raw_writel(send[0], &npe->regs->in_out_fifo);421422if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {423debug_msg(npe, "NPE input FIFO full\n");424return -EIO;425}426427__raw_writel(send[1], &npe->regs->in_out_fifo);428429while ((cycles < MAX_RETRIES) &&430(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {431udelay(1);432cycles++;433}434435if (cycles == MAX_RETRIES) {436debug_msg(npe, "Timeout sending message\n");437return -ETIMEDOUT;438}439440#if DEBUG_MSG > 1441debug_msg(npe, "Sending a message took %i cycles\n", cycles);442#endif443return 0;444}445446int npe_recv_message(struct npe *npe, void *msg, const char *what)447{448u32 *recv = msg;449int cycles = 0, cnt = 0;450451debug_msg(npe, "Trying to receive message %s\n", what);452453while (cycles < MAX_RETRIES) {454if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {455recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);456if (cnt == 2)457break;458} else {459udelay(1);460cycles++;461}462}463464switch(cnt) {465case 1:466debug_msg(npe, "Received [%08X]\n", recv[0]);467break;468case 2:469debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);470break;471}472473if (cycles == MAX_RETRIES) {474debug_msg(npe, "Timeout waiting for message\n");475return -ETIMEDOUT;476}477478#if DEBUG_MSG > 1479debug_msg(npe, "Receiving a message took %i cycles\n", cycles);480#endif481return 0;482}483484int npe_send_recv_message(struct npe *npe, void *msg, const char *what)485{486int result;487u32 *send = msg, recv[2];488489if ((result = npe_send_message(npe, msg, what)) != 0)490return result;491if ((result = npe_recv_message(npe, recv, what)) != 0)492return result;493494if ((recv[0] != send[0]) || (recv[1] != send[1])) {495debug_msg(npe, "Message %s: unexpected message received\n",496what);497return -EIO;498}499return 0;500}501502503int npe_load_firmware(struct npe *npe, const char *name, struct device *dev)504{505const struct firmware *fw_entry;506507struct dl_block {508u32 type;509u32 offset;510} *blk;511512struct dl_image {513u32 magic;514u32 id;515u32 size;516union {517u32 data[0];518struct dl_block blocks[0];519};520} *image;521522struct dl_codeblock {523u32 npe_addr;524u32 size;525u32 data[0];526} *cb;527528int i, j, err, data_size, instr_size, blocks, table_end;529u32 cmd;530531if ((err = request_firmware(&fw_entry, name, dev)) != 0)532return err;533534err = -EINVAL;535if (fw_entry->size < sizeof(struct dl_image)) {536print_npe(KERN_ERR, npe, "incomplete firmware file\n");537goto err;538}539image = (struct dl_image*)fw_entry->data;540541#if DEBUG_FW542print_npe(KERN_DEBUG, npe, "firmware: %08X %08X %08X (0x%X bytes)\n",543image->magic, image->id, image->size, image->size * 4);544#endif545546if (image->magic == swab32(FW_MAGIC)) { /* swapped file */547image->id = swab32(image->id);548image->size = swab32(image->size);549} else if (image->magic != FW_MAGIC) {550print_npe(KERN_ERR, npe, "bad firmware file magic: 0x%X\n",551image->magic);552goto err;553}554if ((image->size * 4 + sizeof(struct dl_image)) != fw_entry->size) {555print_npe(KERN_ERR, npe,556"inconsistent size of firmware file\n");557goto err;558}559if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {560print_npe(KERN_ERR, npe, "firmware file NPE ID mismatch\n");561goto err;562}563if (image->magic == swab32(FW_MAGIC))564for (i = 0; i < image->size; i++)565image->data[i] = swab32(image->data[i]);566567if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {568print_npe(KERN_INFO, npe, "IXP43x/IXP46x firmware ignored on "569"IXP42x\n");570goto err;571}572573if (npe_running(npe)) {574print_npe(KERN_INFO, npe, "unable to load firmware, NPE is "575"already running\n");576err = -EBUSY;577goto err;578}579#if 0580npe_stop(npe);581npe_reset(npe);582#endif583584print_npe(KERN_INFO, npe, "firmware functionality 0x%X, "585"revision 0x%X:%X\n", (image->id >> 16) & 0xFF,586(image->id >> 8) & 0xFF, image->id & 0xFF);587588if (cpu_is_ixp42x()) {589if (!npe->id)590instr_size = NPE_A_42X_INSTR_SIZE;591else592instr_size = NPE_B_AND_C_42X_INSTR_SIZE;593data_size = NPE_42X_DATA_SIZE;594} else {595instr_size = NPE_46X_INSTR_SIZE;596data_size = NPE_46X_DATA_SIZE;597}598599for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;600blocks++)601if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)602break;603if (blocks * sizeof(struct dl_block) / 4 >= image->size) {604print_npe(KERN_INFO, npe, "firmware EOF block marker not "605"found\n");606goto err;607}608609#if DEBUG_FW610print_npe(KERN_DEBUG, npe, "%i firmware blocks found\n", blocks);611#endif612613table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;614for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {615if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4616|| blk->offset < table_end) {617print_npe(KERN_INFO, npe, "invalid offset 0x%X of "618"firmware block #%i\n", blk->offset, i);619goto err;620}621622cb = (struct dl_codeblock*)&image->data[blk->offset];623if (blk->type == FW_BLOCK_TYPE_INSTR) {624if (cb->npe_addr + cb->size > instr_size)625goto too_big;626cmd = CMD_WR_INS_MEM;627} else if (blk->type == FW_BLOCK_TYPE_DATA) {628if (cb->npe_addr + cb->size > data_size)629goto too_big;630cmd = CMD_WR_DATA_MEM;631} else {632print_npe(KERN_INFO, npe, "invalid firmware block #%i "633"type 0x%X\n", i, blk->type);634goto err;635}636if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {637print_npe(KERN_INFO, npe, "firmware block #%i doesn't "638"fit in firmware image: type %c, start 0x%X,"639" length 0x%X\n", i,640blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',641cb->npe_addr, cb->size);642goto err;643}644645for (j = 0; j < cb->size; j++)646npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);647}648649npe_start(npe);650if (!npe_running(npe))651print_npe(KERN_ERR, npe, "unable to start\n");652release_firmware(fw_entry);653return 0;654655too_big:656print_npe(KERN_INFO, npe, "firmware block #%i doesn't fit in NPE "657"memory: type %c, start 0x%X, length 0x%X\n", i,658blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',659cb->npe_addr, cb->size);660err:661release_firmware(fw_entry);662return err;663}664665666struct npe *npe_request(unsigned id)667{668if (id < NPE_COUNT)669if (npe_tab[id].valid)670if (try_module_get(THIS_MODULE))671return &npe_tab[id];672return NULL;673}674675void npe_release(struct npe *npe)676{677module_put(THIS_MODULE);678}679680681static int __init npe_init_module(void)682{683684int i, found = 0;685686for (i = 0; i < NPE_COUNT; i++) {687struct npe *npe = &npe_tab[i];688if (!(ixp4xx_read_feature_bits() &689(IXP4XX_FEATURE_RESET_NPEA << i)))690continue; /* NPE already disabled or not present */691if (!(npe->mem_res = request_mem_region(npe->regs_phys,692REGS_SIZE,693npe_name(npe)))) {694print_npe(KERN_ERR, npe,695"failed to request memory region\n");696continue;697}698699if (npe_reset(npe))700continue;701npe->valid = 1;702found++;703}704705if (!found)706return -ENODEV;707return 0;708}709710static void __exit npe_cleanup_module(void)711{712int i;713714for (i = 0; i < NPE_COUNT; i++)715if (npe_tab[i].mem_res) {716npe_reset(&npe_tab[i]);717release_resource(npe_tab[i].mem_res);718}719}720721module_init(npe_init_module);722module_exit(npe_cleanup_module);723724MODULE_AUTHOR("Krzysztof Halasa");725MODULE_LICENSE("GPL v2");726727EXPORT_SYMBOL(npe_names);728EXPORT_SYMBOL(npe_running);729EXPORT_SYMBOL(npe_request);730EXPORT_SYMBOL(npe_release);731EXPORT_SYMBOL(npe_load_firmware);732EXPORT_SYMBOL(npe_send_message);733EXPORT_SYMBOL(npe_recv_message);734EXPORT_SYMBOL(npe_send_recv_message);735736737