ixp425_npe.c revision 186420
1255570Strasz/*- 2255570Strasz * Copyright (c) 2006-2008 Sam Leffler, Errno Consulting 3255570Strasz * All rights reserved. 4255570Strasz * 5255570Strasz * Redistribution and use in source and binary forms, with or without 6255570Strasz * modification, are permitted provided that the following conditions 7255570Strasz * are met: 8255570Strasz * 1. Redistributions of source code must retain the above copyright 9255570Strasz * notice, this list of conditions and the following disclaimer, 10255570Strasz * without modification. 11255570Strasz * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12255570Strasz * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13255570Strasz * redistribution must be conditioned upon including a substantially 14255570Strasz * similar Disclaimer requirement for further binary redistribution. 15255570Strasz * 16255570Strasz * NO WARRANTY 17255570Strasz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18255570Strasz * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19255570Strasz * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20255570Strasz * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21255570Strasz * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22255570Strasz * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23255570Strasz * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24255570Strasz * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25255570Strasz * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26255570Strasz * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27255570Strasz * THE POSSIBILITY OF SUCH DAMAGES. 28255570Strasz */ 29255570Strasz 30255570Strasz/*- 31255570Strasz * Copyright (c) 2001-2005, Intel Corporation. 32255570Strasz * All rights reserved. 33255570Strasz * 34255570Strasz * Redistribution and use in source and binary forms, with or without 35255570Strasz * modification, are permitted provided that the following conditions 36255570Strasz * are met: 37255570Strasz * 1. Redistributions of source code must retain the above copyright 38255570Strasz * notice, this list of conditions and the following disclaimer. 39255570Strasz * 2. Redistributions in binary form must reproduce the above copyright 40255570Strasz * notice, this list of conditions and the following disclaimer in the 41255570Strasz * documentation and/or other materials provided with the distribution. 42255570Strasz * 3. Neither the name of the Intel Corporation nor the names of its contributors 43255570Strasz * may be used to endorse or promote products derived from this software 44255570Strasz * without specific prior written permission. 45255570Strasz * 46255570Strasz * 47255570Strasz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 48255570Strasz * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50255570Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 51255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57255570Strasz * SUCH DAMAGE. 58255570Strasz*/ 59255570Strasz#include <sys/cdefs.h> 60263724Strasz__FBSDID("$FreeBSD: head/sys/arm/xscale/ixp425/ixp425_npe.c 186420 2008-12-23 04:51:46Z sam $"); 61275244Strasz 62275247Strasz/* 63275247Strasz * Intel XScale Network Processing Engine (NPE) support. 64275642Strasz * 65275642Strasz * Each NPE has an ixpnpeX device associated with it that is 66255570Strasz * attached at boot. Depending on the microcode loaded into 67255570Strasz * an NPE there may be an Ethernet interface (npeX) or some 68255570Strasz * other network interface (e.g. for ATM). This file has support 69255570Strasz * for loading microcode images and the associated NPE CPU 70255570Strasz * manipulations (start, stop, reset). 71255570Strasz * 72255570Strasz * The code here basically replaces the npeDl and npeMh classes 73255570Strasz * in the Intel Access Library (IAL). 74255570Strasz * 75255570Strasz * NB: Microcode images are loaded with firmware(9). To 76255570Strasz * include microcode in a static kernel include the 77255570Strasz * ixpnpe_fw device. Otherwise the firmware will be 78255570Strasz * automatically loaded from the filesystem. 79275246Strasz */ 80275246Strasz#include <sys/param.h> 81255570Strasz#include <sys/systm.h> 82255570Strasz#include <sys/kernel.h> 83255570Strasz#include <sys/malloc.h> 84263722Strasz#include <sys/module.h> 85255570Strasz#include <sys/time.h> 86263722Strasz#include <sys/bus.h> 87255570Strasz#include <sys/resource.h> 88263722Strasz#include <sys/rman.h> 89255570Strasz#include <sys/sysctl.h> 90263722Strasz 91255570Strasz#include <sys/linker.h> 92274939Smav#include <sys/firmware.h> 93274939Smav 94274939Smav#include <machine/bus.h> 95274939Smav#include <machine/cpu.h> 96274939Smav#include <machine/cpufunc.h> 97274939Smav#include <machine/resource.h> 98263722Strasz#include <machine/intr.h> 99255570Strasz#include <arm/xscale/ixp425/ixp425reg.h> 100263722Strasz#include <arm/xscale/ixp425/ixp425var.h> 101255570Strasz 102279002Smav#include <arm/xscale/ixp425/ixp425_npereg.h> 103279002Smav#include <arm/xscale/ixp425/ixp425_npevar.h> 104263722Strasz 105255570Straszstruct ixpnpe_softc { 106255570Strasz device_t sc_dev; 107275186Strasz bus_space_tag_t sc_iot; 108255570Strasz bus_space_handle_t sc_ioh; 109275186Strasz bus_size_t sc_size; /* size of mapped register window */ 110275186Strasz struct resource *sc_irq; /* IRQ resource */ 111275186Strasz void *sc_ih; /* interrupt handler */ 112275187Strasz struct mtx sc_mtx; /* mailbox lock */ 113275186Strasz uint32_t sc_msg[2]; /* reply msg collected in ixpnpe_intr */ 114275186Strasz int sc_msgwaiting; /* sc_msg holds valid data */ 115275186Strasz int sc_npeid; 116275186Strasz int sc_nrefs; /* # of references */ 117275186Strasz 118255570Strasz int validImage; /* valid ucode image loaded */ 119255570Strasz int started; /* NPE is started */ 120255570Strasz uint8_t functionalityId;/* ucode functionality ID */ 121275186Strasz int insMemSize; /* size of instruction memory */ 122255570Strasz int dataMemSize; /* size of data memory */ 123275186Strasz uint32_t savedExecCount; 124275186Strasz uint32_t savedEcsDbgCtxtReg2; 125275186Strasz}; 126275187Straszstatic struct ixpnpe_softc *npes[NPE_MAX]; 127275186Strasz 128275186Strasz#define IX_NPEDL_NPEIMAGE_FIELD_MASK 0xff 129275186Strasz 130275186Strasz/* used to read download map from version in microcode image */ 131275186Strasz#define IX_NPEDL_BLOCK_TYPE_INSTRUCTION 0x00000000 132255570Strasz#define IX_NPEDL_BLOCK_TYPE_DATA 0x00000001 133255570Strasz#define IX_NPEDL_BLOCK_TYPE_STATE 0x00000002 134255570Strasz#define IX_NPEDL_END_OF_DOWNLOAD_MAP 0x0000000F 135275186Strasz 136255570Strasz/* 137275186Strasz * masks used to extract address info from State information context 138275186Strasz * register addresses as read from microcode image 139275186Strasz */ 140275187Strasz#define IX_NPEDL_MASK_STATE_ADDR_CTXT_REG 0x0000000F 141275186Strasz#define IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM 0x000000F0 142275186Strasz 143275186Strasz/* LSB offset of Context Number field in State-Info Context Address */ 144275186Strasz#define IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM 4 145275186Strasz 146255570Strasz/* size (in words) of single State Information entry (ctxt reg address|data) */ 147255570Strasz#define IX_NPEDL_STATE_INFO_ENTRY_SIZE 2 148255570Strasz 149263722Strasztypedef struct { 150255570Strasz uint32_t type; 151255570Strasz uint32_t offset; 152255570Strasz} IxNpeDlNpeMgrDownloadMapBlockEntry; 153255570Strasz 154255570Strasztypedef union { 155255570Strasz IxNpeDlNpeMgrDownloadMapBlockEntry block; 156255570Strasz uint32_t eodmMarker; 157255570Strasz} IxNpeDlNpeMgrDownloadMapEntry; 158255570Strasz 159255570Strasztypedef struct { 160274939Smav /* 1st entry in the download map (there may be more than one) */ 161274939Smav IxNpeDlNpeMgrDownloadMapEntry entry[1]; 162274939Smav} IxNpeDlNpeMgrDownloadMap; 163274939Smav 164274939Smav/* used to access an instruction or data block in a microcode image */ 165274939Smavtypedef struct { 166274939Smav uint32_t npeMemAddress; 167274939Smav uint32_t size; 168274939Smav uint32_t data[1]; 169274939Smav} IxNpeDlNpeMgrCodeBlock; 170274939Smav 171275187Strasz/* used to access each Context Reg entry state-information block */ 172274939Smavtypedef struct { 173275187Strasz uint32_t addressInfo; 174275187Strasz uint32_t value; 175275187Strasz} IxNpeDlNpeMgrStateInfoCtxtRegEntry; 176275187Strasz 177275187Strasz/* used to access a state-information block in a microcode image */ 178275187Strasztypedef struct { 179275187Strasz uint32_t size; 180275187Strasz IxNpeDlNpeMgrStateInfoCtxtRegEntry ctxtRegEntry[1]; 181275187Strasz} IxNpeDlNpeMgrStateInfoBlock; 182274939Smav 183274939Smavstatic int npe_debug = 0; 184274939SmavSYSCTL_INT(_debug, OID_AUTO, ixp425npe, CTLFLAG_RW, &npe_debug, 185275187Strasz 0, "IXP4XX NPE debug msgs"); 186274939SmavTUNABLE_INT("debug.ixp425npe", &npe_debug); 187275187Strasz#define DPRINTF(dev, fmt, ...) do { \ 188275187Strasz if (npe_debug) device_printf(dev, fmt, __VA_ARGS__); \ 189275187Strasz} while (0) 190275187Strasz#define DPRINTFn(n, dev, fmt, ...) do { \ 191275187Strasz if (npe_debug >= n) printf(fmt, __VA_ARGS__); \ 192275187Strasz} while (0) 193275187Strasz 194275187Straszstatic int npe_checkbits(struct ixpnpe_softc *, uint32_t reg, uint32_t); 195275187Straszstatic int npe_isstopped(struct ixpnpe_softc *); 196274939Smavstatic int npe_load_ins(struct ixpnpe_softc *, 197274939Smav const IxNpeDlNpeMgrCodeBlock *bp, int verify); 198274939Smavstatic int npe_load_data(struct ixpnpe_softc *, 199263722Strasz const IxNpeDlNpeMgrCodeBlock *bp, int verify); 200255570Straszstatic int npe_load_stateinfo(struct ixpnpe_softc *, 201255570Strasz const IxNpeDlNpeMgrStateInfoBlock *bp, int verify); 202255570Straszstatic int npe_load_image(struct ixpnpe_softc *, 203255570Strasz const uint32_t *imageCodePtr, int verify); 204255570Straszstatic int npe_cpu_reset(struct ixpnpe_softc *); 205255570Straszstatic int npe_cpu_start(struct ixpnpe_softc *); 206255570Straszstatic int npe_cpu_stop(struct ixpnpe_softc *); 207255570Straszstatic void npe_cmd_issue_write(struct ixpnpe_softc *, 208263726Strasz uint32_t cmd, uint32_t addr, uint32_t data); 209263726Straszstatic uint32_t npe_cmd_issue_read(struct ixpnpe_softc *, 210263726Strasz uint32_t cmd, uint32_t addr); 211263726Straszstatic int npe_ins_write(struct ixpnpe_softc *, 212263726Strasz uint32_t addr, uint32_t data, int verify); 213263726Straszstatic int npe_data_write(struct ixpnpe_softc *, 214263726Strasz uint32_t addr, uint32_t data, int verify); 215263726Straszstatic void npe_ecs_reg_write(struct ixpnpe_softc *, 216263726Strasz uint32_t reg, uint32_t data); 217263726Straszstatic uint32_t npe_ecs_reg_read(struct ixpnpe_softc *, uint32_t reg); 218263726Straszstatic void npe_issue_cmd(struct ixpnpe_softc *, uint32_t command); 219255570Straszstatic void npe_cpu_step_save(struct ixpnpe_softc *); 220255570Straszstatic int npe_cpu_step(struct ixpnpe_softc *, uint32_t npeInstruction, 221255570Strasz uint32_t ctxtNum, uint32_t ldur); 222255570Straszstatic void npe_cpu_step_restore(struct ixpnpe_softc *); 223255570Straszstatic int npe_logical_reg_read(struct ixpnpe_softc *, 224255570Strasz uint32_t regAddr, uint32_t regSize, 225255570Strasz uint32_t ctxtNum, uint32_t *regVal); 226255570Straszstatic int npe_logical_reg_write(struct ixpnpe_softc *, 227255570Strasz uint32_t regAddr, uint32_t regVal, 228275246Strasz uint32_t regSize, uint32_t ctxtNum, int verify); 229275246Straszstatic int npe_physical_reg_write(struct ixpnpe_softc *, 230255570Strasz uint32_t regAddr, uint32_t regValue, int verify); 231255570Straszstatic int npe_ctx_reg_write(struct ixpnpe_softc *, uint32_t ctxtNum, 232255570Strasz uint32_t ctxtReg, uint32_t ctxtRegVal, int verify); 233263724Strasz 234263724Straszstatic void ixpnpe_intr(void *arg); 235255570Strasz 236255570Straszstatic uint32_t 237255570Strasznpe_reg_read(struct ixpnpe_softc *sc, bus_size_t off) 238263720Strasz{ 239263720Strasz uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); 240263720Strasz DPRINTFn(9, sc->sc_dev, "%s(0x%lx) => 0x%x\n", __func__, off, v); 241263720Strasz return v; 242255570Strasz} 243255570Strasz 244263724Straszstatic void 245263724Strasznpe_reg_write(struct ixpnpe_softc *sc, bus_size_t off, uint32_t val) 246263724Strasz{ 247263724Strasz DPRINTFn(9, sc->sc_dev, "%s(0x%lx, 0x%x)\n", __func__, off, val); 248275245Strasz bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val); 249263724Strasz} 250263724Strasz 251263724Straszstruct ixpnpe_softc * 252263724Straszixpnpe_attach(device_t dev, int npeid) 253263724Strasz{ 254263724Strasz struct npeconfig { 255255570Strasz uint32_t base; 256255570Strasz uint32_t size; 257255570Strasz int irq; 258255570Strasz uint32_t ins_memsize; 259255570Strasz uint32_t data_memsize; 260255570Strasz }; 261255570Strasz static const struct npeconfig npeconfigs[NPE_MAX] = { 262255570Strasz [NPE_A] = { 263255570Strasz .base = IXP425_NPE_A_HWBASE, 264255570Strasz .size = IXP425_NPE_A_SIZE, 265255570Strasz .irq = IXP425_INT_NPE_A, 266255570Strasz .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEA, 267255570Strasz .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEA 268255570Strasz }, 269255570Strasz [NPE_B] = { 270255570Strasz .base = IXP425_NPE_B_HWBASE, 271255570Strasz .size = IXP425_NPE_B_SIZE, 272255570Strasz .irq = IXP425_INT_NPE_B, 273255570Strasz .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEB, 274255570Strasz .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB 275255570Strasz }, 276255570Strasz [NPE_C] = { 277255570Strasz .base = IXP425_NPE_C_HWBASE, 278255570Strasz .size = IXP425_NPE_C_SIZE, 279255570Strasz .irq = IXP425_INT_NPE_C, 280255570Strasz .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEC, 281263720Strasz .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC 282263720Strasz }, 283263720Strasz }; 284263720Strasz struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); 285263720Strasz struct ixpnpe_softc *sc; 286263720Strasz const struct npeconfig *config; 287263720Strasz int rid; 288263720Strasz 289263720Strasz if (npeid >= NPE_MAX) { 290263720Strasz device_printf(dev, "%s: bad npeid %d\n", __func__, npeid); 291263720Strasz return NULL; 292263720Strasz } 293263720Strasz sc = npes[npeid]; 294263720Strasz if (sc != NULL) { 295263720Strasz sc->sc_nrefs++; 296263720Strasz return sc; 297263720Strasz } 298263720Strasz config = &npeconfigs[npeid]; 299263720Strasz 300263720Strasz /* XXX M_BUS */ 301263720Strasz sc = malloc(sizeof(struct ixpnpe_softc), M_TEMP, M_WAITOK | M_ZERO); 302263720Strasz sc->sc_dev = dev; 303263722Strasz sc->sc_iot = sa->sc_iot; 304255570Strasz mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "npe driver", MTX_DEF); 305255570Strasz sc->sc_npeid = npeid; 306255570Strasz sc->sc_nrefs = 1; 307255570Strasz 308255570Strasz sc->sc_size = config->size; 309255570Strasz sc->insMemSize = config->ins_memsize; /* size of instruction memory */ 310255570Strasz sc->dataMemSize = config->data_memsize; /* size of data memory */ 311255570Strasz 312263725Strasz if (bus_space_map(sc->sc_iot, config->base, sc->sc_size, 0, &sc->sc_ioh)) 313263725Strasz panic("%s: Cannot map registers", device_get_name(dev)); 314263725Strasz 315263725Strasz /* 316263725Strasz * Setup IRQ and handler for NPE message support. 317263725Strasz */ 318263725Strasz rid = 0; 319263725Strasz sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 320263725Strasz config->irq, config->irq, 1, RF_ACTIVE); 321263725Strasz if (sc->sc_irq == NULL) 322263725Strasz panic("%s: Unable to allocate irq %u", device_get_name(dev), 323255570Strasz config->irq); 324255570Strasz /* XXX could be a source of entropy */ 325255570Strasz bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE, 326255570Strasz NULL, ixpnpe_intr, sc, &sc->sc_ih); 327255570Strasz /* 328255570Strasz * Enable output fifo interrupts (NB: must also set OFIFO Write Enable) 329255570Strasz */ 330255570Strasz npe_reg_write(sc, IX_NPECTL, 331255570Strasz npe_reg_read(sc, IX_NPECTL) | (IX_NPECTL_OFE | IX_NPECTL_OFWE)); 332275246Strasz 333275246Strasz npes[npeid] = sc; 334255570Strasz 335255570Strasz return sc; 336255570Strasz} 337255570Strasz 338255570Straszvoid 339275244Straszixpnpe_detach(struct ixpnpe_softc *sc) 340275244Strasz{ 341255570Strasz if (--sc->sc_nrefs == 0) { 342255570Strasz npes[sc->sc_npeid] = NULL; 343255570Strasz 344275642Strasz /* disable output fifo interrupts */ 345275642Strasz npe_reg_write(sc, IX_NPECTL, 346255570Strasz npe_reg_read(sc, IX_NPECTL) &~ (IX_NPECTL_OFE | IX_NPECTL_OFWE)); 347255570Strasz 348255570Strasz bus_teardown_intr(sc->sc_dev, sc->sc_irq, sc->sc_ih); 349255570Strasz bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); 350255570Strasz mtx_destroy(&sc->sc_mtx); 351255570Strasz free(sc, M_TEMP); 352255570Strasz } 353255570Strasz} 354255570Strasz 355255570Straszint 356255570Straszixpnpe_stopandreset(struct ixpnpe_softc *sc) 357255570Strasz{ 358255570Strasz int error; 359255570Strasz 360255570Strasz mtx_lock(&sc->sc_mtx); 361255570Strasz error = npe_cpu_stop(sc); /* stop NPE */ 362255570Strasz if (error == 0) 363255570Strasz error = npe_cpu_reset(sc); /* reset it */ 364255570Strasz if (error == 0) 365255570Strasz sc->started = 0; /* mark stopped */ 366255570Strasz mtx_unlock(&sc->sc_mtx); 367255570Strasz 368275244Strasz DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); 369275244Strasz return error; 370275244Strasz} 371275244Strasz 372275245Straszstatic int 373275244Straszixpnpe_start_locked(struct ixpnpe_softc *sc) 374275244Strasz{ 375275244Strasz int error; 376275244Strasz 377275244Strasz if (!sc->started) { 378275244Strasz error = npe_cpu_start(sc); 379255570Strasz if (error == 0) 380255570Strasz sc->started = 1; 381255570Strasz } else 382255570Strasz error = 0; 383255570Strasz 384255570Strasz DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); 385255570Strasz return error; 386255570Strasz} 387255570Strasz 388255570Straszint 389255570Straszixpnpe_start(struct ixpnpe_softc *sc) 390255570Strasz{ 391255570Strasz int ret; 392255570Strasz 393255570Strasz mtx_lock(&sc->sc_mtx); 394255570Strasz ret = ixpnpe_start_locked(sc); 395255570Strasz mtx_unlock(&sc->sc_mtx); 396255570Strasz return (ret); 397255570Strasz} 398255570Strasz 399255570Straszint 400255570Straszixpnpe_stop(struct ixpnpe_softc *sc) 401275642Strasz{ 402275642Strasz int error; 403275642Strasz 404275642Strasz mtx_lock(&sc->sc_mtx); 405275642Strasz error = npe_cpu_stop(sc); 406275642Strasz if (error == 0) 407275642Strasz sc->started = 0; 408275642Strasz mtx_unlock(&sc->sc_mtx); 409275642Strasz 410275642Strasz DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); 411275642Strasz return error; 412279002Smav} 413279002Smav 414279002Smav/* 415279002Smav * Indicates the start of an NPE Image, in new NPE Image Library format. 416279002Smav * 2 consecutive occurances indicates the end of the NPE Image Library 417279002Smav */ 418279002Smav#define NPE_IMAGE_MARKER 0xfeedf00d 419279002Smav 420279002Smav/* 421279002Smav * NPE Image Header definition, used in new NPE Image Library format 422279002Smav */ 423279002Smavtypedef struct { 424279002Smav uint32_t marker; 425279002Smav uint32_t id; 426279002Smav uint32_t size; 427279002Smav} IxNpeDlImageMgrImageHeader; 428263722Strasz 429255570Straszstatic int 430255570Strasznpe_findimage(struct ixpnpe_softc *sc, 431255570Strasz const uint32_t *imageLibrary, uint32_t imageId, 432255570Strasz const uint32_t **imagePtr, uint32_t *imageSize) 433255570Strasz{ 434255570Strasz const IxNpeDlImageMgrImageHeader *image; 435263722Strasz uint32_t offset = 0; 436255570Strasz 437255570Strasz while (imageLibrary[offset] == NPE_IMAGE_MARKER) { 438255570Strasz image = (const IxNpeDlImageMgrImageHeader *) 439255570Strasz &imageLibrary[offset]; 440255570Strasz offset += sizeof(IxNpeDlImageMgrImageHeader)/sizeof(uint32_t); 441255570Strasz 442255570Strasz DPRINTF(sc->sc_dev, "%s: off %u mark 0x%x id 0x%x size %u\n", 443255570Strasz __func__, offset, image->marker, image->id, image->size); 444255570Strasz if (image->id == imageId) { 445255570Strasz *imagePtr = imageLibrary + offset; 446255570Strasz *imageSize = image->size; 447275246Strasz return 0; 448275246Strasz } 449255570Strasz /* 2 consecutive NPE_IMAGE_MARKER's indicates end of library */ 450255570Strasz if (image->id == NPE_IMAGE_MARKER) { 451255570Strasz DPRINTF(sc->sc_dev, "imageId 0x%08x not found in " 452263722Strasz "image library header\n", imageId); 453255570Strasz /* reached end of library, image not found */ 454263722Strasz return ESRCH; 455255570Strasz } 456263724Strasz offset += image->size; 457263724Strasz } 458263722Strasz return ESRCH; 459255570Strasz} 460263722Strasz 461255570Straszstatic int 462263722Straszixpnpe_load_firmware(struct ixpnpe_softc *sc, const char *imageName, 463263720Strasz uint32_t imageId) 464263722Strasz{ 465263720Strasz static const char *devname[4] = 466263722Strasz { "IXP425", "IXP435/IXP465", "DeviceID#2", "DeviceID#3" }; 467255570Strasz uint32_t imageSize; 468275642Strasz const uint32_t *imageCodePtr; 469275642Strasz const struct firmware *fw; 470263722Strasz int error; 471279002Smav 472279002Smav DPRINTF(sc->sc_dev, "load %s, imageId 0x%08x\n", imageName, imageId); 473255570Strasz 474255570Strasz#if 0 475263722Strasz IxFeatureCtrlDeviceId devid = IX_NPEDL_DEVICEID_FROM_IMAGEID_GET(imageId); 476255570Strasz /* 477255570Strasz * Checking if image being loaded is meant for device that is running. 478255570Strasz * Image is forward compatible. i.e Image built for IXP42X should run 479263723Strasz * on IXP46X but not vice versa. 480255570Strasz */ 481255570Strasz if (devid > (ixFeatureCtrlDeviceRead() & IX_FEATURE_CTRL_DEVICE_TYPE_MASK)) 482255570Strasz return EINVAL; 483255570Strasz#endif 484255570Strasz error = ixpnpe_stopandreset(sc); /* stop and reset the NPE */ 485255570Strasz if (error != 0) 486263722Strasz return error; 487255570Strasz 488255570Strasz fw = firmware_get(imageName); 489255570Strasz if (fw == NULL) 490255570Strasz return ENOENT; 491263723Strasz 492255570Strasz /* Locate desired image in files w/ combined images */ 493263724Strasz error = npe_findimage(sc, fw->data, imageId, &imageCodePtr, &imageSize); 494255570Strasz if (error != 0) 495263723Strasz goto done; 496255570Strasz 497255570Strasz device_printf(sc->sc_dev, 498255570Strasz "load fw image %s.NPE-%c Func 0x%x Rev %u.%u\n", 499255570Strasz devname[NPEIMAGE_DEVID(imageId)], 'A' + NPEIMAGE_NPEID(imageId), 500255570Strasz NPEIMAGE_FUNCID(imageId), NPEIMAGE_MAJOR(imageId), 501263723Strasz NPEIMAGE_MINOR(imageId)); 502255570Strasz 503255570Strasz /* 504255570Strasz * If download was successful, store image Id in list of 505255570Strasz * currently loaded images. If a critical error occured 506255570Strasz * during download, record that the NPE has an invalid image 507255570Strasz */ 508263724Strasz mtx_lock(&sc->sc_mtx); 509263724Strasz error = npe_load_image(sc, imageCodePtr, 1 /*VERIFY*/); 510263724Strasz if (error == 0) { 511263724Strasz sc->validImage = 1; 512263724Strasz error = ixpnpe_start_locked(sc); 513263724Strasz } else { 514263724Strasz sc->validImage = 0; 515263724Strasz } 516263724Strasz sc->functionalityId = IX_NPEDL_FUNCTIONID_FROM_IMAGEID_GET(imageId); 517263724Strasz mtx_unlock(&sc->sc_mtx); 518263724Straszdone: 519263724Strasz firmware_put(fw, FIRMWARE_UNLOAD); 520263724Strasz DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); 521263724Strasz return error; 522263724Strasz} 523263724Strasz 524263724Straszstatic int 525263724Straszoverride_imageid(device_t dev, const char *resname, uint32_t *val) 526263724Strasz{ 527275245Strasz int unit = device_get_unit(dev); 528263724Strasz int resval; 529263724Strasz 530263724Strasz if (resource_int_value("npe", unit, resname, &resval) != 0) 531263724Strasz return 0; 532263724Strasz /* XXX validate */ 533263724Strasz if (bootverbose) 534263722Strasz device_printf(dev, "using npe.%d.%s=0x%x override\n", 535255570Strasz unit, resname, resval); 536255570Strasz *val = resval; 537255570Strasz return 1; 538255570Strasz} 539255570Strasz 540263724Straszint 541263724Straszixpnpe_init(struct ixpnpe_softc *sc) 542263723Strasz{ 543255570Strasz static const uint32_t npeconfig[NPE_MAX] = { 544255570Strasz [NPE_A] = IXP425_NPE_A_IMAGEID, 545255570Strasz [NPE_B] = IXP425_NPE_B_IMAGEID, 546255570Strasz [NPE_C] = IXP425_NPE_C_IMAGEID, 547255570Strasz }; 548255570Strasz uint32_t imageid, msg[2]; 549255570Strasz int error; 550255570Strasz 551255570Strasz if (sc->started) 552255570Strasz return 0; 553255570Strasz /* 554255570Strasz * Load NPE firmware and start it running. We assume 555255570Strasz * that minor version bumps remain compatible so probe 556255570Strasz * the firmware image starting with the expected version 557255570Strasz * and then bump the minor version up to the max. 558255570Strasz */ 559255570Strasz if (!override_imageid(sc->sc_dev, "imageid", &imageid)) 560255570Strasz imageid = npeconfig[sc->sc_npeid]; 561255570Strasz for (;;) { 562255570Strasz error = ixpnpe_load_firmware(sc, "npe_fw", imageid); 563255570Strasz if (error == 0) 564263722Strasz break; 565255570Strasz /* 566255570Strasz * ESRCH is returned when the requested image 567255570Strasz * is not present 568255570Strasz */ 569255570Strasz if (error != ESRCH) { 570263724Strasz device_printf(sc->sc_dev, 571263724Strasz "cannot init NPE (error %d)\n", error); 572263723Strasz return error; 573255570Strasz } 574255570Strasz /* bump the minor version up to the max possible */ 575255570Strasz if (NPEIMAGE_MINOR(imageid) == 0xff) { 576255570Strasz device_printf(sc->sc_dev, "cannot locate firmware " 577255570Strasz "(imageid 0x%08x)\n", imageid); 578255570Strasz return error; 579255570Strasz } 580255570Strasz imageid++; 581255570Strasz } 582255570Strasz /* NB: firmware should respond with a status msg */ 583255570Strasz if (ixpnpe_recvmsg_sync(sc, msg) != 0) { 584255570Strasz device_printf(sc->sc_dev, 585255570Strasz "firmware did not respond as expected\n"); 586255570Strasz return EIO; 587255570Strasz } 588255570Strasz return 0; 589255570Strasz} 590255570Strasz 591255570Straszint 592255570Straszixpnpe_getfunctionality(struct ixpnpe_softc *sc) 593255570Strasz{ 594255570Strasz return (sc->validImage ? sc->functionalityId : 0); 595255570Strasz} 596255570Strasz 597255570Straszstatic int 598255570Strasznpe_checkbits(struct ixpnpe_softc *sc, uint32_t reg, uint32_t expectedBitsSet) 599255570Strasz{ 600255570Strasz uint32_t val; 601263722Strasz 602263720Strasz val = npe_reg_read(sc, reg); 603263720Strasz DPRINTFn(5, sc->sc_dev, "%s(0x%x, 0x%x) => 0x%x (%u)\n", 604263720Strasz __func__, reg, expectedBitsSet, val, 605263720Strasz (val & expectedBitsSet) == expectedBitsSet); 606263720Strasz return ((val & expectedBitsSet) == expectedBitsSet); 607263724Strasz} 608263720Strasz 609263723Straszstatic int 610263720Strasznpe_isstopped(struct ixpnpe_softc *sc) 611263720Strasz{ 612263720Strasz return npe_checkbits(sc, 613263720Strasz IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP); 614263720Strasz} 615263720Strasz 616263720Straszstatic int 617263720Strasznpe_load_ins(struct ixpnpe_softc *sc, 618263720Strasz const IxNpeDlNpeMgrCodeBlock *bp, int verify) 619263720Strasz{ 620263720Strasz uint32_t npeMemAddress; 621263720Strasz int i, blockSize; 622263720Strasz 623263720Strasz npeMemAddress = bp->npeMemAddress; 624263720Strasz blockSize = bp->size; /* NB: instruction/data count */ 625263720Strasz if (npeMemAddress + blockSize > sc->insMemSize) { 626263720Strasz device_printf(sc->sc_dev, 627263720Strasz "Block size %u too big for NPE memory\n", blockSize); 628263722Strasz return EINVAL; /* XXX */ 629263720Strasz } 630263720Strasz for (i = 0; i < blockSize; i++, npeMemAddress++) { 631263720Strasz if (npe_ins_write(sc, npeMemAddress, bp->data[i], verify) != 0) { 632263720Strasz device_printf(sc->sc_dev, 633263720Strasz "NPE instruction write failed"); 634263724Strasz return EIO; 635263720Strasz } 636263723Strasz } 637263720Strasz return 0; 638263720Strasz} 639263720Strasz 640263720Straszstatic int 641263720Strasznpe_load_data(struct ixpnpe_softc *sc, 642263720Strasz const IxNpeDlNpeMgrCodeBlock *bp, int verify) 643263720Strasz{ 644263720Strasz uint32_t npeMemAddress; 645263720Strasz int i, blockSize; 646263720Strasz 647263720Strasz npeMemAddress = bp->npeMemAddress; 648263720Strasz blockSize = bp->size; /* NB: instruction/data count */ 649263720Strasz if (npeMemAddress + blockSize > sc->dataMemSize) { 650263720Strasz device_printf(sc->sc_dev, 651263720Strasz "Block size %u too big for NPE memory\n", blockSize); 652263720Strasz return EINVAL; 653263720Strasz } 654263720Strasz for (i = 0; i < blockSize; i++, npeMemAddress++) { 655263722Strasz if (npe_data_write(sc, npeMemAddress, bp->data[i], verify) != 0) { 656255570Strasz device_printf(sc->sc_dev, "NPE data write failed\n"); 657255570Strasz return EIO; 658255570Strasz } 659263723Strasz } 660255570Strasz return 0; 661255570Strasz} 662255570Strasz 663255570Straszstatic int 664255570Strasznpe_load_stateinfo(struct ixpnpe_softc *sc, 665255570Strasz const IxNpeDlNpeMgrStateInfoBlock *bp, int verify) 666263723Strasz{ 667255570Strasz int i, nentries, error; 668255570Strasz 669255570Strasz npe_cpu_step_save(sc); 670255570Strasz 671255570Strasz /* for each state-info context register entry in block */ 672255570Strasz nentries = bp->size / IX_NPEDL_STATE_INFO_ENTRY_SIZE; 673255570Strasz error = 0; 674275642Strasz for (i = 0; i < nentries; i++) { 675275642Strasz /* each state-info entry is 2 words (address, value) */ 676275642Strasz uint32_t regVal = bp->ctxtRegEntry[i].value; 677275642Strasz uint32_t addrInfo = bp->ctxtRegEntry[i].addressInfo; 678275642Strasz 679275642Strasz uint32_t reg = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_REG); 680275642Strasz uint32_t cNum = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM) >> 681275642Strasz IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM; 682275642Strasz 683275642Strasz /* error-check Context Register No. and Context Number values */ 684275642Strasz if (!(0 <= reg && reg < IX_NPEDL_CTXT_REG_MAX)) { 685263722Strasz device_printf(sc->sc_dev, 686263722Strasz "invalid Context Register %u\n", reg); 687255570Strasz error = EINVAL; 688255570Strasz break; 689255570Strasz } 690255570Strasz if (!(0 <= cNum && cNum < IX_NPEDL_CTXT_NUM_MAX)) { 691255570Strasz device_printf(sc->sc_dev, 692275186Strasz "invalid Context Number %u\n", cNum); 693255570Strasz error = EINVAL; 694275186Strasz break; 695279002Smav } 696275186Strasz /* NOTE that there is no STEVT register for Context 0 */ 697275186Strasz if (cNum == 0 && reg == IX_NPEDL_CTXT_REG_STEVT) { 698275187Strasz device_printf(sc->sc_dev, 699275186Strasz "no STEVT for Context 0\n"); 700275186Strasz error = EINVAL; 701275186Strasz break; 702275186Strasz } 703279002Smav 704279002Smav if (npe_ctx_reg_write(sc, cNum, reg, regVal, verify) != 0) { 705255570Strasz device_printf(sc->sc_dev, 706255570Strasz "write of state-info to NPE failed\n"); 707279002Smav error = EIO; 708279002Smav break; 709279002Smav } 710255570Strasz } 711255570Strasz 712255570Strasz npe_cpu_step_restore(sc); 713279002Smav return error; 714279002Smav} 715279002Smav 716279002Smavstatic int 717279002Smavnpe_load_image(struct ixpnpe_softc *sc, 718279002Smav const uint32_t *imageCodePtr, int verify) 719279002Smav{ 720279002Smav#define EOM(marker) ((marker) == IX_NPEDL_END_OF_DOWNLOAD_MAP) 721279002Smav const IxNpeDlNpeMgrDownloadMap *downloadMap; 722279002Smav int i, error; 723279002Smav 724279002Smav if (!npe_isstopped(sc)) { /* verify NPE is stopped */ 725279002Smav device_printf(sc->sc_dev, 726279002Smav "cannot load image, NPE not stopped\n"); 727279002Smav return EIO; 728279002Smav } 729279002Smav 730279002Smav /* 731279002Smav * Read Download Map, checking each block type and calling 732279002Smav * appropriate function to perform download 733279002Smav */ 734263722Strasz error = 0; 735255570Strasz downloadMap = (const IxNpeDlNpeMgrDownloadMap *) imageCodePtr; 736263722Strasz for (i = 0; !EOM(downloadMap->entry[i].eodmMarker); i++) { 737275246Strasz /* calculate pointer to block to be downloaded */ 738275246Strasz const uint32_t *bp = imageCodePtr + 739255570Strasz downloadMap->entry[i].block.offset; 740255570Strasz switch (downloadMap->entry[i].block.type) { 741263722Strasz case IX_NPEDL_BLOCK_TYPE_INSTRUCTION: 742263722Strasz error = npe_load_ins(sc, 743255570Strasz (const IxNpeDlNpeMgrCodeBlock *) bp, verify); 744263722Strasz DPRINTF(sc->sc_dev, "%s: inst, error %d\n", 745255570Strasz __func__, error); 746263722Strasz break; 747255570Strasz case IX_NPEDL_BLOCK_TYPE_DATA: 748263722Strasz error = npe_load_data(sc, 749255570Strasz (const IxNpeDlNpeMgrCodeBlock *) bp, verify); 750263722Strasz DPRINTF(sc->sc_dev, "%s: data, error %d\n", 751255570Strasz __func__, error); 752263722Strasz break; 753255570Strasz case IX_NPEDL_BLOCK_TYPE_STATE: 754263722Strasz error = npe_load_stateinfo(sc, 755255570Strasz (const IxNpeDlNpeMgrStateInfoBlock *) bp, verify); 756255570Strasz DPRINTF(sc->sc_dev, "%s: state, error %d\n", 757263722Strasz __func__, error); 758255570Strasz break; 759255570Strasz default: 760279002Smav device_printf(sc->sc_dev, 761255570Strasz "unknown block type 0x%x in download map\n", 762279002Smav downloadMap->entry[i].block.type); 763255570Strasz error = EIO; /* XXX */ 764255570Strasz break; 765255570Strasz } 766255570Strasz if (error != 0) 767255570Strasz break; 768255570Strasz } 769255570Strasz return error; 770255570Strasz#undef EOM 771275186Strasz} 772255570Strasz 773275186Strasz/* contains Reset values for Context Store Registers */ 774275186Straszstatic const struct { 775275186Strasz uint32_t regAddr; 776275187Strasz uint32_t regResetVal; 777275186Strasz} ixNpeDlEcsRegResetValues[] = { 778275186Strasz { IX_NPEDL_ECS_BG_CTXT_REG_0, IX_NPEDL_ECS_BG_CTXT_REG_0_RESET }, 779275186Strasz { IX_NPEDL_ECS_BG_CTXT_REG_1, IX_NPEDL_ECS_BG_CTXT_REG_1_RESET }, 780275186Strasz { IX_NPEDL_ECS_BG_CTXT_REG_2, IX_NPEDL_ECS_BG_CTXT_REG_2_RESET }, 781255570Strasz { IX_NPEDL_ECS_PRI_1_CTXT_REG_0, IX_NPEDL_ECS_PRI_1_CTXT_REG_0_RESET }, 782279002Smav { IX_NPEDL_ECS_PRI_1_CTXT_REG_1, IX_NPEDL_ECS_PRI_1_CTXT_REG_1_RESET }, 783255570Strasz { IX_NPEDL_ECS_PRI_1_CTXT_REG_2, IX_NPEDL_ECS_PRI_1_CTXT_REG_2_RESET }, 784279002Smav { IX_NPEDL_ECS_PRI_2_CTXT_REG_0, IX_NPEDL_ECS_PRI_2_CTXT_REG_0_RESET }, 785255570Strasz { IX_NPEDL_ECS_PRI_2_CTXT_REG_1, IX_NPEDL_ECS_PRI_2_CTXT_REG_1_RESET }, 786255570Strasz { IX_NPEDL_ECS_PRI_2_CTXT_REG_2, IX_NPEDL_ECS_PRI_2_CTXT_REG_2_RESET }, 787275186Strasz { IX_NPEDL_ECS_DBG_CTXT_REG_0, IX_NPEDL_ECS_DBG_CTXT_REG_0_RESET }, 788255570Strasz { IX_NPEDL_ECS_DBG_CTXT_REG_1, IX_NPEDL_ECS_DBG_CTXT_REG_1_RESET }, 789255570Strasz { IX_NPEDL_ECS_DBG_CTXT_REG_2, IX_NPEDL_ECS_DBG_CTXT_REG_2_RESET }, 790255570Strasz { IX_NPEDL_ECS_INSTRUCT_REG, IX_NPEDL_ECS_INSTRUCT_REG_RESET } 791263722Strasz}; 792255570Strasz 793255570Strasz/* contains Reset values for Context Store Registers */ 794279002Smavstatic const uint32_t ixNpeDlCtxtRegResetValues[] = { 795255570Strasz IX_NPEDL_CTXT_REG_RESET_STEVT, 796279002Smav IX_NPEDL_CTXT_REG_RESET_STARTPC, 797255570Strasz IX_NPEDL_CTXT_REG_RESET_REGMAP, 798255570Strasz IX_NPEDL_CTXT_REG_RESET_CINDEX, 799255570Strasz}; 800255570Strasz 801255570Strasz#define IX_NPEDL_RESET_NPE_PARITY 0x0800 802255570Strasz#define IX_NPEDL_PARITY_BIT_MASK 0x3F00FFFF 803255570Strasz#define IX_NPEDL_CONFIG_CTRL_REG_MASK 0x3F3FFFFF 804255570Strasz 805263722Straszstatic int 806255570Strasznpe_cpu_reset(struct ixpnpe_softc *sc) 807255570Strasz{ 808274870Strasz#define N(a) (sizeof(a) / sizeof(a[0])) 809255570Strasz struct ixp425_softc *sa = 810255570Strasz device_get_softc(device_get_parent(sc->sc_dev)); 811255570Strasz uint32_t ctxtReg; /* identifies Context Store reg (0-3) */ 812255570Strasz uint32_t regAddr; 813255570Strasz uint32_t regVal; 814255570Strasz uint32_t resetNpeParity; 815255570Strasz uint32_t ixNpeConfigCtrlRegVal; 816255570Strasz int i, error = 0; 817263722Strasz 818255570Strasz /* pre-store the NPE Config Control Register Value */ 819255570Strasz ixNpeConfigCtrlRegVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL); 820279002Smav ixNpeConfigCtrlRegVal |= 0x3F000000; 821255570Strasz 822279002Smav /* disable the parity interrupt */ 823255570Strasz npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL, 824255570Strasz (ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK)); 825255570Strasz DPRINTFn(2, sc->sc_dev, "%s: dis parity int, CTL => 0x%x\n", 826255570Strasz __func__, ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK); 827255570Strasz 828255570Strasz npe_cpu_step_save(sc); 829255570Strasz 830255570Strasz /* 831263722Strasz * Clear the FIFOs. 832255570Strasz */ 833255570Strasz while (npe_checkbits(sc, 834279002Smav IX_NPEDL_REG_OFFSET_WFIFO, IX_NPEDL_MASK_WFIFO_VALID)) { 835255570Strasz /* read from the Watch-point FIFO until empty */ 836279002Smav (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WFIFO); 837255570Strasz } 838255570Strasz 839255570Strasz while (npe_checkbits(sc, 840255570Strasz IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_OFNE)) { 841255570Strasz /* read from the outFIFO until empty */ 842275186Strasz (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_FIFO); 843275186Strasz } 844275186Strasz 845275186Strasz while (npe_checkbits(sc, 846267962Sjpaetzel IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_IFNE)) { 847275186Strasz /* 848267962Sjpaetzel * Step execution of the NPE intruction to read inFIFO using 849275186Strasz * the Debug Executing Context stack. 850275187Strasz */ 851275186Strasz error = npe_cpu_step(sc, IX_NPEDL_INSTR_RD_FIFO, 0, 0); 852267962Sjpaetzel if (error != 0) { 853267962Sjpaetzel DPRINTF(sc->sc_dev, "%s: cannot step (1), error %u\n", 854255570Strasz __func__, error); 855255570Strasz npe_cpu_step_restore(sc); 856279002Smav return error; 857255570Strasz } 858279002Smav } 859255570Strasz 860255570Strasz /* 861275186Strasz * Reset the mailbox reg 862255570Strasz */ 863255570Strasz /* ...from XScale side */ 864255570Strasz npe_reg_write(sc, IX_NPEDL_REG_OFFSET_MBST, IX_NPEDL_REG_RESET_MBST); 865255570Strasz /* ...from NPE side */ 866255570Strasz error = npe_cpu_step(sc, IX_NPEDL_INSTR_RESET_MBOX, 0, 0); 867255570Strasz if (error != 0) { 868255570Strasz DPRINTF(sc->sc_dev, "%s: cannot step (2), error %u\n", 869255570Strasz __func__, error); 870255570Strasz npe_cpu_step_restore(sc); 871255570Strasz return error; 872255570Strasz } 873255570Strasz 874255570Strasz /* 875255570Strasz * Reset the physical registers in the NPE register file: 876255570Strasz * Note: no need to save/restore REGMAP for Context 0 here 877255570Strasz * since all Context Store regs are reset in subsequent code. 878255570Strasz */ 879255570Strasz for (regAddr = 0; 880255570Strasz regAddr < IX_NPEDL_TOTAL_NUM_PHYS_REG && error == 0; 881255570Strasz regAddr++) { 882255570Strasz /* for each physical register in the NPE reg file, write 0 : */ 883255570Strasz error = npe_physical_reg_write(sc, regAddr, 0, TRUE); 884255570Strasz if (error != 0) { 885255570Strasz DPRINTF(sc->sc_dev, "%s: cannot write phy reg," 886255570Strasz "error %u\n", __func__, error); 887255570Strasz npe_cpu_step_restore(sc); 888255570Strasz return error; /* abort reset */ 889255570Strasz } 890255570Strasz } 891255570Strasz 892255570Strasz /* 893255570Strasz * Reset the context store: 894255570Strasz */ 895255570Strasz for (i = IX_NPEDL_CTXT_NUM_MIN; i <= IX_NPEDL_CTXT_NUM_MAX; i++) { 896255570Strasz /* set each context's Context Store registers to reset values */ 897255570Strasz for (ctxtReg = 0; ctxtReg < IX_NPEDL_CTXT_REG_MAX; ctxtReg++) { 898255570Strasz /* NOTE that there is no STEVT register for Context 0 */ 899255570Strasz if (i == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STEVT) 900255570Strasz continue; 901255570Strasz regVal = ixNpeDlCtxtRegResetValues[ctxtReg]; 902255570Strasz error = npe_ctx_reg_write(sc, i, ctxtReg, 903255570Strasz regVal, TRUE); 904255570Strasz if (error != 0) { 905255570Strasz DPRINTF(sc->sc_dev, "%s: cannot write ctx reg," 906255570Strasz "error %u\n", __func__, error); 907255570Strasz npe_cpu_step_restore(sc); 908255570Strasz return error; /* abort reset */ 909255570Strasz } 910255570Strasz } 911255570Strasz } 912255570Strasz 913263726Strasz npe_cpu_step_restore(sc); 914263726Strasz 915263726Strasz /* write Reset values to Execution Context Stack registers */ 916255570Strasz for (i = 0; i < N(ixNpeDlEcsRegResetValues); i++) 917263725Strasz npe_ecs_reg_write(sc, 918255570Strasz ixNpeDlEcsRegResetValues[i].regAddr, 919255570Strasz ixNpeDlEcsRegResetValues[i].regResetVal); 920255570Strasz 921263725Strasz /* clear the profile counter */ 922263729Strasz npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_CLR_PROFILE_CNT); 923255570Strasz 924255570Strasz /* clear registers EXCT, AP0, AP1, AP2 and AP3 */ 925263725Strasz for (regAddr = IX_NPEDL_REG_OFFSET_EXCT; 926255570Strasz regAddr <= IX_NPEDL_REG_OFFSET_AP3; 927255570Strasz regAddr += sizeof(uint32_t)) 928255570Strasz npe_reg_write(sc, regAddr, 0); 929255570Strasz 930255570Strasz /* Reset the Watch-count register */ 931255570Strasz npe_reg_write(sc, IX_NPEDL_REG_OFFSET_WC, 0); 932255570Strasz 933255570Strasz /* 934263715Strasz * WR IXA00055043 - Remove IMEM Parity Introduced by NPE Reset Operation 935255570Strasz */ 936255570Strasz 937255570Strasz /* 938255570Strasz * Reset the NPE and its coprocessor - to reset internal 939255570Strasz * states and remove parity error. Note this makes no 940255570Strasz * sense based on the documentation. The feature control 941255570Strasz * register always reads back as 0 on the ixp425 and further 942255570Strasz * the bit definition of NPEA/NPEB is off by 1 according to 943255570Strasz * the Intel documention--so we're blindly following the 944255570Strasz * Intel code w/o any real understanding. 945255570Strasz */ 946255570Strasz regVal = EXP_BUS_READ_4(sa, EXP_FCTRL_OFFSET); 947263726Strasz DPRINTFn(2, sc->sc_dev, "%s: FCTRL 0x%x\n", __func__, regVal); 948263726Strasz resetNpeParity = 949263726Strasz IX_NPEDL_RESET_NPE_PARITY << (1 + device_get_unit(sc->sc_dev)); 950263726Strasz DPRINTFn(2, sc->sc_dev, "%s: FCTRL fuse parity, write 0x%x\n", 951263726Strasz __func__, regVal | resetNpeParity); 952263729Strasz EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal | resetNpeParity); 953263726Strasz 954263726Strasz /* un-fuse and un-reset the NPE & coprocessor */ 955263725Strasz DPRINTFn(2, sc->sc_dev, "%s: FCTRL unfuse parity, write 0x%x\n", 956263725Strasz __func__, regVal & resetNpeParity); 957263725Strasz EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal &~ resetNpeParity); 958263725Strasz 959263725Strasz /* 960263725Strasz * Call NpeMgr function to stop the NPE again after the Feature Control 961263725Strasz * has unfused and Un-Reset the NPE and its associated Coprocessors. 962263725Strasz */ 963263725Strasz error = npe_cpu_stop(sc); 964265511Strasz 965265511Strasz /* restore NPE configuration bus Control Register - Parity Settings */ 966255570Strasz npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL, 967255570Strasz (ixNpeConfigCtrlRegVal & IX_NPEDL_CONFIG_CTRL_REG_MASK)); 968255570Strasz DPRINTFn(2, sc->sc_dev, "%s: restore CTL => 0x%x\n", 969255570Strasz __func__, npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL)); 970255570Strasz 971255570Strasz return error; 972255570Strasz#undef N 973255570Strasz} 974 975static int 976npe_cpu_start(struct ixpnpe_softc *sc) 977{ 978 uint32_t ecsRegVal; 979 980 /* 981 * Ensure only Background Context Stack Level is Active by turning off 982 * the Active bit in each of the other Executing Context Stack levels. 983 */ 984 ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0); 985 ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; 986 npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0, ecsRegVal); 987 988 ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0); 989 ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; 990 npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0, ecsRegVal); 991 992 ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0); 993 ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; 994 npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsRegVal); 995 996 /* clear the pipeline */ 997 npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); 998 999 /* start NPE execution by issuing cmd through EXCTL register on NPE */ 1000 npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_START); 1001 1002 /* 1003 * Check execution status of NPE to verify operation was successful. 1004 */ 1005 return npe_checkbits(sc, 1006 IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_RUN) ? 0 : EIO; 1007} 1008 1009static int 1010npe_cpu_stop(struct ixpnpe_softc *sc) 1011{ 1012 /* stop NPE execution by issuing cmd through EXCTL register on NPE */ 1013 npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STOP); 1014 1015 /* verify that NPE Stop was successful */ 1016 return npe_checkbits(sc, 1017 IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP) ? 0 : EIO; 1018} 1019 1020#define IX_NPEDL_REG_SIZE_BYTE 8 1021#define IX_NPEDL_REG_SIZE_SHORT 16 1022#define IX_NPEDL_REG_SIZE_WORD 32 1023 1024/* 1025 * Introduce extra read cycles after issuing read command to NPE 1026 * so that we read the register after the NPE has updated it 1027 * This is to overcome race condition between XScale and NPE 1028 */ 1029#define IX_NPEDL_DELAY_READ_CYCLES 2 1030/* 1031 * To mask top three MSBs of 32bit word to download into NPE IMEM 1032 */ 1033#define IX_NPEDL_MASK_UNUSED_IMEM_BITS 0x1FFFFFFF; 1034 1035static void 1036npe_cmd_issue_write(struct ixpnpe_softc *sc, 1037 uint32_t cmd, uint32_t addr, uint32_t data) 1038{ 1039 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, data); 1040 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr); 1041 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd); 1042} 1043 1044static uint32_t 1045npe_cmd_issue_read(struct ixpnpe_softc *sc, uint32_t cmd, uint32_t addr) 1046{ 1047 uint32_t data; 1048 int i; 1049 1050 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr); 1051 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd); 1052 for (i = 0; i <= IX_NPEDL_DELAY_READ_CYCLES; i++) 1053 data = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA); 1054 return data; 1055} 1056 1057static int 1058npe_ins_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify) 1059{ 1060 DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data); 1061 npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_INS_MEM, addr, data); 1062 if (verify) { 1063 uint32_t rdata; 1064 1065 /* 1066 * Write invalid data to this reg, so we can see if we're 1067 * reading the EXDATA register too early. 1068 */ 1069 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data); 1070 1071 /* 1072 * Disabled since top 3 MSB are not used for Azusa 1073 * hardware Refer WR:IXA00053900 1074 */ 1075 data &= IX_NPEDL_MASK_UNUSED_IMEM_BITS; 1076 1077 rdata = npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_INS_MEM, 1078 addr); 1079 rdata &= IX_NPEDL_MASK_UNUSED_IMEM_BITS; 1080 1081 if (data != rdata) 1082 return EIO; 1083 } 1084 return 0; 1085} 1086 1087static int 1088npe_data_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify) 1089{ 1090 DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data); 1091 npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_DATA_MEM, addr, data); 1092 if (verify) { 1093 /* 1094 * Write invalid data to this reg, so we can see if we're 1095 * reading the EXDATA register too early. 1096 */ 1097 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data); 1098 if (data != npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_DATA_MEM, addr)) 1099 return EIO; 1100 } 1101 return 0; 1102} 1103 1104static void 1105npe_ecs_reg_write(struct ixpnpe_softc *sc, uint32_t reg, uint32_t data) 1106{ 1107 npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_ECS_REG, reg, data); 1108} 1109 1110static uint32_t 1111npe_ecs_reg_read(struct ixpnpe_softc *sc, uint32_t reg) 1112{ 1113 return npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_ECS_REG, reg); 1114} 1115 1116static void 1117npe_issue_cmd(struct ixpnpe_softc *sc, uint32_t command) 1118{ 1119 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, command); 1120} 1121 1122static void 1123npe_cpu_step_save(struct ixpnpe_softc *sc) 1124{ 1125 /* turn off the halt bit by clearing Execution Count register. */ 1126 /* save reg contents 1st and restore later */ 1127 sc->savedExecCount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXCT); 1128 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, 0); 1129 1130 /* ensure that IF and IE are on (temporarily), so that we don't end up 1131 * stepping forever */ 1132 sc->savedEcsDbgCtxtReg2 = npe_ecs_reg_read(sc, 1133 IX_NPEDL_ECS_DBG_CTXT_REG_2); 1134 1135 npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, 1136 (sc->savedEcsDbgCtxtReg2 | IX_NPEDL_MASK_ECS_DBG_REG_2_IF | 1137 IX_NPEDL_MASK_ECS_DBG_REG_2_IE)); 1138} 1139 1140static int 1141npe_cpu_step(struct ixpnpe_softc *sc, uint32_t npeInstruction, 1142 uint32_t ctxtNum, uint32_t ldur) 1143{ 1144#define IX_NPE_DL_MAX_NUM_OF_RETRIES 1000000 1145 uint32_t ecsDbgRegVal; 1146 uint32_t oldWatchcount, newWatchcount; 1147 int tries; 1148 1149 /* set the Active bit, and the LDUR, in the debug level */ 1150 ecsDbgRegVal = IX_NPEDL_MASK_ECS_REG_0_ACTIVE | 1151 (ldur << IX_NPEDL_OFFSET_ECS_REG_0_LDUR); 1152 1153 npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsDbgRegVal); 1154 1155 /* 1156 * Set CCTXT at ECS DEBUG L3 to specify in which context to execute the 1157 * instruction, and set SELCTXT at ECS DEBUG Level to specify which 1158 * context store to access. 1159 * Debug ECS Level Reg 1 has form 0x000n000n, where n = context number 1160 */ 1161 ecsDbgRegVal = (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_CCTXT) | 1162 (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_SELCTXT); 1163 1164 npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_1, ecsDbgRegVal); 1165 1166 /* clear the pipeline */ 1167 npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); 1168 1169 /* load NPE instruction into the instruction register */ 1170 npe_ecs_reg_write(sc, IX_NPEDL_ECS_INSTRUCT_REG, npeInstruction); 1171 1172 /* need this value later to wait for completion of NPE execution step */ 1173 oldWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); 1174 1175 /* issue a Step One command via the Execution Control register */ 1176 npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STEP); 1177 1178 /* 1179 * Force the XScale to wait until the NPE has finished execution step 1180 * NOTE that this delay will be very small, just long enough to allow a 1181 * single NPE instruction to complete execution; if instruction 1182 * execution is not completed before timeout retries, exit the while 1183 * loop. 1184 */ 1185 newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); 1186 for (tries = 0; tries < IX_NPE_DL_MAX_NUM_OF_RETRIES && 1187 newWatchcount == oldWatchcount; tries++) { 1188 /* Watch Count register incr's when NPE completes an inst */ 1189 newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); 1190 } 1191 return (tries < IX_NPE_DL_MAX_NUM_OF_RETRIES) ? 0 : EIO; 1192#undef IX_NPE_DL_MAX_NUM_OF_RETRIES 1193} 1194 1195static void 1196npe_cpu_step_restore(struct ixpnpe_softc *sc) 1197{ 1198 /* clear active bit in debug level */ 1199 npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, 0); 1200 1201 /* clear the pipeline */ 1202 npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); 1203 1204 /* restore Execution Count register contents. */ 1205 npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, sc->savedExecCount); 1206 1207 /* restore IF and IE bits to original values */ 1208 npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, sc->savedEcsDbgCtxtReg2); 1209} 1210 1211static int 1212npe_logical_reg_read(struct ixpnpe_softc *sc, 1213 uint32_t regAddr, uint32_t regSize, 1214 uint32_t ctxtNum, uint32_t *regVal) 1215{ 1216 uint32_t npeInstruction, mask; 1217 int error; 1218 1219 switch (regSize) { 1220 case IX_NPEDL_REG_SIZE_BYTE: 1221 npeInstruction = IX_NPEDL_INSTR_RD_REG_BYTE; 1222 mask = 0xff; 1223 break; 1224 case IX_NPEDL_REG_SIZE_SHORT: 1225 npeInstruction = IX_NPEDL_INSTR_RD_REG_SHORT; 1226 mask = 0xffff; 1227 break; 1228 case IX_NPEDL_REG_SIZE_WORD: 1229 npeInstruction = IX_NPEDL_INSTR_RD_REG_WORD; 1230 mask = 0xffffffff; 1231 break; 1232 default: 1233 return EINVAL; 1234 } 1235 1236 /* make regAddr be the SRC and DEST operands (e.g. movX d0, d0) */ 1237 npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_SRC) | 1238 (regAddr << IX_NPEDL_OFFSET_INSTR_DEST); 1239 1240 /* step execution of NPE inst using Debug Executing Context stack */ 1241 error = npe_cpu_step(sc, npeInstruction, ctxtNum, 1242 IX_NPEDL_RD_INSTR_LDUR); 1243 if (error != 0) { 1244 DPRINTF(sc->sc_dev, "%s(0x%x, %u, %u), cannot step, error %d\n", 1245 __func__, regAddr, regSize, ctxtNum, error); 1246 return error; 1247 } 1248 /* read value of register from Execution Data register */ 1249 *regVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA); 1250 1251 /* align value from left to right */ 1252 *regVal = (*regVal >> (IX_NPEDL_REG_SIZE_WORD - regSize)) & mask; 1253 1254 return 0; 1255} 1256 1257static int 1258npe_logical_reg_write(struct ixpnpe_softc *sc, uint32_t regAddr, uint32_t regVal, 1259 uint32_t regSize, uint32_t ctxtNum, int verify) 1260{ 1261 int error; 1262 1263 DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x, %u, %u)\n", 1264 __func__, regAddr, regVal, regSize, ctxtNum); 1265 if (regSize == IX_NPEDL_REG_SIZE_WORD) { 1266 /* 1267 * NPE register addressing is left-to-right: e.g. |d0|d1|d2|d3| 1268 * Write upper half-word (short) to |d0|d1| 1269 */ 1270 error = npe_logical_reg_write(sc, regAddr, 1271 regVal >> IX_NPEDL_REG_SIZE_SHORT, 1272 IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify); 1273 if (error != 0) 1274 return error; 1275 1276 /* Write lower half-word (short) to |d2|d3| */ 1277 error = npe_logical_reg_write(sc, 1278 regAddr + sizeof(uint16_t), 1279 regVal & 0xffff, 1280 IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify); 1281 } else { 1282 uint32_t npeInstruction; 1283 1284 switch (regSize) { 1285 case IX_NPEDL_REG_SIZE_BYTE: 1286 npeInstruction = IX_NPEDL_INSTR_WR_REG_BYTE; 1287 regVal &= 0xff; 1288 break; 1289 case IX_NPEDL_REG_SIZE_SHORT: 1290 npeInstruction = IX_NPEDL_INSTR_WR_REG_SHORT; 1291 regVal &= 0xffff; 1292 break; 1293 default: 1294 return EINVAL; 1295 } 1296 /* fill dest operand field of inst with dest reg addr */ 1297 npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_DEST); 1298 1299 /* fill src operand field of inst with least-sig 5 bits of val*/ 1300 npeInstruction |= 1301 ((regVal & IX_NPEDL_MASK_IMMED_INSTR_SRC_DATA) << 1302 IX_NPEDL_OFFSET_INSTR_SRC); 1303 1304 /* fill coprocessor field of inst with most-sig 11 bits of val*/ 1305 npeInstruction |= 1306 ((regVal & IX_NPEDL_MASK_IMMED_INSTR_COPROC_DATA) << 1307 IX_NPEDL_DISPLACE_IMMED_INSTR_COPROC_DATA); 1308 1309 /* step execution of NPE intruction using Debug ECS */ 1310 error = npe_cpu_step(sc, npeInstruction, 1311 ctxtNum, IX_NPEDL_WR_INSTR_LDUR); 1312 } 1313 if (error != 0) { 1314 DPRINTF(sc->sc_dev, "%s(0x%x, 0x%x, %u, %u), error %u " 1315 "writing reg\n", __func__, regAddr, regVal, regSize, 1316 ctxtNum, error); 1317 return error; 1318 } 1319 if (verify) { 1320 uint32_t retRegVal; 1321 1322 error = npe_logical_reg_read(sc, regAddr, regSize, ctxtNum, 1323 &retRegVal); 1324 if (error == 0 && regVal != retRegVal) 1325 error = EIO; /* XXX ambiguous */ 1326 } 1327 return error; 1328} 1329 1330/* 1331 * There are 32 physical registers used in an NPE. These are 1332 * treated as 16 pairs of 32-bit registers. To write one of the pair, 1333 * write the pair number (0-16) to the REGMAP for Context 0. Then write 1334 * the value to register 0 or 4 in the regfile, depending on which 1335 * register of the pair is to be written 1336 */ 1337static int 1338npe_physical_reg_write(struct ixpnpe_softc *sc, 1339 uint32_t regAddr, uint32_t regValue, int verify) 1340{ 1341 int error; 1342 1343 /* 1344 * Set REGMAP for context 0 to (regAddr >> 1) to choose which pair 1345 * (0-16) of physical registers to write . 1346 */ 1347 error = npe_logical_reg_write(sc, IX_NPEDL_CTXT_REG_ADDR_REGMAP, 1348 (regAddr >> IX_NPEDL_OFFSET_PHYS_REG_ADDR_REGMAP), 1349 IX_NPEDL_REG_SIZE_SHORT, 0, verify); 1350 if (error == 0) { 1351 /* regAddr = 0 or 4 */ 1352 regAddr = (regAddr & IX_NPEDL_MASK_PHYS_REG_ADDR_LOGICAL_ADDR) * 1353 sizeof(uint32_t); 1354 error = npe_logical_reg_write(sc, regAddr, regValue, 1355 IX_NPEDL_REG_SIZE_WORD, 0, verify); 1356 } 1357 return error; 1358} 1359 1360static int 1361npe_ctx_reg_write(struct ixpnpe_softc *sc, uint32_t ctxtNum, 1362 uint32_t ctxtReg, uint32_t ctxtRegVal, int verify) 1363{ 1364 DPRINTFn(4, sc->sc_dev, "%s(%u, %u, %u)\n", 1365 __func__, ctxtNum, ctxtReg, ctxtRegVal); 1366 /* 1367 * Context 0 has no STARTPC. Instead, this value is used to set 1368 * NextPC for Background ECS, to set where NPE starts executing code 1369 */ 1370 if (ctxtNum == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STARTPC) { 1371 /* read BG_CTXT_REG_0, update NEXTPC bits, & write back to reg*/ 1372 uint32_t v = npe_ecs_reg_read(sc, IX_NPEDL_ECS_BG_CTXT_REG_0); 1373 v &= ~IX_NPEDL_MASK_ECS_REG_0_NEXTPC; 1374 v |= (ctxtRegVal << IX_NPEDL_OFFSET_ECS_REG_0_NEXTPC) & 1375 IX_NPEDL_MASK_ECS_REG_0_NEXTPC; 1376 1377 npe_ecs_reg_write(sc, IX_NPEDL_ECS_BG_CTXT_REG_0, v); 1378 return 0; 1379 } else { 1380 static const struct { 1381 uint32_t regAddress; 1382 uint32_t regSize; 1383 } regAccInfo[IX_NPEDL_CTXT_REG_MAX] = { 1384 { IX_NPEDL_CTXT_REG_ADDR_STEVT, 1385 IX_NPEDL_REG_SIZE_BYTE }, 1386 { IX_NPEDL_CTXT_REG_ADDR_STARTPC, 1387 IX_NPEDL_REG_SIZE_SHORT }, 1388 { IX_NPEDL_CTXT_REG_ADDR_REGMAP, 1389 IX_NPEDL_REG_SIZE_SHORT }, 1390 { IX_NPEDL_CTXT_REG_ADDR_CINDEX, 1391 IX_NPEDL_REG_SIZE_BYTE } 1392 }; 1393 return npe_logical_reg_write(sc, regAccInfo[ctxtReg].regAddress, 1394 ctxtRegVal, regAccInfo[ctxtReg].regSize, ctxtNum, verify); 1395 } 1396} 1397 1398/* 1399 * NPE Mailbox support. 1400 */ 1401#define IX_NPEMH_MAXTRIES 100000 1402 1403static int 1404ofifo_wait(struct ixpnpe_softc *sc) 1405{ 1406 int i; 1407 1408 for (i = 0; i < IX_NPEMH_MAXTRIES; i++) { 1409 if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_OFNE) 1410 return 1; 1411 DELAY(10); 1412 } 1413 device_printf(sc->sc_dev, "%s: timeout, last status 0x%x\n", 1414 __func__, npe_reg_read(sc, IX_NPESTAT)); 1415 return 0; 1416} 1417 1418static int 1419getmsg(struct ixpnpe_softc *sc, uint32_t msg[2]) 1420{ 1421 mtx_assert(&sc->sc_mtx, MA_OWNED); 1422 1423 if (!ofifo_wait(sc)) 1424 return EAGAIN; 1425 msg[0] = npe_reg_read(sc, IX_NPEFIFO); 1426 DPRINTF(sc->sc_dev, "%s: msg0 0x%x\n", __func__, msg[0]); 1427 if (!ofifo_wait(sc)) 1428 return EAGAIN; 1429 msg[1] = npe_reg_read(sc, IX_NPEFIFO); 1430 DPRINTF(sc->sc_dev, "%s: msg1 0x%x\n", __func__, msg[1]); 1431 return 0; 1432} 1433 1434static void 1435ixpnpe_intr(void *arg) 1436{ 1437 struct ixpnpe_softc *sc = arg; 1438 uint32_t status; 1439 1440 mtx_lock(&sc->sc_mtx); 1441 status = npe_reg_read(sc, IX_NPESTAT); 1442 DPRINTF(sc->sc_dev, "%s: status 0x%x\n", __func__, status); 1443 if ((status & IX_NPESTAT_OFINT) == 0) { 1444 /* NB: should not happen */ 1445 device_printf(sc->sc_dev, "%s: status 0x%x\n", 1446 __func__, status); 1447 /* XXX must silence interrupt? */ 1448 mtx_unlock(&sc->sc_mtx); 1449 return; 1450 } 1451 /* 1452 * A message is waiting in the output FIFO, copy it so 1453 * the interrupt will be silenced. 1454 */ 1455 if (getmsg(sc, sc->sc_msg) == 0) 1456 sc->sc_msgwaiting = 1; 1457 mtx_unlock(&sc->sc_mtx); 1458} 1459 1460static int 1461ififo_wait(struct ixpnpe_softc *sc) 1462{ 1463 int i; 1464 1465 for (i = 0; i < IX_NPEMH_MAXTRIES; i++) { 1466 if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_IFNF) 1467 return 1; 1468 DELAY(10); 1469 } 1470 device_printf(sc->sc_dev, "%s: timeout, last status 0x%x\n", 1471 __func__, npe_reg_read(sc, IX_NPESTAT)); 1472 return 0; 1473} 1474 1475static int 1476putmsg(struct ixpnpe_softc *sc, const uint32_t msg[2]) 1477{ 1478 mtx_assert(&sc->sc_mtx, MA_OWNED); 1479 1480 DPRINTF(sc->sc_dev, "%s: msg 0x%x:0x%x\n", __func__, msg[0], msg[1]); 1481 if (!ififo_wait(sc)) 1482 return EIO; 1483 npe_reg_write(sc, IX_NPEFIFO, msg[0]); 1484 if (!ififo_wait(sc)) 1485 return EIO; 1486 npe_reg_write(sc, IX_NPEFIFO, msg[1]); 1487 1488 return 0; 1489} 1490 1491/* 1492 * Send a msg to the NPE and wait for a reply. We spin as 1493 * we may be called early with interrupts not properly setup. 1494 */ 1495int 1496ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *sc, 1497 const uint32_t send[2], uint32_t recv[2]) 1498{ 1499 int error; 1500 1501 mtx_lock(&sc->sc_mtx); 1502 error = putmsg(sc, send); 1503 if (error == 0) 1504 error = getmsg(sc, recv); 1505 mtx_unlock(&sc->sc_mtx); 1506 1507 return error; 1508} 1509 1510/* 1511 * Send a msg to the NPE w/o waiting for a reply. 1512 */ 1513int 1514ixpnpe_sendmsg_async(struct ixpnpe_softc *sc, const uint32_t msg[2]) 1515{ 1516 int error; 1517 1518 mtx_lock(&sc->sc_mtx); 1519 error = putmsg(sc, msg); 1520 mtx_unlock(&sc->sc_mtx); 1521 1522 return error; 1523} 1524 1525static int 1526recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2]) 1527{ 1528 mtx_assert(&sc->sc_mtx, MA_OWNED); 1529 1530 DPRINTF(sc->sc_dev, "%s: msgwaiting %d\n", __func__, sc->sc_msgwaiting); 1531 if (sc->sc_msgwaiting) { 1532 msg[0] = sc->sc_msg[0]; 1533 msg[1] = sc->sc_msg[1]; 1534 sc->sc_msgwaiting = 0; 1535 return 0; 1536 } 1537 return EAGAIN; 1538} 1539 1540/* 1541 * Receive any msg previously received from the NPE. If nothing 1542 * is available we return EAGAIN and the caller is required to 1543 * do a synchronous receive or try again later. 1544 */ 1545int 1546ixpnpe_recvmsg_async(struct ixpnpe_softc *sc, uint32_t msg[2]) 1547{ 1548 int error; 1549 1550 mtx_lock(&sc->sc_mtx); 1551 error = recvmsg_locked(sc, msg); 1552 mtx_unlock(&sc->sc_mtx); 1553 1554 return error; 1555} 1556 1557/* 1558 * Receive a msg from the NPE. If one was received asynchronously 1559 * then it's returned; otherwise we poll synchronously. 1560 */ 1561int 1562ixpnpe_recvmsg_sync(struct ixpnpe_softc *sc, uint32_t msg[2]) 1563{ 1564 int error; 1565 1566 mtx_lock(&sc->sc_mtx); 1567 error = recvmsg_locked(sc, msg); 1568 if (error == EAGAIN) 1569 error = getmsg(sc, msg); 1570 mtx_unlock(&sc->sc_mtx); 1571 1572 return error; 1573} 1574