/* $OpenBSD: if_ie_gsc.c,v 1.25 2004/10/28 19:13:30 mickey Exp $ */ /* * Copyright (c) 1998-2004 Michael Shalayeff * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * References: * 1. 82596DX and 82596SX High-Performance 32-bit Local Area Network Coprocessor * Intel Corporation, November 1996, Order Number: 290219-006 * * 2. 712 I/O Subsystem ERS Rev 1.0 * Hewlett-Packard, June 17 1992, Dwg No. A-A2263-66510-31 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IEGSC_GECKO IEMD_FLAG0 struct ie_gsc_regs { u_int32_t ie_reset; u_int32_t ie_port; u_int32_t ie_attn; }; #define IE_SIZE 0x8000 int ie_gsc_probe(struct device *, void *, void *); void ie_gsc_attach(struct device *, struct device *, void *); struct cfattach ie_gsc_ca = { sizeof(struct ie_softc), ie_gsc_probe, ie_gsc_attach }; static int ie_gsc_media[] = { IFM_ETHER | IFM_10_2, }; #define IE_NMEDIA (sizeof(ie_gsc_media) / sizeof(ie_gsc_media[0])) char *ie_mem; void ie_gsc_reset(struct ie_softc *sc, int what); void ie_gsc_attend(struct ie_softc *sc); void ie_gsc_run(struct ie_softc *sc); void ie_gsc_port(struct ie_softc *sc, u_int); #ifdef USELEDS int ie_gsc_intrhook(struct ie_softc *sc, int what); #endif u_int16_t ie_gsc_read16(struct ie_softc *sc, int offset); void ie_gsc_write16(struct ie_softc *sc, int offset, u_int16_t v); void ie_gsc_write24(struct ie_softc *sc, int offset, int addr); void ie_gsc_memcopyin(struct ie_softc *sc, void *p, int offset, size_t); void ie_gsc_memcopyout(struct ie_softc *sc, const void *p, int, size_t); void ie_gsc_reset(sc, what) struct ie_softc *sc; int what; { volatile struct ie_gsc_regs *r = (struct ie_gsc_regs *)sc->ioh; int i; r->ie_reset = 0; /* * per [2] 4.6.2.1 * delay for 10 system clocks + 5 transmit clocks, * NB: works for system clocks over 10MHz */ DELAY(1000); switch (what) { case IE_CHIP_PROBE: break; case IE_CARD_RESET: /* * after the hardware reset: * inform i825[89]6 about new SCP address, * maddr must be at least 16-byte aligned */ ie_gsc_port(sc, IE_PORT_SCP); ie_gsc_attend(sc); for (i = 9000; i-- && ie_gsc_read16(sc, IE_ISCP_BUSY(sc->iscp)); DELAY(100)) pdcache(0, sc->sc_maddr + sc->iscp, IE_ISCP_SZ); #ifdef I82596_DEBUG if (i < 0) { printf("timeout for PORT command (%x)%s\n", ie_gsc_read16(sc, IE_ISCP_BUSY(sc->iscp)), (sc->sc_flags & IEGSC_GECKO)? " on gecko":""); return; } #endif break; } } void ie_gsc_attend(sc) struct ie_softc *sc; { volatile struct ie_gsc_regs *r = (struct ie_gsc_regs *)sc->ioh; fdcache(0, (vaddr_t)ie_mem, IE_SIZE); DELAY(1); r->ie_attn = 0; DELAY(1); } void ie_gsc_run(sc) struct ie_softc *sc; { } void ie_gsc_port(sc, cmd) struct ie_softc *sc; u_int cmd; { switch (cmd) { case IE_PORT_RESET: cmd = 0; break; case IE_PORT_TEST: cmd = ((u_int)sc->sc_maddr + sc->scp) | 1; break; case IE_PORT_SCP: cmd = ((u_int)sc->sc_maddr + sc->scp) | 2; break; case IE_PORT_DUMP: cmd = 3; break; } if (sc->sc_flags & IEGSC_GECKO) { volatile struct ie_gsc_regs *r = (struct ie_gsc_regs *)sc->ioh; r->ie_port = cmd & 0xffff; DELAY(1000); r->ie_port = cmd >> 16; DELAY(1000); } else { volatile struct ie_gsc_regs *r = (struct ie_gsc_regs *)sc->ioh; r->ie_port = cmd >> 16; DELAY(1000); r->ie_port = cmd & 0xffff; DELAY(1000); } } #ifdef USELEDS int ie_gsc_intrhook(sc, where) struct ie_softc *sc; int where; { switch (where) { case IE_INTR_ENRCV: ledctl(PALED_NETRCV, 0, 0); break; case IE_INTR_ENSND: ledctl(PALED_NETSND, 0, 0); break; case IE_INTR_EXIT: case IE_INTR_LOOP: fdcache(0, (vaddr_t)ie_mem, IE_SIZE); break; } return 0; } #endif u_int16_t ie_gsc_read16(sc, offset) struct ie_softc *sc; int offset; { volatile u_int16_t *addr = (volatile u_int16_t *)(sc->bh + offset); asm __volatile ("fdc %%r0(%%sr0, %0)" :: "r" (addr)); return *addr; } void ie_gsc_write16(sc, offset, v) struct ie_softc *sc; int offset; u_int16_t v; { volatile u_int16_t *addr = (volatile u_int16_t *)(sc->bh + offset); *addr = v; asm __volatile ("fdc %%r0(%%sr0, %0)" :: "r" (addr)); } void ie_gsc_write24(sc, offset, v) struct ie_softc *sc; int offset; int v; { volatile u_int16_t *addr = (volatile u_int16_t *)(sc->bh + offset); addr[0] = (v ) & 0xffff; addr[1] = (v >> 16) & 0xffff; asm __volatile ("fdc %%r0(%%sr0, %0)" :: "r" (addr+0)); asm __volatile ("fdc %%r0(%%sr0, %0)" :: "r" (addr+1)); } void ie_gsc_memcopyin(sc, p, offset, size) struct ie_softc *sc; void *p; int offset; size_t size; { pdcache(0, sc->bh + offset, size); bcopy ((void *)((u_long)sc->bh + offset), p, size); } void ie_gsc_memcopyout(sc, p, offset, size) struct ie_softc *sc; const void *p; int offset; size_t size; { bcopy (p, (void *)((u_long)sc->bh + offset), size); fdcache(0, sc->bh + offset, size); } int ie_gsc_probe(parent, match, aux) struct device *parent; void *match, *aux; { struct gsc_attach_args *ga = aux; if (ga->ga_type.iodc_type != HPPA_TYPE_FIO || (ga->ga_type.iodc_sv_model != HPPA_FIO_LAN && ga->ga_type.iodc_sv_model != HPPA_FIO_GLAN)) return 0; return 1; } void ie_gsc_attach(parent, self, aux) struct device *parent, *self; void *aux; { struct pdc_lan_station_id pdc_mac PDC_ALIGNMENT; struct ie_softc *sc = (struct ie_softc *)self; struct gsc_attach_args *ga = aux; /*bus_dma_segment_t seg; int rseg;*/ int rv; #ifdef PMAPDEBUG extern int pmapdebug; int opmapdebug = pmapdebug; pmapdebug = 0; #endif sc->iot = sc->bt = ga->ga_iot; if (bus_space_map(sc->iot, ga->ga_hpa, IOMOD_HPASIZE, 0, &sc->ioh)) { printf(": can't map IO space\n"); return; } if (ga->ga_type.iodc_sv_model == HPPA_FIO_GLAN) sc->sc_flags |= IEGSC_GECKO; sc->sc_msize = IE_SIZE; /* XXX memory must be under 16M until the mi part is fixed */ #if 0 if (bus_dmamem_alloc(ga->ga_dmatag, sc->sc_msize, NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) { printf (": cannot allocate %d bytes of DMA memory\n", sc->sc_msize); return; } if (bus_dmamem_map(ga->ga_dmatag, &seg, rseg, sc->sc_msize, (caddr_t *)&sc->bh, BUS_DMA_NOWAIT)) { printf (": cannot map DMA memory\n"); bus_dmamem_free(ga->ga_dmatag, &seg, rseg); return; } bzero((void *)sc->bh, sc->sc_msize); sc->sc_maddr = kvtop((caddr_t)sc->bh); #else sc->bh = (u_int)ie_mem; sc->sc_maddr = sc->bh; #endif sc->sysbus = 0x40 | IE_SYSBUS_82586 | IE_SYSBUS_INTLOW | IE_SYSBUS_TRG | IE_SYSBUS_BE; sc->do_xmitnopchain = 0; sc->hwreset = ie_gsc_reset; sc->chan_attn = ie_gsc_attend; sc->port = ie_gsc_port; sc->hwinit = ie_gsc_run; sc->memcopyout = ie_gsc_memcopyout; sc->memcopyin = ie_gsc_memcopyin; sc->ie_bus_read16 = ie_gsc_read16; sc->ie_bus_write16 = ie_gsc_write16; sc->ie_bus_write24 = ie_gsc_write24; #ifdef USELEDS sc->intrhook = ie_gsc_intrhook; #else sc->intrhook = NULL; #endif #ifdef I82596_DEBUG printf(" mem %x[%p]/%x", sc->bh, sc->sc_maddr, sc->sc_msize); sc->sc_debug = IED_ALL; #endif rv = i82596_probe(sc); if (!rv) { /*bus_dmamem_free(ga->ga_dmatag, &seg, sc->sc_msize);*/ } #ifdef PMAPDEBUG pmapdebug = opmapdebug; #endif if (!rv) { printf("\n"); return; } if (pdc_call((iodcio_t)pdc, 0, PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ, &pdc_mac, ga->ga_hpa) < 0) bcopy((void *)ASP_PROM, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); else bcopy(pdc_mac.addr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); printf(":"); sc->iscp = 0; sc->scp = 32; sc->scb = 94; sc->buf_area = 256; sc->buf_area_sz = sc->sc_msize - sc->buf_area; sc->sc_type = sc->sc_flags & IEGSC_GECKO? "LASI/i82596CA" : "i82596DX"; sc->sc_vers = ga->ga_type.iodc_model * 10 + ga->ga_type.iodc_sv_rev; i82596_attach(sc, sc->sc_type, (char *)sc->sc_arpcom.ac_enaddr, ie_gsc_media, IE_NMEDIA, ie_gsc_media[0]); sc->sc_ih = gsc_intr_establish((struct gsc_softc *)parent, ga->ga_irq, IPL_NET, i82596_intr, sc, sc->sc_dev.dv_xname); }