1*134268ccSskrll /* $NetBSD: if_ie_gsc.c,v 1.5 2020/04/15 15:50:15 skrll Exp $ */
26d3ceb1dSskrll
36d3ceb1dSskrll /* $OpenBSD: if_ie_gsc.c,v 1.6 2001/01/12 22:57:04 mickey Exp $ */
46d3ceb1dSskrll
56d3ceb1dSskrll /*
66d3ceb1dSskrll * Copyright (c) 1998-2004 Michael Shalayeff
76d3ceb1dSskrll * All rights reserved.
86d3ceb1dSskrll *
96d3ceb1dSskrll * Redistribution and use in source and binary forms, with or without
106d3ceb1dSskrll * modification, are permitted provided that the following conditions
116d3ceb1dSskrll * are met:
126d3ceb1dSskrll * 1. Redistributions of source code must retain the above copyright
136d3ceb1dSskrll * notice, this list of conditions and the following disclaimer.
146d3ceb1dSskrll * 2. Redistributions in binary form must reproduce the above copyright
156d3ceb1dSskrll * notice, this list of conditions and the following disclaimer in the
166d3ceb1dSskrll * documentation and/or other materials provided with the distribution.
176d3ceb1dSskrll *
186d3ceb1dSskrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
196d3ceb1dSskrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
206d3ceb1dSskrll * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
216d3ceb1dSskrll * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
226d3ceb1dSskrll * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
236d3ceb1dSskrll * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
246d3ceb1dSskrll * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
256d3ceb1dSskrll * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
266d3ceb1dSskrll * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
276d3ceb1dSskrll * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
286d3ceb1dSskrll * THE POSSIBILITY OF SUCH DAMAGE.
296d3ceb1dSskrll */
306d3ceb1dSskrll
316d3ceb1dSskrll /*
326d3ceb1dSskrll * Referencies:
3332cded6cSdholland * 1. 82596DX and 82596SX High-Performance 32-bit Local Area Network Coprocessor
346d3ceb1dSskrll * Intel Corporation, November 1996, Order Number: 290219-006
356d3ceb1dSskrll *
366d3ceb1dSskrll * 2. 712 I/O Subsystem ERS Rev 1.0
376d3ceb1dSskrll * Hewlett-Packard, June 17 1992, Dwg No. A-A2263-66510-31
386d3ceb1dSskrll */
396d3ceb1dSskrll
406d3ceb1dSskrll #include <sys/cdefs.h>
41*134268ccSskrll __KERNEL_RCSID(0, "$NetBSD: if_ie_gsc.c,v 1.5 2020/04/15 15:50:15 skrll Exp $");
426d3ceb1dSskrll
436d3ceb1dSskrll #include <sys/param.h>
446d3ceb1dSskrll #include <sys/systm.h>
456d3ceb1dSskrll #include <sys/device.h>
466d3ceb1dSskrll #include <sys/socket.h>
476d3ceb1dSskrll #include <sys/sockio.h>
486d3ceb1dSskrll
496d3ceb1dSskrll #include <uvm/uvm_extern.h>
506d3ceb1dSskrll
516d3ceb1dSskrll #include <net/if.h>
526d3ceb1dSskrll #include <net/if_dl.h>
536d3ceb1dSskrll #include <net/if_ether.h>
546d3ceb1dSskrll #include <net/if_types.h>
556d3ceb1dSskrll #include <net/if_media.h>
566d3ceb1dSskrll
576d3ceb1dSskrll #include <netinet/in.h>
586d3ceb1dSskrll
596d3ceb1dSskrll #include <sys/bus.h>
606d3ceb1dSskrll #include <machine/intr.h>
616d3ceb1dSskrll #include <machine/iomod.h>
626d3ceb1dSskrll #include <machine/autoconf.h>
636d3ceb1dSskrll
646d3ceb1dSskrll #include <hppa/dev/cpudevs.h>
656d3ceb1dSskrll #include <hppa/gsc/gscbusvar.h>
666d3ceb1dSskrll #include <hppa/hppa/machdep.h>
676d3ceb1dSskrll
686d3ceb1dSskrll #include <dev/ic/i82586reg.h>
696d3ceb1dSskrll #include <dev/ic/i82586var.h>
706d3ceb1dSskrll
716d3ceb1dSskrll #define I82596_DEBUG I82586_DEBUG
726d3ceb1dSskrll
736d3ceb1dSskrll #ifdef __for_reference_only
746d3ceb1dSskrll struct ie_gsc_regs {
756d3ceb1dSskrll uint32_t ie_reset;
766d3ceb1dSskrll uint32_t ie_port;
776d3ceb1dSskrll uint32_t ie_attn;
786d3ceb1dSskrll };
796d3ceb1dSskrll #endif
806d3ceb1dSskrll
816d3ceb1dSskrll #define IE_GSC_BANK_SZ (12)
826d3ceb1dSskrll #define IE_GSC_REG_RESET (0)
836d3ceb1dSskrll #define IE_GSC_REG_PORT (4)
846d3ceb1dSskrll #define IE_GSC_REG_ATTN (8)
856d3ceb1dSskrll
866d3ceb1dSskrll #define IE_GSC_ALIGN(v) ((((u_int) (v)) + 0xf) & ~0xf)
876d3ceb1dSskrll
886d3ceb1dSskrll #define IE_GSC_SYSBUS (IE_SYSBUS_596_RSVD_SET | \
896d3ceb1dSskrll IE_SYSBUS_596_82586 | \
906d3ceb1dSskrll IE_SYSBUS_596_INTLOW | \
916d3ceb1dSskrll IE_SYSBUS_596_TRGEXT | \
926d3ceb1dSskrll IE_SYSBUS_596_BE)
936d3ceb1dSskrll
946d3ceb1dSskrll #define IE_SIZE 0x8000
956d3ceb1dSskrll
966d3ceb1dSskrll struct ie_gsc_softc {
976d3ceb1dSskrll struct ie_softc ie;
986d3ceb1dSskrll
996d3ceb1dSskrll /* tag and handle to hppa-specific adapter registers. */
1006d3ceb1dSskrll bus_space_tag_t iot;
1016d3ceb1dSskrll bus_space_handle_t ioh;
1026d3ceb1dSskrll
1036d3ceb1dSskrll /* bus_dma_tag_t for the memory used by the adapter. */
1046d3ceb1dSskrll bus_dma_tag_t iemt;
1056d3ceb1dSskrll
1066d3ceb1dSskrll /* interrupt handle. */
1076d3ceb1dSskrll void *sc_ih;
1086d3ceb1dSskrll
1096d3ceb1dSskrll /* miscellaneous flags. */
1106d3ceb1dSskrll int flags;
1116d3ceb1dSskrll #define IEGSC_GECKO (1 << 0)
1126d3ceb1dSskrll };
1136d3ceb1dSskrll
1146d3ceb1dSskrll int ie_gsc_probe(device_t, cfdata_t, void *);
1156d3ceb1dSskrll void ie_gsc_attach(device_t, device_t, void *);
1166d3ceb1dSskrll
1176d3ceb1dSskrll CFATTACH_DECL_NEW(ie_gsc, sizeof(struct ie_gsc_softc),
1186d3ceb1dSskrll ie_gsc_probe, ie_gsc_attach, NULL, NULL);
1196d3ceb1dSskrll
1206d3ceb1dSskrll static int ie_gsc_media[] = {
1216d3ceb1dSskrll IFM_ETHER | IFM_10_2,
1226d3ceb1dSskrll };
12314d9bb32Smsaitoh #define IE_NMEDIA __arraycount(ie_gsc_media)
1246d3ceb1dSskrll
1256d3ceb1dSskrll void ie_gsc_reset(struct ie_softc *, int);
1266d3ceb1dSskrll void ie_gsc_attend(struct ie_softc *, int);
1276d3ceb1dSskrll void ie_gsc_run(struct ie_softc *);
1286d3ceb1dSskrll void ie_gsc_port(struct ie_softc *, u_int);
1296d3ceb1dSskrll uint16_t ie_gsc_read16(struct ie_softc *, int);
1306d3ceb1dSskrll void ie_gsc_write16(struct ie_softc *, int, uint16_t);
1316d3ceb1dSskrll void ie_gsc_write24(struct ie_softc *, int, int);
1326d3ceb1dSskrll void ie_gsc_memcopyin(struct ie_softc *, void *, int, size_t);
1336d3ceb1dSskrll void ie_gsc_memcopyout(struct ie_softc *, const void *, int, size_t);
1346d3ceb1dSskrll
1356d3ceb1dSskrll
1366d3ceb1dSskrll /* Reset the adapter. */
1376d3ceb1dSskrll void
ie_gsc_reset(struct ie_softc * sc,int what)1386d3ceb1dSskrll ie_gsc_reset(struct ie_softc *sc, int what)
1396d3ceb1dSskrll {
1406d3ceb1dSskrll struct ie_gsc_softc *gsc = (struct ie_gsc_softc *)sc;
1416d3ceb1dSskrll int i;
1426d3ceb1dSskrll
1436d3ceb1dSskrll switch (what) {
1446d3ceb1dSskrll case CHIP_PROBE:
1456d3ceb1dSskrll bus_space_write_4(gsc->iot, gsc->ioh, IE_GSC_REG_RESET, 0);
1466d3ceb1dSskrll break;
1476d3ceb1dSskrll
1486d3ceb1dSskrll case CARD_RESET:
1496d3ceb1dSskrll bus_space_write_4(gsc->iot, gsc->ioh, IE_GSC_REG_RESET, 0);
1506d3ceb1dSskrll
1516d3ceb1dSskrll /*
15214d9bb32Smsaitoh * Per [2] 4.6.2.1
1536d3ceb1dSskrll * delay for 10 system clocks + 5 transmit clocks,
1546d3ceb1dSskrll * NB: works for system clocks over 10MHz
1556d3ceb1dSskrll */
1566d3ceb1dSskrll DELAY(1000);
1576d3ceb1dSskrll
1586d3ceb1dSskrll /*
15914d9bb32Smsaitoh * After the hardware reset:
1606d3ceb1dSskrll * inform i825[89]6 about new SCP address,
1616d3ceb1dSskrll * which must be at least 16-byte aligned
1626d3ceb1dSskrll */
1636d3ceb1dSskrll ie_gsc_port(sc, IE_PORT_ALT_SCP);
1646d3ceb1dSskrll ie_gsc_attend(sc, what);
1656d3ceb1dSskrll
1666d3ceb1dSskrll for (i = 9000; i-- && ie_gsc_read16(sc, IE_ISCP_BUSY(sc->iscp));
1676d3ceb1dSskrll DELAY(100))
16814d9bb32Smsaitoh pdcache(0, (vaddr_t)sc->sc_maddr + sc->iscp,
16914d9bb32Smsaitoh IE_ISCP_SZ);
1706d3ceb1dSskrll
1716d3ceb1dSskrll #if I82596_DEBUG
1726d3ceb1dSskrll if (i < 0) {
1736d3ceb1dSskrll printf("timeout for PORT command (%x)%s\n",
1746d3ceb1dSskrll ie_gsc_read16(sc, IE_ISCP_BUSY(sc->iscp)),
1756d3ceb1dSskrll (gsc->flags & IEGSC_GECKO)? " on gecko":"");
1766d3ceb1dSskrll return;
1776d3ceb1dSskrll }
1786d3ceb1dSskrll #endif
1796d3ceb1dSskrll break;
1806d3ceb1dSskrll }
1816d3ceb1dSskrll }
1826d3ceb1dSskrll
1836d3ceb1dSskrll /* Do a channel attention on the adapter. */
1846d3ceb1dSskrll void
ie_gsc_attend(struct ie_softc * sc,int why)1856d3ceb1dSskrll ie_gsc_attend(struct ie_softc *sc, int why)
1866d3ceb1dSskrll {
1876d3ceb1dSskrll struct ie_gsc_softc *gsc = (struct ie_gsc_softc *)sc;
1886d3ceb1dSskrll
1896d3ceb1dSskrll bus_space_write_4(gsc->iot, gsc->ioh, IE_GSC_REG_ATTN, 0);
1906d3ceb1dSskrll }
1916d3ceb1dSskrll
1926d3ceb1dSskrll /* Enable the adapter. */
1936d3ceb1dSskrll void
ie_gsc_run(struct ie_softc * sc)1946d3ceb1dSskrll ie_gsc_run(struct ie_softc *sc)
1956d3ceb1dSskrll {
1966d3ceb1dSskrll }
1976d3ceb1dSskrll
1986d3ceb1dSskrll /* Run an i82596 PORT command on the adapter. */
1996d3ceb1dSskrll void
ie_gsc_port(struct ie_softc * sc,u_int cmd)2006d3ceb1dSskrll ie_gsc_port(struct ie_softc *sc, u_int cmd)
2016d3ceb1dSskrll {
2026d3ceb1dSskrll struct ie_gsc_softc *gsc = (struct ie_gsc_softc *)sc;
2036d3ceb1dSskrll
2046d3ceb1dSskrll switch (cmd) {
2056d3ceb1dSskrll case IE_PORT_RESET:
2066d3ceb1dSskrll case IE_PORT_DUMP:
2076d3ceb1dSskrll break;
2086d3ceb1dSskrll case IE_PORT_SELF_TEST:
2096d3ceb1dSskrll cmd |= (sc->sc_dmamap->dm_segs[0].ds_addr + 0);
2106d3ceb1dSskrll break;
2116d3ceb1dSskrll case IE_PORT_ALT_SCP:
2126d3ceb1dSskrll cmd |= (sc->sc_dmamap->dm_segs[0].ds_addr + sc->scp);
2136d3ceb1dSskrll break;
2146d3ceb1dSskrll }
2156d3ceb1dSskrll
2166d3ceb1dSskrll if (gsc->flags & IEGSC_GECKO) {
2176d3ceb1dSskrll bus_space_write_4(gsc->iot, gsc->ioh,
2186d3ceb1dSskrll IE_GSC_REG_PORT, (cmd & 0xffff));
2196d3ceb1dSskrll DELAY(1000);
2206d3ceb1dSskrll bus_space_write_4(gsc->iot, gsc->ioh,
2216d3ceb1dSskrll IE_GSC_REG_PORT, (cmd >> 16));
2226d3ceb1dSskrll DELAY(1000);
2236d3ceb1dSskrll } else {
2246d3ceb1dSskrll bus_space_write_4(gsc->iot, gsc->ioh,
2256d3ceb1dSskrll IE_GSC_REG_PORT, (cmd >> 16));
2266d3ceb1dSskrll DELAY(1000);
2276d3ceb1dSskrll bus_space_write_4(gsc->iot, gsc->ioh,
2286d3ceb1dSskrll IE_GSC_REG_PORT, (cmd & 0xffff));
2296d3ceb1dSskrll DELAY(1000);
2306d3ceb1dSskrll }
2316d3ceb1dSskrll }
2326d3ceb1dSskrll
2336d3ceb1dSskrll uint16_t
ie_gsc_read16(struct ie_softc * sc,int offset)2346d3ceb1dSskrll ie_gsc_read16(struct ie_softc *sc, int offset)
2356d3ceb1dSskrll {
2366d3ceb1dSskrll uint16_t val;
2376d3ceb1dSskrll
2386d3ceb1dSskrll __asm volatile(
2396d3ceb1dSskrll " ldh 0(%1), %0 \n"
2406d3ceb1dSskrll " fdc %%r0(%1) \n"
2416d3ceb1dSskrll : "=&r" (val)
2426d3ceb1dSskrll : "r" ((char *)sc->sc_maddr + offset));
24314d9bb32Smsaitoh return val;
2446d3ceb1dSskrll }
2456d3ceb1dSskrll
2466d3ceb1dSskrll void
ie_gsc_write16(struct ie_softc * sc,int offset,uint16_t v)2476d3ceb1dSskrll ie_gsc_write16(struct ie_softc *sc, int offset, uint16_t v)
2486d3ceb1dSskrll {
2496d3ceb1dSskrll
2506d3ceb1dSskrll __asm volatile(
2516d3ceb1dSskrll " sth %0, 0(%1) \n"
2526d3ceb1dSskrll " fdc %%r0(%1) \n"
2536d3ceb1dSskrll : /* no outputs */
2546d3ceb1dSskrll : "r" (v), "r" ((char *)sc->sc_maddr + offset));
2556d3ceb1dSskrll }
2566d3ceb1dSskrll
2576d3ceb1dSskrll void
ie_gsc_write24(struct ie_softc * sc,int offset,int addr)2586d3ceb1dSskrll ie_gsc_write24(struct ie_softc *sc, int offset, int addr)
2596d3ceb1dSskrll {
2606d3ceb1dSskrll
2616d3ceb1dSskrll /*
2626d3ceb1dSskrll * i82586.c assumes that the chip address space starts at
2636d3ceb1dSskrll * zero, so we have to add in the appropriate offset here.
2646d3ceb1dSskrll */
2656d3ceb1dSskrll addr += sc->sc_dmamap->dm_segs[0].ds_addr;
2666d3ceb1dSskrll __asm volatile(
2676d3ceb1dSskrll " ldi 2, %%r21 \n"
2686d3ceb1dSskrll " extru %0, 15, 16, %%r22 \n"
2696d3ceb1dSskrll " sth %0, 0(%1) \n"
2706d3ceb1dSskrll " sth %%r22, 2(%1) \n"
2716d3ceb1dSskrll " fdc %%r0(%1) \n"
2726d3ceb1dSskrll " fdc %%r21(%1) \n"
2736d3ceb1dSskrll : /* No outputs */
2746d3ceb1dSskrll : "r" (addr), "r" ((char *)sc->sc_maddr + offset)
2756d3ceb1dSskrll : "r21", "r22");
2766d3ceb1dSskrll }
2776d3ceb1dSskrll
2786d3ceb1dSskrll void
ie_gsc_memcopyin(struct ie_softc * sc,void * p,int offset,size_t size)2796d3ceb1dSskrll ie_gsc_memcopyin(struct ie_softc *sc, void *p, int offset, size_t size)
2806d3ceb1dSskrll {
2816d3ceb1dSskrll struct ie_gsc_softc *gsc = (struct ie_gsc_softc *)sc;
2826d3ceb1dSskrll
2836d3ceb1dSskrll if (size == 0)
2846d3ceb1dSskrll return;
2856d3ceb1dSskrll
2866d3ceb1dSskrll memcpy(p, (char *)sc->sc_maddr + offset, size);
2876d3ceb1dSskrll bus_dmamap_sync(gsc->iemt, sc->sc_dmamap, offset, size,
2886d3ceb1dSskrll BUS_DMASYNC_PREREAD);
2896d3ceb1dSskrll hppa_led_blink(HPPA_LED_NETRCV);
2906d3ceb1dSskrll }
2916d3ceb1dSskrll
2926d3ceb1dSskrll void
ie_gsc_memcopyout(struct ie_softc * sc,const void * p,int offset,size_t size)2936d3ceb1dSskrll ie_gsc_memcopyout(struct ie_softc *sc, const void *p, int offset, size_t size)
2946d3ceb1dSskrll {
2956d3ceb1dSskrll struct ie_gsc_softc *gsc = (struct ie_gsc_softc *)sc;
2966d3ceb1dSskrll
2976d3ceb1dSskrll if (size == 0)
2986d3ceb1dSskrll return;
2996d3ceb1dSskrll
3006d3ceb1dSskrll memcpy((char *)sc->sc_maddr + offset, p, size);
3016d3ceb1dSskrll bus_dmamap_sync(gsc->iemt, sc->sc_dmamap, offset, size,
3026d3ceb1dSskrll BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
3036d3ceb1dSskrll hppa_led_blink(HPPA_LED_NETSND);
3046d3ceb1dSskrll }
3056d3ceb1dSskrll
3066d3ceb1dSskrll /*
3076d3ceb1dSskrll * i82596 probe routine
3086d3ceb1dSskrll */
3096d3ceb1dSskrll int i82596_probe(struct ie_softc *);
3106d3ceb1dSskrll int
i82596_probe(struct ie_softc * sc)3116d3ceb1dSskrll i82596_probe(struct ie_softc *sc)
3126d3ceb1dSskrll {
3136d3ceb1dSskrll struct ie_gsc_softc *gsc = (struct ie_gsc_softc *)sc;
3146d3ceb1dSskrll int i;
3156d3ceb1dSskrll
3166d3ceb1dSskrll /* Set up the SCP. */
3176d3ceb1dSskrll sc->ie_bus_write16(sc, IE_SCP_BUS_USE(sc->scp), IE_GSC_SYSBUS);
3186d3ceb1dSskrll sc->ie_bus_write24(sc, IE_SCP_ISCP(sc->scp), sc->iscp);
3196d3ceb1dSskrll
3206d3ceb1dSskrll /* Set up the ISCP. */
3216d3ceb1dSskrll sc->ie_bus_write16(sc, IE_ISCP_SCB(sc->iscp), sc->scb);
3226d3ceb1dSskrll sc->ie_bus_write24(sc, IE_ISCP_BASE(sc->iscp), 0);
3236d3ceb1dSskrll
3246d3ceb1dSskrll /* Set BUSY in the ISCP. */
3256d3ceb1dSskrll sc->ie_bus_write16(sc, IE_ISCP_BUSY(sc->iscp), 1);
3266d3ceb1dSskrll
3276d3ceb1dSskrll /* Reset the adapter. */
3286d3ceb1dSskrll bus_dmamap_sync(gsc->iemt, sc->sc_dmamap, 0, sc->sc_msize,
3296d3ceb1dSskrll BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3306d3ceb1dSskrll sc->hwreset(sc, CARD_RESET);
3316d3ceb1dSskrll
3326d3ceb1dSskrll /* Make sure that BUSY got cleared. */
3336d3ceb1dSskrll if (sc->ie_bus_read16(sc, IE_ISCP_BUSY(sc->iscp))) {
3346d3ceb1dSskrll #if I82596_DEBUG
3356d3ceb1dSskrll printf ("%s: ISCP set failed\n", device_xname(sc->sc_dev));
3366d3ceb1dSskrll #endif
3376d3ceb1dSskrll return 0;
3386d3ceb1dSskrll }
3396d3ceb1dSskrll
3406d3ceb1dSskrll /* Run the chip self-test. */
3416d3ceb1dSskrll sc->ie_bus_write24(sc, 0, -sc->sc_dmamap->dm_segs[0].ds_addr);
3426d3ceb1dSskrll sc->ie_bus_write24(sc, 4, -(sc->sc_dmamap->dm_segs[0].ds_addr + 1));
3436d3ceb1dSskrll bus_dmamap_sync(gsc->iemt, sc->sc_dmamap, 0, sc->sc_msize,
3446d3ceb1dSskrll BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
3456d3ceb1dSskrll ie_gsc_port(sc, IE_PORT_SELF_TEST);
34614d9bb32Smsaitoh for (i = 9000; i-- && sc->ie_bus_read16(sc, 4); DELAY(100))
3476d3ceb1dSskrll pdcache(0, (vaddr_t)sc->sc_maddr, sc->sc_msize);
3486d3ceb1dSskrll
3496d3ceb1dSskrll #if I82596_DEBUG
3506d3ceb1dSskrll printf (": test %x:%x\n%s",
3516d3ceb1dSskrll *((volatile int32_t *)((char *)sc->sc_maddr + 0)),
3526d3ceb1dSskrll *((volatile int32_t *)((char *)sc->sc_maddr + 4)),
3536d3ceb1dSskrll device_xname(sc->sc_dev));
3546d3ceb1dSskrll #endif
3556d3ceb1dSskrll return 1;
3566d3ceb1dSskrll }
3576d3ceb1dSskrll
3586d3ceb1dSskrll int
ie_gsc_probe(device_t parent,cfdata_t match,void * aux)3596d3ceb1dSskrll ie_gsc_probe(device_t parent, cfdata_t match, void *aux)
3606d3ceb1dSskrll {
3616d3ceb1dSskrll struct gsc_attach_args *ga = aux;
3626d3ceb1dSskrll
3636d3ceb1dSskrll if (ga->ga_type.iodc_type != HPPA_TYPE_FIO ||
3646d3ceb1dSskrll (ga->ga_type.iodc_sv_model != HPPA_FIO_LAN &&
3656d3ceb1dSskrll ga->ga_type.iodc_sv_model != HPPA_FIO_GLAN))
3666d3ceb1dSskrll return 0;
3676d3ceb1dSskrll
3686d3ceb1dSskrll return 1;
3696d3ceb1dSskrll }
3706d3ceb1dSskrll
3716d3ceb1dSskrll void
ie_gsc_attach(device_t parent,device_t self,void * aux)3726d3ceb1dSskrll ie_gsc_attach(device_t parent, device_t self, void *aux)
3736d3ceb1dSskrll {
3746d3ceb1dSskrll struct ie_gsc_softc *gsc = device_private(self);
3756d3ceb1dSskrll struct ie_softc *sc = &gsc->ie;
3766d3ceb1dSskrll struct gsc_attach_args *ga = aux;
3776d3ceb1dSskrll bus_dma_segment_t seg;
3786d3ceb1dSskrll int rseg;
3796d3ceb1dSskrll int rv;
3806d3ceb1dSskrll uint8_t myaddr[ETHER_ADDR_LEN];
3816d3ceb1dSskrll
3826d3ceb1dSskrll if (ga->ga_type.iodc_sv_model == HPPA_FIO_GLAN)
3836d3ceb1dSskrll gsc->flags |= IEGSC_GECKO;
3846d3ceb1dSskrll
38514d9bb32Smsaitoh /* Map the GSC registers. */
3866d3ceb1dSskrll if (bus_space_map(ga->ga_iot, ga->ga_hpa,
3876d3ceb1dSskrll IE_GSC_BANK_SZ, 0, &gsc->ioh)) {
3886d3ceb1dSskrll printf(": can't map i/o space\n");
3896d3ceb1dSskrll return;
3906d3ceb1dSskrll }
3916d3ceb1dSskrll
3926d3ceb1dSskrll /* Set up some initial glue. */
3936d3ceb1dSskrll sc->sc_dev = self;
3946d3ceb1dSskrll gsc->iot = ga->ga_iot;
3956d3ceb1dSskrll gsc->iemt = ga->ga_dmatag;
3966d3ceb1dSskrll sc->bt = ga->ga_iot;
3976d3ceb1dSskrll sc->sc_msize = IE_SIZE;
3986d3ceb1dSskrll
3996d3ceb1dSskrll /*
4006d3ceb1dSskrll * Allocate one contiguous segment of physical memory
4016d3ceb1dSskrll * to be used with the i82596. Since we're running the
4026d3ceb1dSskrll * chip in i82586 mode, we're restricted to 24-bit
4036d3ceb1dSskrll * physical addresses.
4046d3ceb1dSskrll */
4056d3ceb1dSskrll if (bus_dmamem_alloc(gsc->iemt, sc->sc_msize, PAGE_SIZE, 0,
4066d3ceb1dSskrll &seg, 1, &rseg, BUS_DMA_NOWAIT | BUS_DMA_24BIT)) {
4076d3ceb1dSskrll printf (": can't allocate %d bytes of DMA memory\n",
4086d3ceb1dSskrll sc->sc_msize);
4096d3ceb1dSskrll return;
4106d3ceb1dSskrll }
4116d3ceb1dSskrll
41214d9bb32Smsaitoh /* Map that physical memory into kernel virtual space. */
4136d3ceb1dSskrll if (bus_dmamem_map(gsc->iemt, &seg, rseg, sc->sc_msize,
4146d3ceb1dSskrll (void **)&sc->sc_maddr, BUS_DMA_NOWAIT)) {
4156d3ceb1dSskrll printf (": can't map DMA memory\n");
4166d3ceb1dSskrll bus_dmamem_free(gsc->iemt, &seg, rseg);
4176d3ceb1dSskrll return;
4186d3ceb1dSskrll }
4196d3ceb1dSskrll
42014d9bb32Smsaitoh /* Create a DMA map for the memory. */
4216d3ceb1dSskrll if (bus_dmamap_create(gsc->iemt, sc->sc_msize, rseg, sc->sc_msize,
4226d3ceb1dSskrll 0, BUS_DMA_NOWAIT, &sc->sc_dmamap)) {
4236d3ceb1dSskrll printf(": can't create DMA map\n");
4246d3ceb1dSskrll bus_dmamem_unmap(gsc->iemt,
4256d3ceb1dSskrll (void *)sc->sc_maddr, sc->sc_msize);
4266d3ceb1dSskrll bus_dmamem_free(gsc->iemt, &seg, rseg);
4276d3ceb1dSskrll return;
4286d3ceb1dSskrll }
4296d3ceb1dSskrll
43014d9bb32Smsaitoh /* Load the mapped DMA memory into the DMA map. */
43114d9bb32Smsaitoh if (bus_dmamap_load(gsc->iemt, sc->sc_dmamap, sc->sc_maddr,
43214d9bb32Smsaitoh sc->sc_msize, NULL, BUS_DMA_NOWAIT)) {
4336d3ceb1dSskrll printf(": can't load DMA map\n");
4346d3ceb1dSskrll bus_dmamap_destroy(gsc->iemt, sc->sc_dmamap);
4356d3ceb1dSskrll bus_dmamem_unmap(gsc->iemt,
4366d3ceb1dSskrll (void *)sc->sc_maddr, sc->sc_msize);
4376d3ceb1dSskrll bus_dmamem_free(gsc->iemt, &seg, rseg);
4386d3ceb1dSskrll return;
4396d3ceb1dSskrll }
4406d3ceb1dSskrll
4416d3ceb1dSskrll #if 1
4426d3ceb1dSskrll /* XXX - this should go away. */
4436d3ceb1dSskrll sc->bh = (bus_space_handle_t)sc->sc_maddr;
4446d3ceb1dSskrll #endif
4456d3ceb1dSskrll
4466d3ceb1dSskrll #if I82596_DEBUG
4476d3ceb1dSskrll printf(" mem %x[%p]/%x\n%s",
4486d3ceb1dSskrll (u_int)sc->sc_dmamap->dm_segs[0].ds_addr,
4496d3ceb1dSskrll sc->sc_maddr,
4506d3ceb1dSskrll sc->sc_msize,
4516d3ceb1dSskrll device_xname(self));
4526d3ceb1dSskrll sc->sc_debug = IED_ALL;
4536d3ceb1dSskrll #endif
4546d3ceb1dSskrll
4556d3ceb1dSskrll /* Initialize our bus glue. */
4566d3ceb1dSskrll sc->hwreset = ie_gsc_reset;
4576d3ceb1dSskrll sc->chan_attn = ie_gsc_attend;
4586d3ceb1dSskrll sc->hwinit = ie_gsc_run;
4596d3ceb1dSskrll sc->memcopyout = ie_gsc_memcopyout;
4606d3ceb1dSskrll sc->memcopyin = ie_gsc_memcopyin;
4616d3ceb1dSskrll sc->ie_bus_read16 = ie_gsc_read16;
4626d3ceb1dSskrll sc->ie_bus_write16 = ie_gsc_write16;
4636d3ceb1dSskrll sc->ie_bus_write24 = ie_gsc_write24;
4646d3ceb1dSskrll sc->intrhook = NULL;
4656d3ceb1dSskrll
4666d3ceb1dSskrll /* Clear all RAM. */
4676d3ceb1dSskrll memset(sc->sc_maddr, 0, sc->sc_msize);
4686d3ceb1dSskrll bus_dmamap_sync(gsc->iemt, sc->sc_dmamap, 0, sc->sc_msize,
4696d3ceb1dSskrll BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
4706d3ceb1dSskrll
4716d3ceb1dSskrll /*
4726d3ceb1dSskrll * We use low memory to set up SCP, ICSP and SCB data
4736d3ceb1dSskrll * structures. The remaining pages become the buffer area
4746d3ceb1dSskrll * (managed in i82586.c).
4756d3ceb1dSskrll */
4766d3ceb1dSskrll
4776d3ceb1dSskrll /*
4786d3ceb1dSskrll * Since we have an i82596, we can control where where
4796d3ceb1dSskrll * the chip looks for SCP. We plan to use the first
4806d3ceb1dSskrll * two 32-bit words of memory for the self-test, so the
4816d3ceb1dSskrll * SCP can go after that.
4826d3ceb1dSskrll */
4836d3ceb1dSskrll sc->scp = IE_GSC_ALIGN(8);
4846d3ceb1dSskrll
4856d3ceb1dSskrll /* ISCP follows SCP */
4866d3ceb1dSskrll sc->iscp = IE_GSC_ALIGN(sc->scp + IE_SCP_SZ);
4876d3ceb1dSskrll
4886d3ceb1dSskrll /* SCB follows ISCP */
4896d3ceb1dSskrll sc->scb = IE_GSC_ALIGN(sc->iscp + IE_ISCP_SZ);
4906d3ceb1dSskrll
4916d3ceb1dSskrll /* The remainder of the memory is for buffers. */
4926d3ceb1dSskrll sc->buf_area = IE_GSC_ALIGN(sc->scb + IE_SCB_SZ);
4936d3ceb1dSskrll sc->buf_area_sz = sc->sc_msize - sc->buf_area;
4946d3ceb1dSskrll
4956d3ceb1dSskrll /* Finally, we can probe the chip. */
4966d3ceb1dSskrll rv = i82596_probe(sc);
4976d3ceb1dSskrll if (!rv) {
4986d3ceb1dSskrll bus_dmamap_destroy(gsc->iemt, sc->sc_dmamap);
4996d3ceb1dSskrll bus_dmamem_unmap(gsc->iemt,
5006d3ceb1dSskrll (void *)sc->sc_maddr, sc->sc_msize);
5016d3ceb1dSskrll bus_dmamem_free(gsc->iemt, &seg, rseg);
5026d3ceb1dSskrll return;
5036d3ceb1dSskrll }
5046d3ceb1dSskrll if (!rv)
5056d3ceb1dSskrll return;
5066d3ceb1dSskrll
5076d3ceb1dSskrll /* Get our Ethernet address. */
5086d3ceb1dSskrll memcpy(myaddr, ga->ga_ether_address, ETHER_ADDR_LEN);
5096d3ceb1dSskrll
5106d3ceb1dSskrll /* Set up the SCP. */
5116d3ceb1dSskrll sc->ie_bus_write16(sc, IE_SCP_BUS_USE(sc->scp), IE_GSC_SYSBUS);
5126d3ceb1dSskrll sc->ie_bus_write24(sc, IE_SCP_ISCP(sc->scp), sc->iscp);
5136d3ceb1dSskrll
5146d3ceb1dSskrll /* Set up the ISCP. */
5156d3ceb1dSskrll sc->ie_bus_write16(sc, IE_ISCP_SCB(sc->iscp), sc->scb);
5166d3ceb1dSskrll sc->ie_bus_write24(sc, IE_ISCP_BASE(sc->iscp), 0);
5176d3ceb1dSskrll
5186d3ceb1dSskrll /* Set BUSY in the ISCP. */
5196d3ceb1dSskrll sc->ie_bus_write16(sc, IE_ISCP_BUSY(sc->iscp), 1);
5206d3ceb1dSskrll
5216d3ceb1dSskrll /* Reset the adapter. */
5226d3ceb1dSskrll bus_dmamap_sync(gsc->iemt, sc->sc_dmamap, 0, sc->sc_msize,
5236d3ceb1dSskrll BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
5246d3ceb1dSskrll sc->hwreset(sc, CARD_RESET);
5256d3ceb1dSskrll bus_dmamap_sync(gsc->iemt, sc->sc_dmamap, 0, sc->sc_msize,
5266d3ceb1dSskrll BUS_DMASYNC_PREREAD);
5276d3ceb1dSskrll
5286d3ceb1dSskrll /* Now call the MI attachment. */
5296d3ceb1dSskrll printf(": v%d.%d", ga->ga_type.iodc_model, ga->ga_type.iodc_sv_rev);
5306d3ceb1dSskrll i82586_attach(sc,
5316d3ceb1dSskrll (gsc->flags & IEGSC_GECKO) ?
5326d3ceb1dSskrll "LASI/i82596CA" :
5336d3ceb1dSskrll "i82596DX",
5346d3ceb1dSskrll myaddr, ie_gsc_media, IE_NMEDIA, ie_gsc_media[0]);
5356d3ceb1dSskrll gsc->sc_ih = hppa_intr_establish(IPL_NET, i82586_intr, sc,
5366d3ceb1dSskrll ga->ga_ir, ga->ga_irq);
5376d3ceb1dSskrll }
538