diff --git a/sys/conf/files b/sys/conf/files index 97eee3329e63..cc2d33d80b7f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -469,6 +469,7 @@ dev/drm/sis_ds.c optional sisdrm dev/drm/sis_mm.c optional sisdrm dev/drm/tdfx_drv.c optional tdfxdrm dev/ed/if_ed.c optional ed +dev/ed/if_ed_novell.c optional ed dev/ed/if_ed_pccard.c optional ed pccard dev/ed/if_ed_pci.c optional ed pci dev/eisa/eisa_if.m standard diff --git a/sys/conf/files.alpha b/sys/conf/files.alpha index c3b03bee4dc3..b256fd4ef2b5 100644 --- a/sys/conf/files.alpha +++ b/sys/conf/files.alpha @@ -169,7 +169,11 @@ dev/advansys/adv_isa.c optional adv isa dev/aic/aic_isa.c optional aic isa dev/dec/mcclock.c optional mcclock dev/dec/mcclock_if.m optional mcclock +dev/ed/if_ed_3c503.c optional ed isa ed_3c503 dev/ed/if_ed_isa.c optional ed isa +dev/ed/if_ed_wd80x3.c optional ed isa +dev/ed/if_ed_hpp.c optional ed isa ed_hpp +dev/ed/if_ed_sic.c optional ed isa ed_sic dev/fb/fb.c optional fb dev/fb/fb.c optional vga dev/fb/splash.c optional splash diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 03ac732258a1..7af1fbb75f0f 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -143,7 +143,11 @@ dev/ctau/if_ct.c optional ctau dev/cx/csigma.c optional cx dev/cx/cxddk.c optional cx dev/cx/if_cx.c optional cx +dev/ed/if_ed_3c503.c optional ed isa ed_3c503 dev/ed/if_ed_isa.c optional ed isa +dev/ed/if_ed_wd80x3.c optional ed isa +dev/ed/if_ed_hpp.c optional ed isa ed_hpp +dev/ed/if_ed_sic.c optional ed isa ed_sic dev/fb/fb.c optional fb dev/fb/fb.c optional vga dev/fb/splash.c optional splash diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 6d365cdf1735..24e95a561663 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -108,6 +108,7 @@ dev/ct/bshw_machdep.c optional ct dev/ct/ct.c optional ct dev/ct/ct_isa.c optional ct isa dev/ed/if_ed_cbus.c optional ed isa +dev/ed/wd80x3.c optional ed isa dev/ed/if_ed_pccard.c optional ed card dev/ep/if_ep_pccard.c optional ep card dev/ex/if_ex_pccard.c optional ex card diff --git a/sys/conf/options b/sys/conf/options index e5b0a0d7f8d1..f104f9405703 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -616,6 +616,9 @@ EISA_SLOTS opt_eisa.h # ed driver ED_NO_MIIBUS opt_ed.h +ED_HPP opt_ed.h +ED_3C503 opt_ed.h +ED_SIC opt_ed.h # wi driver WI_SYMBOL_FIRMWARE opt_wi.h diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c index 22f970428446..4a349e5883f3 100644 --- a/sys/dev/ed/if_ed.c +++ b/sys/dev/ed/if_ed.c @@ -68,8 +68,6 @@ __FBSDID("$FreeBSD$"); #include -#include - #include #include @@ -91,67 +89,10 @@ static void ed_get_packet(struct ed_softc *, char *, u_short); static __inline void ed_rint(struct ed_softc *); static __inline void ed_xmit(struct ed_softc *); static __inline char *ed_ring_copy(struct ed_softc *, char *, char *, u_short); -static void ed_hpp_set_physical_link(struct ed_softc *); -static void ed_hpp_readmem(struct ed_softc *, long, uint8_t *, uint16_t); -static void ed_hpp_writemem(struct ed_softc *, uint8_t *, uint16_t, - uint16_t); -static u_short ed_hpp_write_mbufs(struct ed_softc *, struct mbuf *, int); - static u_short ed_pio_write_mbufs(struct ed_softc *, struct mbuf *, long); static void ed_setrcr(struct ed_softc *); -/* - * Interrupt conversion table for WD/SMC ASIC/83C584 - */ -static uint16_t ed_intr_val[] = { - 9, - 3, - 5, - 7, - 10, - 11, - 15, - 4 -}; - -/* - * Interrupt conversion table for 83C790 - */ -static uint16_t ed_790_intr_val[] = { - 0, - 9, - 3, - 5, - 7, - 10, - 11, - 15 -}; - -/* - * Interrupt conversion table for the HP PC LAN+ - */ - -static uint16_t ed_hpp_intr_val[] = { - 0, /* 0 */ - 0, /* 1 */ - 0, /* 2 */ - 3, /* 3 */ - 4, /* 4 */ - 5, /* 5 */ - 6, /* 6 */ - 7, /* 7 */ - 0, /* 8 */ - 9, /* 9 */ - 10, /* 10 */ - 11, /* 11 */ - 12, /* 12 */ - 0, /* 13 */ - 0, /* 14 */ - 15 /* 15 */ -}; - /* * Generic probe routine for testing for the existance of a DS8390. * Must be called after the NIC has just been reset. This routine @@ -188,1387 +129,6 @@ ed_probe_generic8390(struct ed_softc *sc) return (1); } -/* - * Probe and vendor-specific initialization routine for SMC/WD80x3 boards - */ -int -ed_probe_WD80x3_generic(device_t dev, int flags, uint16_t *intr_vals[]) -{ - struct ed_softc *sc = device_get_softc(dev); - int error; - int i; - u_int memsize, maddr; - u_char iptr, isa16bit, sum, totalsum; - u_long conf_maddr, conf_msize, irq, junk; - - sc->chip_type = ED_CHIP_TYPE_DP8390; - - if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { - totalsum = ED_WD_ROM_CHECKSUM_TOTAL_TOSH_ETHER; - ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_POW); - DELAY(10000); - } - else - totalsum = ED_WD_ROM_CHECKSUM_TOTAL; - - /* - * Attempt to do a checksum over the station address PROM. If it - * fails, it's probably not a SMC/WD board. There is a problem with - * this, though: some clone WD boards don't pass the checksum test. - * Danpex boards for one. - */ - for (sum = 0, i = 0; i < 8; ++i) - sum += ed_asic_inb(sc, ED_WD_PROM + i); - - if (sum != totalsum) { - - /* - * Checksum is invalid. This often happens with cheap WD8003E - * clones. In this case, the checksum byte (the eighth byte) - * seems to always be zero. - */ - if (ed_asic_inb(sc, ED_WD_CARD_ID) != ED_TYPE_WD8003E || - ed_asic_inb(sc, ED_WD_PROM + 7) != 0) - return (ENXIO); - } - /* reset card to force it into a known state. */ - if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) - ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW); - else - ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST); - - DELAY(100); - ed_asic_outb(sc, ED_WD_MSR, ed_asic_inb(sc, ED_WD_MSR) & ~ED_WD_MSR_RST); - /* wait in the case this card is reading its EEROM */ - DELAY(5000); - - sc->vendor = ED_VENDOR_WD_SMC; - sc->type = ed_asic_inb(sc, ED_WD_CARD_ID); - - /* - * Set initial values for width/size. - */ - memsize = 8192; - isa16bit = 0; - switch (sc->type) { - case ED_TYPE_WD8003S: - sc->type_str = "WD8003S"; - break; - case ED_TYPE_WD8003E: - sc->type_str = "WD8003E"; - break; - case ED_TYPE_WD8003EB: - sc->type_str = "WD8003EB"; - break; - case ED_TYPE_WD8003W: - sc->type_str = "WD8003W"; - break; - case ED_TYPE_WD8013EBT: - sc->type_str = "WD8013EBT"; - memsize = 16384; - isa16bit = 1; - break; - case ED_TYPE_WD8013W: - sc->type_str = "WD8013W"; - memsize = 16384; - isa16bit = 1; - break; - case ED_TYPE_WD8013EP: /* also WD8003EP */ - if (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) { - isa16bit = 1; - memsize = 16384; - sc->type_str = "WD8013EP"; - } else { - sc->type_str = "WD8003EP"; - } - break; - case ED_TYPE_WD8013WC: - sc->type_str = "WD8013WC"; - memsize = 16384; - isa16bit = 1; - break; - case ED_TYPE_WD8013EBP: - sc->type_str = "WD8013EBP"; - memsize = 16384; - isa16bit = 1; - break; - case ED_TYPE_WD8013EPC: - sc->type_str = "WD8013EPC"; - memsize = 16384; - isa16bit = 1; - break; - case ED_TYPE_SMC8216C: /* 8216 has 16K shared mem -- 8416 has 8K */ - case ED_TYPE_SMC8216T: - if (sc->type == ED_TYPE_SMC8216C) { - sc->type_str = "SMC8216/SMC8216C"; - } else { - sc->type_str = "SMC8216T"; - } - - ed_asic_outb(sc, ED_WD790_HWR, - ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); - switch (ed_asic_inb(sc, ED_WD790_RAR) & ED_WD790_RAR_SZ64) { - case ED_WD790_RAR_SZ64: - memsize = 65536; - break; - case ED_WD790_RAR_SZ32: - memsize = 32768; - break; - case ED_WD790_RAR_SZ16: - memsize = 16384; - break; - case ED_WD790_RAR_SZ8: - /* 8216 has 16K shared mem -- 8416 has 8K */ - if (sc->type == ED_TYPE_SMC8216C) { - sc->type_str = "SMC8416C/SMC8416BT"; - } else { - sc->type_str = "SMC8416T"; - } - memsize = 8192; - break; - } - ed_asic_outb(sc, ED_WD790_HWR, - ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); - - isa16bit = 1; - sc->chip_type = ED_CHIP_TYPE_WD790; - break; - case ED_TYPE_TOSHIBA1: - sc->type_str = "Toshiba1"; - memsize = 32768; - isa16bit = 1; - break; - case ED_TYPE_TOSHIBA4: - sc->type_str = "Toshiba4"; - memsize = 32768; - isa16bit = 1; - break; - default: - sc->type_str = ""; - break; - } - - /* - * Make some adjustments to initial values depending on what is found - * in the ICR. - */ - if (isa16bit && (sc->type != ED_TYPE_WD8013EBT) - && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4) - && ((ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { - isa16bit = 0; - memsize = 8192; - } - - error = bus_get_resource(dev, SYS_RES_MEMORY, 0, - &conf_maddr, &conf_msize); - if (error) - return (error); - -#ifdef ED_DEBUG - printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%lu\n", - sc->type, sc->type_str, isa16bit, memsize, conf_msize); - for (i = 0; i < 8; i++) - printf("%x -> %x\n", i, ed_asic_inb(sc, i)); -#endif - - /* - * Allow the user to override the autoconfiguration - */ - if (conf_msize > 1) - memsize = conf_msize; - - maddr = conf_maddr; - if (maddr < 0xa0000 || maddr + memsize > 0x1000000) { - device_printf(dev, "Invalid ISA memory address range configured: 0x%x - 0x%x\n", - maddr, maddr + memsize); - return (ENXIO); - } - - /* - * (note that if the user specifies both of the following flags that - * '8bit' mode intentionally has precedence) - */ - if (flags & ED_FLAGS_FORCE_16BIT_MODE) - isa16bit = 1; - if (flags & ED_FLAGS_FORCE_8BIT_MODE) - isa16bit = 0; - - /* - * If possible, get the assigned interrupt number from the card and - * use it. - */ - if ((sc->type & ED_WD_SOFTCONFIG) && - (sc->chip_type != ED_CHIP_TYPE_WD790)) { - - /* - * Assemble together the encoded interrupt number. - */ - iptr = (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_IR2) | - ((ed_asic_inb(sc, ED_WD_IRR) & - (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5); - - /* - * If no interrupt specified (or "?"), use what the board tells us. - */ - error = bus_get_resource(dev, SYS_RES_IRQ, 0, - &irq, &junk); - if (error && intr_vals[0] != NULL) { - error = bus_set_resource(dev, SYS_RES_IRQ, 0, - intr_vals[0][iptr], 1); - } - if (error) - return (error); - - /* - * Enable the interrupt. - */ - ed_asic_outb(sc, ED_WD_IRR, - ed_asic_inb(sc, ED_WD_IRR) | ED_WD_IRR_IEN); - } - if (sc->chip_type == ED_CHIP_TYPE_WD790) { - ed_asic_outb(sc, ED_WD790_HWR, - ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); - iptr = (((ed_asic_inb(sc, ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) | - (ed_asic_inb(sc, ED_WD790_GCR) & - (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2); - ed_asic_outb(sc, ED_WD790_HWR, - ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); - - /* - * If no interrupt specified (or "?"), use what the board tells us. - */ - error = bus_get_resource(dev, SYS_RES_IRQ, 0, - &irq, &junk); - if (error && intr_vals[1] != NULL) { - error = bus_set_resource(dev, SYS_RES_IRQ, 0, - intr_vals[1][iptr], 1); - } - if (error) - return (error); - - /* - * Enable interrupts. - */ - ed_asic_outb(sc, ED_WD790_ICR, - ed_asic_inb(sc, ED_WD790_ICR) | ED_WD790_ICR_EIL); - } - error = bus_get_resource(dev, SYS_RES_IRQ, 0, - &irq, &junk); - if (error) { - device_printf(dev, "%s cards don't support auto-detected/assigned interrupts.\n", - sc->type_str); - return (ENXIO); - } - sc->isa16bit = isa16bit; - sc->mem_shared = 1; - - error = ed_alloc_memory(dev, 0, memsize); - if (error) { - printf("*** ed_alloc_memory() failed! (%d)\n", error); - return (error); - } - sc->mem_start = (caddr_t) rman_get_virtual(sc->mem_res); - - /* - * allocate one xmit buffer if < 16k, two buffers otherwise - */ - if ((memsize < 16384) || - (flags & ED_FLAGS_NO_MULTI_BUFFERING)) { - sc->txb_cnt = 1; - } else { - sc->txb_cnt = 2; - } - sc->tx_page_start = ED_WD_PAGE_OFFSET; - sc->rec_page_start = ED_WD_PAGE_OFFSET + ED_TXBUF_SIZE * sc->txb_cnt; - sc->rec_page_stop = ED_WD_PAGE_OFFSET + memsize / ED_PAGE_SIZE; - sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * sc->rec_page_start); - sc->mem_size = memsize; - sc->mem_end = sc->mem_start + memsize; - - /* - * Get station address from on-board ROM - */ - for (i = 0; i < ETHER_ADDR_LEN; ++i) - sc->arpcom.ac_enaddr[i] = ed_asic_inb(sc, ED_WD_PROM + i); - - /* - * Set upper address bits and 8/16 bit access to shared memory. - */ - if (isa16bit) { - if (sc->chip_type == ED_CHIP_TYPE_WD790) { - sc->wd_laar_proto = ed_asic_inb(sc, ED_WD_LAAR); - } else { - sc->wd_laar_proto = ED_WD_LAAR_L16EN | - ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI); - } - /* - * Enable 16bit access - */ - ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto | - ED_WD_LAAR_M16EN); - } else { - if (((sc->type & ED_WD_SOFTCONFIG) || - (sc->type == ED_TYPE_TOSHIBA1) || - (sc->type == ED_TYPE_TOSHIBA4) || - (sc->type == ED_TYPE_WD8013EBT)) && - (sc->chip_type != ED_CHIP_TYPE_WD790)) { - sc->wd_laar_proto = (kvtop(sc->mem_start) >> 19) & - ED_WD_LAAR_ADDRHI; - ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto); - } - } - - /* - * Set address and enable interface shared memory. - */ - if (sc->chip_type != ED_CHIP_TYPE_WD790) { - if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { - ed_asic_outb(sc, ED_WD_MSR + 1, - ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4); - ed_asic_outb(sc, ED_WD_MSR + 2, - ((kvtop(sc->mem_start) >> 16) & 0x0f)); - ed_asic_outb(sc, ED_WD_MSR, - ED_WD_MSR_MENB | ED_WD_MSR_POW); - } else { - ed_asic_outb(sc, ED_WD_MSR, - ((kvtop(sc->mem_start) >> 13) & - ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); - } - sc->cr_proto = ED_CR_RD2; - } else { - ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_MENB); - ed_asic_outb(sc, ED_WD790_HWR, (ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH)); - ed_asic_outb(sc, ED_WD790_RAR, ((kvtop(sc->mem_start) >> 13) & 0x0f) | - ((kvtop(sc->mem_start) >> 11) & 0x40) | - (ed_asic_inb(sc, ED_WD790_RAR) & 0xb0)); - ed_asic_outb(sc, ED_WD790_HWR, (ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH)); - sc->cr_proto = 0; - } - -#if 0 - printf("starting memory performance test at 0x%x, size %d...\n", - sc->mem_start, memsize*16384); - for (i = 0; i < 16384; i++) - bzero(sc->mem_start, memsize); - printf("***DONE***\n"); -#endif - - /* - * Now zero memory and verify that it is clear - */ - bzero(sc->mem_start, memsize); - - for (i = 0; i < memsize; ++i) { - if (sc->mem_start[i]) { - device_printf(dev, "failed to clear shared memory at %jx - check configuration\n", - (uintmax_t)kvtop(sc->mem_start + i)); - - /* - * Disable 16 bit access to shared memory - */ - if (isa16bit) { - if (sc->chip_type == ED_CHIP_TYPE_WD790) { - ed_asic_outb(sc, ED_WD_MSR, 0x00); - } - ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto & - ~ED_WD_LAAR_M16EN); - } - return (ENXIO); - } - } - - /* - * Disable 16bit access to shared memory - we leave it - * disabled so that 1) machines reboot properly when the board - * is set 16 bit mode and there are conflicting 8bit - * devices/ROMS in the same 128k address space as this boards - * shared memory. and 2) so that other 8 bit devices with - * shared memory can be used in this 128k region, too. - */ - if (isa16bit) { - if (sc->chip_type == ED_CHIP_TYPE_WD790) { - ed_asic_outb(sc, ED_WD_MSR, 0x00); - } - ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto & - ~ED_WD_LAAR_M16EN); - } - return (0); -} - -int -ed_probe_WD80x3(device_t dev, int port_rid, int flags) -{ - struct ed_softc *sc = device_get_softc(dev); - int error; - static uint16_t *intr_vals[] = {ed_intr_val, ed_790_intr_val}; - - error = ed_alloc_port(dev, port_rid, ED_WD_IO_PORTS); - if (error) - return (error); - - sc->asic_offset = ED_WD_ASIC_OFFSET; - sc->nic_offset = ED_WD_NIC_OFFSET; - - return ed_probe_WD80x3_generic(dev, flags, intr_vals); -} - -/* - * Probe and vendor-specific initialization routine for 3Com 3c503 boards - */ -int -ed_probe_3Com(device_t dev, int port_rid, int flags) -{ - struct ed_softc *sc = device_get_softc(dev); - int error; - int i; - u_int memsize; - u_char isa16bit; - u_long conf_maddr, conf_msize, irq, junk; - - error = ed_alloc_port(dev, 0, ED_3COM_IO_PORTS); - if (error) - return (error); - - sc->asic_offset = ED_3COM_ASIC_OFFSET; - sc->nic_offset = ED_3COM_NIC_OFFSET; - - /* - * Verify that the kernel configured I/O address matches the board - * configured address - */ - switch (ed_asic_inb(sc, ED_3COM_BCFR)) { - case ED_3COM_BCFR_300: - if (rman_get_start(sc->port_res) != 0x300) - return (ENXIO); - break; - case ED_3COM_BCFR_310: - if (rman_get_start(sc->port_res) != 0x310) - return (ENXIO); - break; - case ED_3COM_BCFR_330: - if (rman_get_start(sc->port_res) != 0x330) - return (ENXIO); - break; - case ED_3COM_BCFR_350: - if (rman_get_start(sc->port_res) != 0x350) - return (ENXIO); - break; - case ED_3COM_BCFR_250: - if (rman_get_start(sc->port_res) != 0x250) - return (ENXIO); - break; - case ED_3COM_BCFR_280: - if (rman_get_start(sc->port_res) != 0x280) - return (ENXIO); - break; - case ED_3COM_BCFR_2A0: - if (rman_get_start(sc->port_res) != 0x2a0) - return (ENXIO); - break; - case ED_3COM_BCFR_2E0: - if (rman_get_start(sc->port_res) != 0x2e0) - return (ENXIO); - break; - default: - return (ENXIO); - } - - error = bus_get_resource(dev, SYS_RES_MEMORY, 0, - &conf_maddr, &conf_msize); - if (error) - return (error); - - /* - * Verify that the kernel shared memory address matches the board - * configured address. - */ - switch (ed_asic_inb(sc, ED_3COM_PCFR)) { - case ED_3COM_PCFR_DC000: - if (conf_maddr != 0xdc000) - return (ENXIO); - break; - case ED_3COM_PCFR_D8000: - if (conf_maddr != 0xd8000) - return (ENXIO); - break; - case ED_3COM_PCFR_CC000: - if (conf_maddr != 0xcc000) - return (ENXIO); - break; - case ED_3COM_PCFR_C8000: - if (conf_maddr != 0xc8000) - return (ENXIO); - break; - default: - return (ENXIO); - } - - - /* - * Reset NIC and ASIC. Enable on-board transceiver throughout reset - * sequence because it'll lock up if the cable isn't connected if we - * don't. - */ - ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL); - - /* - * Wait for a while, then un-reset it - */ - DELAY(50); - - /* - * The 3Com ASIC defaults to rather strange settings for the CR after - * a reset - it's important to set it again after the following outb - * (this is done when we map the PROM below). - */ - ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL); - - /* - * Wait a bit for the NIC to recover from the reset - */ - DELAY(5000); - - sc->vendor = ED_VENDOR_3COM; - sc->type_str = "3c503"; - sc->mem_shared = 1; - sc->cr_proto = ED_CR_RD2; - - /* - * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k window - * to it. - */ - memsize = 8192; - - /* - * Get station address from on-board ROM - */ - - /* - * First, map ethernet address PROM over the top of where the NIC - * registers normally appear. - */ - ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL); - - for (i = 0; i < ETHER_ADDR_LEN; ++i) - sc->arpcom.ac_enaddr[i] = ed_nic_inb(sc, i); - - /* - * Unmap PROM - select NIC registers. The proper setting of the - * tranceiver is set in ed_init so that the attach code is given a - * chance to set the default based on a compile-time config option - */ - ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL); - - /* - * Determine if this is an 8bit or 16bit board - */ - - /* - * select page 0 registers - */ - ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP); - - /* - * Attempt to clear WTS bit. If it doesn't clear, then this is a 16bit - * board. - */ - ed_nic_outb(sc, ED_P0_DCR, 0); - - /* - * select page 2 registers - */ - ed_nic_outb(sc, ED_P0_CR, ED_CR_PAGE_2 | ED_CR_RD2 | ED_CR_STP); - - /* - * The 3c503 forces the WTS bit to a one if this is a 16bit board - */ - if (ed_nic_inb(sc, ED_P2_DCR) & ED_DCR_WTS) - isa16bit = 1; - else - isa16bit = 0; - - /* - * select page 0 registers - */ - ed_nic_outb(sc, ED_P2_CR, ED_CR_RD2 | ED_CR_STP); - - error = ed_alloc_memory(dev, 0, memsize); - if (error) - return (error); - - sc->mem_start = (caddr_t) rman_get_virtual(sc->mem_res); - sc->mem_size = memsize; - sc->mem_end = sc->mem_start + memsize; - - /* - * We have an entire 8k window to put the transmit buffers on the - * 16bit boards. But since the 16bit 3c503's shared memory is only - * fast enough to overlap the loading of one full-size packet, trying - * to load more than 2 buffers can actually leave the transmitter idle - * during the load. So 2 seems the best value. (Although a mix of - * variable-sized packets might change this assumption. Nonetheless, - * we optimize for linear transfers of same-size packets.) - */ - if (isa16bit) { - if (flags & ED_FLAGS_NO_MULTI_BUFFERING) - sc->txb_cnt = 1; - else - sc->txb_cnt = 2; - - sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT; - sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT; - sc->rec_page_stop = memsize / ED_PAGE_SIZE + - ED_3COM_RX_PAGE_OFFSET_16BIT; - sc->mem_ring = sc->mem_start; - } else { - sc->txb_cnt = 1; - sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT; - sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT; - sc->rec_page_stop = memsize / ED_PAGE_SIZE + - ED_3COM_TX_PAGE_OFFSET_8BIT; - sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); - } - - sc->isa16bit = isa16bit; - - /* - * Initialize GA page start/stop registers. Probably only needed if - * doing DMA, but what the hell. - */ - ed_asic_outb(sc, ED_3COM_PSTR, sc->rec_page_start); - ed_asic_outb(sc, ED_3COM_PSPR, sc->rec_page_stop); - - /* - * Set IRQ. 3c503 only allows a choice of irq 2-5. - */ - error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); - if (error) - return (error); - - switch (irq) { - case 2: - case 9: - ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2); - break; - case 3: - ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3); - break; - case 4: - ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4); - break; - case 5: - ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5); - break; - default: - device_printf(dev, "Invalid irq configuration (%ld) must be 3-5,9 for 3c503\n", - irq); - return (ENXIO); - } - - /* - * Initialize GA configuration register. Set bank and enable shared - * mem. - */ - ed_asic_outb(sc, ED_3COM_GACFR, ED_3COM_GACFR_RSEL | - ED_3COM_GACFR_MBS0); - - /* - * Initialize "Vector Pointer" registers. These gawd-awful things are - * compared to 20 bits of the address on ISA, and if they match, the - * shared memory is disabled. We set them to 0xffff0...allegedly the - * reset vector. - */ - ed_asic_outb(sc, ED_3COM_VPTR2, 0xff); - ed_asic_outb(sc, ED_3COM_VPTR1, 0xff); - ed_asic_outb(sc, ED_3COM_VPTR0, 0x00); - - /* - * Zero memory and verify that it is clear - */ - bzero(sc->mem_start, memsize); - - for (i = 0; i < memsize; ++i) - if (sc->mem_start[i]) { - device_printf(dev, "failed to clear shared memory at %jx - check configuration\n", - (uintmax_t)kvtop(sc->mem_start + i)); - return (ENXIO); - } - return (0); -} - -/* - * Probe and vendor-specific initialization routine for SIC boards - */ -int -ed_probe_SIC(device_t dev, int port_rid, int flags) -{ - struct ed_softc *sc = device_get_softc(dev); - int error; - int i; - u_int memsize; - u_long conf_maddr, conf_msize; - u_char sum; - - error = ed_alloc_port(dev, 0, ED_SIC_IO_PORTS); - if (error) - return (error); - - sc->asic_offset = ED_SIC_ASIC_OFFSET; - sc->nic_offset = ED_SIC_NIC_OFFSET; - - error = bus_get_resource(dev, SYS_RES_MEMORY, 0, - &conf_maddr, &conf_msize); - if (error) - return (error); - - memsize = 16384; - if (conf_msize > 1) - memsize = conf_msize; - - error = ed_alloc_memory(dev, 0, memsize); - if (error) - return (error); - - sc->mem_start = (caddr_t) rman_get_virtual(sc->mem_res); - sc->mem_size = memsize; - - /* Reset card to force it into a known state. */ - ed_asic_outb(sc, 0, 0x00); - DELAY(100); - - /* - * Here we check the card ROM, if the checksum passes, and the - * type code and ethernet address check out, then we know we have - * an SIC card. - */ - ed_asic_outb(sc, 0, 0x81); - DELAY(100); - - sum = sc->mem_start[6]; - for (i = 0; i < ETHER_ADDR_LEN; i++) { - sum ^= (sc->arpcom.ac_enaddr[i] = sc->mem_start[i]); - } -#ifdef ED_DEBUG - device_printf(dev, "ed_probe_sic: got address %6D\n", - sc->arpcom.ac_enaddr, ":"); -#endif - if (sum != 0) { - return (ENXIO); - } - if ((sc->arpcom.ac_enaddr[0] | sc->arpcom.ac_enaddr[1] | - sc->arpcom.ac_enaddr[2]) == 0) { - return (ENXIO); - } - - sc->vendor = ED_VENDOR_SIC; - sc->type_str = "SIC"; - sc->isa16bit = 0; - sc->cr_proto = 0; - - /* - * SIC RAM page 0x0000-0x3fff(or 0x7fff) - */ - ed_asic_outb(sc, 0, 0x80); - DELAY(100); - - /* - * Now zero memory and verify that it is clear - */ - bzero(sc->mem_start, sc->mem_size); - - for (i = 0; i < sc->mem_size; i++) { - if (sc->mem_start[i]) { - device_printf(dev, "failed to clear shared memory " - "at %jx - check configuration\n", - (uintmax_t)kvtop(sc->mem_start + i)); - - return (ENXIO); - } - } - - sc->mem_shared = 1; - sc->mem_end = sc->mem_start + sc->mem_size; - - /* - * allocate one xmit buffer if < 16k, two buffers otherwise - */ - if ((sc->mem_size < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) { - sc->txb_cnt = 1; - } else { - sc->txb_cnt = 2; - } - sc->tx_page_start = 0; - - sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE * sc->txb_cnt; - sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE; - - sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; - - return (0); -} - -/* - * Probe and vendor-specific initialization routine for NE1000/2000 boards - */ -int -ed_probe_Novell_generic(device_t dev, int flags) -{ - struct ed_softc *sc = device_get_softc(dev); - u_int memsize, n; - u_char romdata[16], tmp; - static char test_pattern[32] = "THIS is A memory TEST pattern"; - char test_buffer[32]; - - /* XXX - do Novell-specific probe here */ - - /* Reset the board */ - if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_GWETHER) { - ed_asic_outb(sc, ED_NOVELL_RESET, 0); - DELAY(200); - } - tmp = ed_asic_inb(sc, ED_NOVELL_RESET); - - /* - * I don't know if this is necessary; probably cruft leftover from - * Clarkson packet driver code. Doesn't do a thing on the boards I've - * tested. -DG [note that an outb(0x84, 0) seems to work here, and is - * non-invasive...but some boards don't seem to reset and I don't have - * complete documentation on what the 'right' thing to do is...so we - * do the invasive thing for now. Yuck.] - */ - ed_asic_outb(sc, ED_NOVELL_RESET, tmp); - DELAY(5000); - - /* - * This is needed because some NE clones apparently don't reset the - * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX - * - this makes the probe invasive! ...Done against my better - * judgement. -DLG - */ - ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP); - - DELAY(5000); - - /* Make sure that we really have an 8390 based board */ - if (!ed_probe_generic8390(sc)) - return (ENXIO); - - sc->vendor = ED_VENDOR_NOVELL; - sc->mem_shared = 0; - sc->cr_proto = ED_CR_RD2; - - /* - * Test the ability to read and write to the NIC memory. This has the - * side affect of determining if this is an NE1000 or an NE2000. - */ - - /* - * This prevents packets from being stored in the NIC memory when the - * readmem routine turns on the start bit in the CR. - */ - ed_nic_outb(sc, ED_P0_RCR, ED_RCR_MON); - - /* Temporarily initialize DCR for byte operations */ - ed_nic_outb(sc, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); - - ed_nic_outb(sc, ED_P0_PSTART, 8192 / ED_PAGE_SIZE); - ed_nic_outb(sc, ED_P0_PSTOP, 16384 / ED_PAGE_SIZE); - - sc->isa16bit = 0; - - /* - * Write a test pattern in byte mode. If this fails, then there - * probably isn't any memory at 8k - which likely means that the board - * is an NE2000. - */ - ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern)); - ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern)); - - if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) { - sc->type = ED_TYPE_NE1000; - sc->type_str = "NE1000"; - } else { - - /* neither an NE1000 nor a Linksys - try NE2000 */ - ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); - ed_nic_outb(sc, ED_P0_PSTART, 16384 / ED_PAGE_SIZE); - ed_nic_outb(sc, ED_P0_PSTOP, 32768 / ED_PAGE_SIZE); - - sc->isa16bit = 1; - - /* - * Write a test pattern in word mode. If this also fails, then - * we don't know what this board is. - */ - ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern)); - ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern)); - if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) { - sc->type = ED_TYPE_NE2000; - sc->type_str = "NE2000"; - } else { - return (ENXIO); - } - } - - - /* 8k of memory plus an additional 8k if 16bit */ - memsize = 8192 + sc->isa16bit * 8192; - -#if 0 /* probably not useful - NE boards only come two ways */ - /* allow kernel config file overrides */ - if (isa_dev->id_msize) - memsize = isa_dev->id_msize; -#endif - - sc->mem_size = memsize; - - /* NIC memory doesn't start at zero on an NE board */ - /* The start address is tied to the bus width */ - sc->mem_start = (char *) 8192 + sc->isa16bit * 8192; - sc->mem_end = sc->mem_start + memsize; - sc->tx_page_start = memsize / ED_PAGE_SIZE; - - if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_GWETHER) { - int x, i, msize = 0; - long mstart = 0; - char pbuf0[ED_PAGE_SIZE], pbuf[ED_PAGE_SIZE], tbuf[ED_PAGE_SIZE]; - - for (i = 0; i < ED_PAGE_SIZE; i++) - pbuf0[i] = 0; - - /* Clear all the memory. */ - for (x = 1; x < 256; x++) - ed_pio_writemem(sc, pbuf0, x * 256, ED_PAGE_SIZE); - - /* Search for the start of RAM. */ - for (x = 1; x < 256; x++) { - ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); - if (bcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) { - for (i = 0; i < ED_PAGE_SIZE; i++) - pbuf[i] = 255 - x; - ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE); - ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); - if (bcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0) { - mstart = x * ED_PAGE_SIZE; - msize = ED_PAGE_SIZE; - break; - } - } - } - - if (mstart == 0) { - device_printf(dev, "Cannot find start of RAM.\n"); - return (ENXIO); - } - /* Search for the start of RAM. */ - for (x = (mstart / ED_PAGE_SIZE) + 1; x < 256; x++) { - ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); - if (bcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) { - for (i = 0; i < ED_PAGE_SIZE; i++) - pbuf[i] = 255 - x; - ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE); - ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); - if (bcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0) - msize += ED_PAGE_SIZE; - else { - break; - } - } else { - break; - } - } - - if (msize == 0) { - device_printf(dev, "Cannot find any RAM, start : %ld, x = %d.\n", mstart, x); - return (ENXIO); - } - device_printf(dev, "RAM start at %ld, size : %d.\n", mstart, msize); - - sc->mem_size = msize; - sc->mem_start = (caddr_t)(uintptr_t) mstart; - sc->mem_end = (caddr_t)(uintptr_t) (msize + mstart); - sc->tx_page_start = mstart / ED_PAGE_SIZE; - } - - /* - * Use one xmit buffer if < 16k, two buffers otherwise (if not told - * otherwise). - */ - if ((memsize < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) - sc->txb_cnt = 1; - else - sc->txb_cnt = 2; - - sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; - sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE; - - sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; - - ed_pio_readmem(sc, 0, romdata, 16); - for (n = 0; n < ETHER_ADDR_LEN; n++) - sc->arpcom.ac_enaddr[n] = romdata[n * (sc->isa16bit + 1)]; - - if ((ED_FLAGS_GETTYPE(flags) == ED_FLAGS_GWETHER) && - (sc->arpcom.ac_enaddr[2] == 0x86)) { - sc->type_str = "Gateway AT"; - } - - /* clear any pending interrupts that might have occurred above */ - ed_nic_outb(sc, ED_P0_ISR, 0xff); - - return (0); -} - -int -ed_probe_Novell(device_t dev, int port_rid, int flags) -{ - struct ed_softc *sc = device_get_softc(dev); - int error; - - error = ed_alloc_port(dev, port_rid, ED_NOVELL_IO_PORTS); - if (error) - return (error); - - sc->asic_offset = ED_NOVELL_ASIC_OFFSET; - sc->nic_offset = ED_NOVELL_NIC_OFFSET; - - return ed_probe_Novell_generic(dev, flags); -} - -#define ED_HPP_TEST_SIZE 16 - -/* - * Probe and vendor specific initialization for the HP PC Lan+ Cards. - * (HP Part nos: 27247B and 27252A). - * - * The card has an asic wrapper around a DS8390 core. The asic handles - * host accesses and offers both standard register IO and memory mapped - * IO. Memory mapped I/O allows better performance at the expense of greater - * chance of an incompatibility with existing ISA cards. - * - * The card has a few caveats: it isn't tolerant of byte wide accesses, only - * short (16 bit) or word (32 bit) accesses are allowed. Some card revisions - * don't allow 32 bit accesses; these are indicated by a bit in the software - * ID register (see if_edreg.h). - * - * Other caveats are: we should read the MAC address only when the card - * is inactive. - * - * For more information; please consult the CRYNWR packet driver. - * - * The AUI port is turned on using the "link2" option on the ifconfig - * command line. - */ -int -ed_probe_HP_pclanp(device_t dev, int port_rid, int flags) -{ - struct ed_softc *sc = device_get_softc(dev); - int error; - int n; /* temp var */ - int memsize; /* mem on board */ - u_char checksum; /* checksum of board address */ - u_char irq; /* board configured IRQ */ - uint8_t test_pattern[ED_HPP_TEST_SIZE]; /* read/write areas for */ - uint8_t test_buffer[ED_HPP_TEST_SIZE]; /* probing card */ - u_long conf_maddr, conf_msize, conf_irq, junk; - - error = ed_alloc_port(dev, 0, ED_HPP_IO_PORTS); - if (error) - return (error); - - /* Fill in basic information */ - sc->asic_offset = ED_HPP_ASIC_OFFSET; - sc->nic_offset = ED_HPP_NIC_OFFSET; - - sc->chip_type = ED_CHIP_TYPE_DP8390; - sc->isa16bit = 0; /* the 8390 core needs to be in byte mode */ - - /* - * Look for the HP PCLAN+ signature: "0x50,0x48,0x00,0x53" - */ - - if ((ed_asic_inb(sc, ED_HPP_ID) != 0x50) || - (ed_asic_inb(sc, ED_HPP_ID + 1) != 0x48) || - ((ed_asic_inb(sc, ED_HPP_ID + 2) & 0xF0) != 0) || - (ed_asic_inb(sc, ED_HPP_ID + 3) != 0x53)) - return ENXIO; - - /* - * Read the MAC address and verify checksum on the address. - */ - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_MAC); - for (n = 0, checksum = 0; n < ETHER_ADDR_LEN; n++) - checksum += (sc->arpcom.ac_enaddr[n] = - ed_asic_inb(sc, ED_HPP_MAC_ADDR + n)); - - checksum += ed_asic_inb(sc, ED_HPP_MAC_ADDR + ETHER_ADDR_LEN); - - if (checksum != 0xFF) - return ENXIO; - - /* - * Verify that the software model number is 0. - */ - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_ID); - if (((sc->hpp_id = ed_asic_inw(sc, ED_HPP_PAGE_4)) & - ED_HPP_ID_SOFT_MODEL_MASK) != 0x0000) - return ENXIO; - - /* - * Read in and save the current options configured on card. - */ - - sc->hpp_options = ed_asic_inw(sc, ED_HPP_OPTION); - - sc->hpp_options |= (ED_HPP_OPTION_NIC_RESET | - ED_HPP_OPTION_CHIP_RESET | - ED_HPP_OPTION_ENABLE_IRQ); - - /* - * Reset the chip. This requires writing to the option register - * so take care to preserve the other bits. - */ - - ed_asic_outw(sc, ED_HPP_OPTION, - (sc->hpp_options & ~(ED_HPP_OPTION_NIC_RESET | - ED_HPP_OPTION_CHIP_RESET))); - - DELAY(5000); /* wait for chip reset to complete */ - - ed_asic_outw(sc, ED_HPP_OPTION, - (sc->hpp_options | (ED_HPP_OPTION_NIC_RESET | - ED_HPP_OPTION_CHIP_RESET | - ED_HPP_OPTION_ENABLE_IRQ))); - - DELAY(5000); - - if (!(ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST)) - return ENXIO; /* reset did not complete */ - - /* - * Read out configuration information. - */ - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); - - irq = ed_asic_inb(sc, ED_HPP_HW_IRQ); - - /* - * Check for impossible IRQ. - */ - - if (irq >= (sizeof(ed_hpp_intr_val) / sizeof(ed_hpp_intr_val[0]))) - return ENXIO; - - /* - * If the kernel IRQ was specified with a '?' use the cards idea - * of the IRQ. If the kernel IRQ was explicitly specified, it - * should match that of the hardware. - */ - error = bus_get_resource(dev, SYS_RES_IRQ, 0, - &conf_irq, &junk); - if (error) { - bus_set_resource(dev, SYS_RES_IRQ, 0, - ed_hpp_intr_val[irq], 1); - } else { - if (conf_irq != ed_hpp_intr_val[irq]) - return (ENXIO); - } - - /* - * Fill in softconfig info. - */ - - sc->vendor = ED_VENDOR_HP; - sc->type = ED_TYPE_HP_PCLANPLUS; - sc->type_str = "HP-PCLAN+"; - - sc->mem_shared = 0; /* we DON'T have dual ported RAM */ - sc->mem_start = 0; /* we use offsets inside the card RAM */ - - sc->hpp_mem_start = NULL;/* no memory mapped I/O by default */ - - /* - * The board has 32KB of memory. Is there a way to determine - * this programmatically? - */ - - memsize = 32768; - - /* - * Check if memory mapping of the I/O registers possible. - */ - - if (sc->hpp_options & ED_HPP_OPTION_MEM_ENABLE) - { - u_long mem_addr; - - /* - * determine the memory address from the board. - */ - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); - mem_addr = (ed_asic_inw(sc, ED_HPP_HW_MEM_MAP) << 8); - - /* - * Check that the kernel specified start of memory and - * hardware's idea of it match. - */ - error = bus_get_resource(dev, SYS_RES_MEMORY, 0, - &conf_maddr, &conf_msize); - if (error) - return (error); - - if (mem_addr != conf_maddr) - return ENXIO; - - error = ed_alloc_memory(dev, 0, memsize); - if (error) - return (error); - - sc->hpp_mem_start = rman_get_virtual(sc->mem_res); - } - - /* - * Fill in the rest of the soft config structure. - */ - - /* - * The transmit page index. - */ - - sc->tx_page_start = ED_HPP_TX_PAGE_OFFSET; - - if (device_get_flags(dev) & ED_FLAGS_NO_MULTI_BUFFERING) - sc->txb_cnt = 1; - else - sc->txb_cnt = 2; - - /* - * Memory description - */ - - sc->mem_size = memsize; - sc->mem_ring = sc->mem_start + - (sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE); - sc->mem_end = sc->mem_start + sc->mem_size; - - /* - * Receive area starts after the transmit area and - * continues till the end of memory. - */ - - sc->rec_page_start = sc->tx_page_start + - (sc->txb_cnt * ED_TXBUF_SIZE); - sc->rec_page_stop = (sc->mem_size / ED_PAGE_SIZE); - - - sc->cr_proto = 0; /* value works */ - - /* - * Set the wrap registers for string I/O reads. - */ - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); - ed_asic_outw(sc, ED_HPP_HW_WRAP, - ((sc->rec_page_start / ED_PAGE_SIZE) | - (((sc->rec_page_stop / ED_PAGE_SIZE) - 1) << 8))); - - /* - * Reset the register page to normal operation. - */ - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF); - - /* - * Verify that we can read/write from adapter memory. - * Create test pattern. - */ - - for (n = 0; n < ED_HPP_TEST_SIZE; n++) - { - test_pattern[n] = (n*n) ^ ~n; - } - -#undef ED_HPP_TEST_SIZE - - /* - * Check that the memory is accessible thru the I/O ports. - * Write out the contents of "test_pattern", read back - * into "test_buffer" and compare the two for any - * mismatch. - */ - - for (n = 0; n < (32768 / ED_PAGE_SIZE); n ++) { - - ed_hpp_writemem(sc, test_pattern, (n * ED_PAGE_SIZE), - sizeof(test_pattern)); - ed_hpp_readmem(sc, (n * ED_PAGE_SIZE), - test_buffer, sizeof(test_pattern)); - - if (bcmp(test_pattern, test_buffer, - sizeof(test_pattern))) - return ENXIO; - } - - return (0); - -} - -/* - * HP PC Lan+ : Set the physical link to use AUI or TP/TL. - */ - -static void -ed_hpp_set_physical_link(struct ed_softc *sc) -{ - struct ifnet *ifp = &sc->arpcom.ac_if; - int lan_page; - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); - lan_page = ed_asic_inw(sc, ED_HPP_PAGE_0); - - if (ifp->if_flags & IFF_ALTPHYS) { - - /* - * Use the AUI port. - */ - - lan_page |= ED_HPP_LAN_AUI; - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); - ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page); - - - } else { - - /* - * Use the ThinLan interface - */ - - lan_page &= ~ED_HPP_LAN_AUI; - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); - ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page); - - } - - /* - * Wait for the lan card to re-initialize itself - */ - - DELAY(150000); /* wait 150 ms */ - - /* - * Restore normal pages. - */ - - ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF); - -} - /* * Allocate a port resource with the given resource id. */ @@ -1579,7 +139,7 @@ ed_alloc_port(device_t dev, int rid, int size) struct resource *res; res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, - 0ul, ~0ul, size, RF_ACTIVE); + 0ul, ~0ul, size, RF_ACTIVE); if (res) { sc->port_rid = rid; sc->port_res = res; @@ -1600,7 +160,7 @@ ed_alloc_memory(device_t dev, int rid, int size) struct resource *res; res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, - 0ul, ~0ul, size, RF_ACTIVE); + 0ul, ~0ul, size, RF_ACTIVE); if (res) { sc->mem_rid = rid; sc->mem_res = res; @@ -1620,8 +180,7 @@ ed_alloc_irq(device_t dev, int rid, int flags) struct ed_softc *sc = device_get_softc(dev); struct resource *res; - res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - (RF_ACTIVE | flags)); + res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | flags); if (res) { sc->irq_rid = rid; sc->irq_res = res; @@ -1728,12 +287,14 @@ ed_attach(device_t dev) else device_printf(dev, "type unknown (0x%x) ", sc->type); +#ifdef ED_HPP if (sc->vendor == ED_VENDOR_HP) printf("(%s %s IO)", (sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS) ? "16-bit" : "32-bit", sc->hpp_mem_start ? "memory mapped" : "regular"); else +#endif printf("%s ", sc->isa16bit ? "(16 bit)" : "(8 bit)"); printf("%s\n", (((sc->vendor == ED_VENDOR_3COM) || @@ -2672,8 +1233,11 @@ ed_ioctl(struct ifnet *ifp, u_long command, caddr_t data) } else { ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL); } - } else if (sc->vendor == ED_VENDOR_HP) + } +#ifdef ED_HPP + else if (sc->vendor == ED_VENDOR_HP) ed_hpp_set_physical_link(sc); +#endif break; case SIOCADDMULTI: @@ -2803,11 +1367,13 @@ ed_get_packet(struct ed_softc *sc, char *buf, u_short len) void ed_pio_readmem(struct ed_softc *sc, long src, uint8_t *dst, uint16_t amount) { +#ifdef ED_HPP /* HP PC Lan+ cards need special handling */ if (sc->vendor == ED_VENDOR_HP && sc->type == ED_TYPE_HP_PCLANPLUS) { ed_hpp_readmem(sc, src, dst, amount); return; } +#endif /* Regular Novell cards */ /* select page 0 registers */ @@ -2889,10 +1455,11 @@ ed_pio_write_mbufs(struct ed_softc *sc, struct mbuf *m, long dst) struct mbuf *mp; int maxwait = 200; /* about 240us */ +#ifdef ED_HPP /* HP PC Lan+ cards need special handling */ - if (sc->vendor == ED_VENDOR_HP && sc->type == ED_TYPE_HP_PCLANPLUS) { + if (sc->vendor == ED_VENDOR_HP && sc->type == ED_TYPE_HP_PCLANPLUS) return ed_hpp_write_mbufs(sc, m, dst); - } +#endif /* Regular Novell cards */ /* First, count up the total number of bytes to copy */ @@ -2995,279 +1562,6 @@ ed_pio_write_mbufs(struct ed_softc *sc, struct mbuf *m, long dst) return (total_len); } -/* - * Support routines to handle the HP PC Lan+ card. - */ - -/* - * HP PC Lan+: Read from NIC memory, using either PIO or memory mapped - * IO. - */ - -static void -ed_hpp_readmem(struct ed_softc *sc, long src, uint8_t *dst, uint16_t amount) -{ - - int use_32bit_access = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS); - - - /* Program the source address in RAM */ - ed_asic_outw(sc, ED_HPP_PAGE_2, src); - - /* - * The HP PC Lan+ card supports word reads as well as - * a memory mapped i/o port that is aliased to every - * even address on the board. - */ - - if (sc->hpp_mem_start) { - - /* Enable memory mapped access. */ - ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & - ~(ED_HPP_OPTION_MEM_DISABLE | - ED_HPP_OPTION_BOOT_ROM_ENB)); - - if (use_32bit_access && (amount > 3)) { - uint32_t *dl = (uint32_t *) dst; - volatile uint32_t *const sl = - (uint32_t *) sc->hpp_mem_start; - uint32_t *const fence = dl + (amount >> 2); - - /* Copy out NIC data. We could probably write this - as a `movsl'. The currently generated code is lousy. - */ - - while (dl < fence) - *dl++ = *sl; - - dst += (amount & ~3); - amount &= 3; - - } - - /* Finish off any words left, as a series of short reads */ - if (amount > 1) { - u_short *d = (u_short *) dst; - volatile u_short *const s = - (u_short *) sc->hpp_mem_start; - u_short *const fence = d + (amount >> 1); - - /* Copy out NIC data. */ - - while (d < fence) - *d++ = *s; - - dst += (amount & ~1); - amount &= 1; - } - - /* - * read in a byte; however we need to always read 16 bits - * at a time or the hardware gets into a funny state - */ - - if (amount == 1) { - /* need to read in a short and copy LSB */ - volatile u_short *const s = - (volatile u_short *) sc->hpp_mem_start; - - *dst = (*s) & 0xFF; - } - - /* Restore Boot ROM access. */ - - ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); - - - } else { - /* Read in data using the I/O port */ - if (use_32bit_access && (amount > 3)) { - ed_asic_insl(sc, ED_HPP_PAGE_4, dst, amount >> 2); - dst += (amount & ~3); - amount &= 3; - } - if (amount > 1) { - ed_asic_insw(sc, ED_HPP_PAGE_4, dst, amount >> 1); - dst += (amount & ~1); - amount &= 1; - } - if (amount == 1) { /* read in a short and keep the LSB */ - *dst = ed_asic_inw(sc, ED_HPP_PAGE_4) & 0xFF; - } - } -} - -/* - * HP PC Lan+: Write to NIC memory, using either PIO or memory mapped - * IO. - * Only used in the probe routine to test the memory. 'len' must - * be even. - */ -static void -ed_hpp_writemem(struct ed_softc *sc, uint8_t *src, uint16_t dst, uint16_t len) -{ - /* reset remote DMA complete flag */ - ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC); - - /* program the write address in RAM */ - ed_asic_outw(sc, ED_HPP_PAGE_0, dst); - - if (sc->hpp_mem_start) { - u_short *s = (u_short *) src; - volatile u_short *d = (u_short *) sc->hpp_mem_start; - u_short *const fence = s + (len >> 1); - - /* - * Enable memory mapped access. - */ - - ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & - ~(ED_HPP_OPTION_MEM_DISABLE | - ED_HPP_OPTION_BOOT_ROM_ENB)); - - /* - * Copy to NIC memory. - */ - - while (s < fence) - *d = *s++; - - /* - * Restore Boot ROM access. - */ - - ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); - - } else { - /* write data using I/O writes */ - ed_asic_outsw(sc, ED_HPP_PAGE_4, src, len / 2); - } -} - -/* - * Write to HP PC Lan+ NIC memory. Access to the NIC can be by using - * outsw() or via the memory mapped interface to the same register. - * Writes have to be in word units; byte accesses won't work and may cause - * the NIC to behave weirdly. Long word accesses are permitted if the ASIC - * allows it. - */ - -static u_short -ed_hpp_write_mbufs(struct ed_softc *sc, struct mbuf *m, int dst) -{ - int len, wantbyte; - unsigned short total_len; - unsigned char savebyte[2]; - volatile u_short * const d = - (volatile u_short *) sc->hpp_mem_start; - int use_32bit_accesses = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS); - - /* select page 0 registers */ - ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA); - - /* reset remote DMA complete flag */ - ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC); - - /* program the write address in RAM */ - ed_asic_outw(sc, ED_HPP_PAGE_0, dst); - - if (sc->hpp_mem_start) /* enable memory mapped I/O */ - ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & - ~(ED_HPP_OPTION_MEM_DISABLE | - ED_HPP_OPTION_BOOT_ROM_ENB)); - - wantbyte = 0; - total_len = 0; - - if (sc->hpp_mem_start) { /* Memory mapped I/O port */ - while (m) { - total_len += (len = m->m_len); - if (len) { - caddr_t data = mtod(m, caddr_t); - /* finish the last word of the previous mbuf */ - if (wantbyte) { - savebyte[1] = *data; - *d = *((u_short *) savebyte); - data++; len--; wantbyte = 0; - } - /* output contiguous words */ - if ((len > 3) && (use_32bit_accesses)) { - volatile uint32_t *const dl = - (volatile uint32_t *) d; - uint32_t *sl = (uint32_t *) data; - uint32_t *fence = sl + (len >> 2); - - while (sl < fence) - *dl = *sl++; - - data += (len & ~3); - len &= 3; - } - /* finish off remain 16 bit writes */ - if (len > 1) { - u_short *s = (u_short *) data; - u_short *fence = s + (len >> 1); - - while (s < fence) - *d = *s++; - - data += (len & ~1); - len &= 1; - } - /* save last byte if needed */ - if ((wantbyte = (len == 1)) != 0) - savebyte[0] = *data; - } - m = m->m_next; /* to next mbuf */ - } - if (wantbyte) /* write last byte */ - *d = *((u_short *) savebyte); - } else { - /* use programmed I/O */ - while (m) { - total_len += (len = m->m_len); - if (len) { - caddr_t data = mtod(m, caddr_t); - /* finish the last word of the previous mbuf */ - if (wantbyte) { - savebyte[1] = *data; - ed_asic_outw(sc, ED_HPP_PAGE_4, - *((u_short *)savebyte)); - data++; - len--; - wantbyte = 0; - } - /* output contiguous words */ - if ((len > 3) && use_32bit_accesses) { - ed_asic_outsl(sc, ED_HPP_PAGE_4, - data, len >> 2); - data += (len & ~3); - len &= 3; - } - /* finish off remaining 16 bit accesses */ - if (len > 1) { - ed_asic_outsw(sc, ED_HPP_PAGE_4, - data, len >> 1); - data += (len & ~1); - len &= 1; - } - if ((wantbyte = (len == 1)) != 0) - savebyte[0] = *data; - - } /* if len != 0 */ - m = m->m_next; - } - if (wantbyte) /* spit last byte */ - ed_asic_outw(sc, ED_HPP_PAGE_4, *(u_short *)savebyte); - - } - - if (sc->hpp_mem_start) /* turn off memory mapped i/o */ - ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); - - return (total_len); -} - #ifndef ED_NO_MIIBUS /* * MII bus support routines. @@ -3464,6 +1758,17 @@ ed_ds_getmcaf(struct ed_softc *sc, uint32_t *mcaf) } } +int +ed_isa_mem_ok(device_t dev, u_long pmem, u_int memsize) +{ + if (pmem < 0xa0000 || pmem + memsize > 0x1000000) { + device_printf(dev, "Invalid ISA memory address range " + "configured: 0x%lx - 0x%lx\n", pmem, pmem + memsize); + return (ENXIO); + } + return (0); +} + int ed_clear_memory(device_t dev) { diff --git a/sys/dev/ed/if_ed_3c503.c b/sys/dev/ed/if_ed_3c503.c new file mode 100644 index 000000000000..b46e1078b3a5 --- /dev/null +++ b/sys/dev/ed/if_ed_3c503.c @@ -0,0 +1,341 @@ +/*- + * Copyright (c) 2005, M. Warner Losh + * All rights reserved. + * Copyright (c) 1995, David Greenman + * 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 unmodified, 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 AND CONTRIBUTORS ``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 CONTRIBUTORS 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 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#ifdef ED_3C503 + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* + * Probe and vendor-specific initialization routine for 3Com 3c503 boards + */ +int +ed_probe_3Com(device_t dev, int port_rid, int flags) +{ + struct ed_softc *sc = device_get_softc(dev); + int error; + int i; + u_int memsize; + u_char isa16bit; + u_long conf_maddr, conf_msize, irq, junk, pmem; + + error = ed_alloc_port(dev, 0, ED_3COM_IO_PORTS); + if (error) + return (error); + + sc->asic_offset = ED_3COM_ASIC_OFFSET; + sc->nic_offset = ED_3COM_NIC_OFFSET; + + /* + * Verify that the kernel configured I/O address matches the board + * configured address + */ + switch (ed_asic_inb(sc, ED_3COM_BCFR)) { + case ED_3COM_BCFR_300: + if (rman_get_start(sc->port_res) != 0x300) + return (ENXIO); + break; + case ED_3COM_BCFR_310: + if (rman_get_start(sc->port_res) != 0x310) + return (ENXIO); + break; + case ED_3COM_BCFR_330: + if (rman_get_start(sc->port_res) != 0x330) + return (ENXIO); + break; + case ED_3COM_BCFR_350: + if (rman_get_start(sc->port_res) != 0x350) + return (ENXIO); + break; + case ED_3COM_BCFR_250: + if (rman_get_start(sc->port_res) != 0x250) + return (ENXIO); + break; + case ED_3COM_BCFR_280: + if (rman_get_start(sc->port_res) != 0x280) + return (ENXIO); + break; + case ED_3COM_BCFR_2A0: + if (rman_get_start(sc->port_res) != 0x2a0) + return (ENXIO); + break; + case ED_3COM_BCFR_2E0: + if (rman_get_start(sc->port_res) != 0x2e0) + return (ENXIO); + break; + default: + return (ENXIO); + } + + error = bus_get_resource(dev, SYS_RES_MEMORY, 0, + &conf_maddr, &conf_msize); + if (error) + return (error); + + /* + * Verify that the kernel shared memory address matches the board + * configured address. + */ + switch (ed_asic_inb(sc, ED_3COM_PCFR)) { + case ED_3COM_PCFR_DC000: + if (conf_maddr != 0xdc000) + return (ENXIO); + break; + case ED_3COM_PCFR_D8000: + if (conf_maddr != 0xd8000) + return (ENXIO); + break; + case ED_3COM_PCFR_CC000: + if (conf_maddr != 0xcc000) + return (ENXIO); + break; + case ED_3COM_PCFR_C8000: + if (conf_maddr != 0xc8000) + return (ENXIO); + break; + default: + return (ENXIO); + } + + + /* + * Reset NIC and ASIC. Enable on-board transceiver throughout reset + * sequence because it'll lock up if the cable isn't connected if we + * don't. + */ + ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL); + + /* + * Wait for a while, then un-reset it + */ + DELAY(50); + + /* + * The 3Com ASIC defaults to rather strange settings for the CR after + * a reset - it's important to set it again after the following outb + * (this is done when we map the PROM below). + */ + ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL); + + /* + * Wait a bit for the NIC to recover from the reset + */ + DELAY(5000); + + sc->vendor = ED_VENDOR_3COM; + sc->type_str = "3c503"; + sc->mem_shared = 1; + sc->cr_proto = ED_CR_RD2; + + /* + * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k window + * to it. + */ + memsize = 8192; + + /* + * Get station address from on-board ROM + */ + + /* + * First, map ethernet address PROM over the top of where the NIC + * registers normally appear. + */ + ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL); + + for (i = 0; i < ETHER_ADDR_LEN; ++i) + sc->arpcom.ac_enaddr[i] = ed_nic_inb(sc, i); + + /* + * Unmap PROM - select NIC registers. The proper setting of the + * tranceiver is set in ed_init so that the attach code is given a + * chance to set the default based on a compile-time config option + */ + ed_asic_outb(sc, ED_3COM_CR, ED_3COM_CR_XSEL); + + /* + * Determine if this is an 8bit or 16bit board + */ + + /* + * select page 0 registers + */ + ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP); + + /* + * Attempt to clear WTS bit. If it doesn't clear, then this is a 16bit + * board. + */ + ed_nic_outb(sc, ED_P0_DCR, 0); + + /* + * select page 2 registers + */ + ed_nic_outb(sc, ED_P0_CR, ED_CR_PAGE_2 | ED_CR_RD2 | ED_CR_STP); + + /* + * The 3c503 forces the WTS bit to a one if this is a 16bit board + */ + if (ed_nic_inb(sc, ED_P2_DCR) & ED_DCR_WTS) + isa16bit = 1; + else + isa16bit = 0; + + /* + * select page 0 registers + */ + ed_nic_outb(sc, ED_P2_CR, ED_CR_RD2 | ED_CR_STP); + + error = ed_alloc_memory(dev, 0, memsize); + if (error) + return (error); + + pmem = rman_get_start(sc->mem_res); + error = ed_isa_mem_ok(dev, pmem, memsize); + if (error) + return (error); + + sc->mem_start = (caddr_t) rman_get_virtual(sc->mem_res); + sc->mem_size = memsize; + sc->mem_end = sc->mem_start + memsize; + + /* + * We have an entire 8k window to put the transmit buffers on the + * 16bit boards. But since the 16bit 3c503's shared memory is only + * fast enough to overlap the loading of one full-size packet, trying + * to load more than 2 buffers can actually leave the transmitter idle + * during the load. So 2 seems the best value. (Although a mix of + * variable-sized packets might change this assumption. Nonetheless, + * we optimize for linear transfers of same-size packets.) + */ + if (isa16bit) { + if (flags & ED_FLAGS_NO_MULTI_BUFFERING) + sc->txb_cnt = 1; + else + sc->txb_cnt = 2; + + sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT; + sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT; + sc->rec_page_stop = memsize / ED_PAGE_SIZE + + ED_3COM_RX_PAGE_OFFSET_16BIT; + sc->mem_ring = sc->mem_start; + } else { + sc->txb_cnt = 1; + sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT; + sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT; + sc->rec_page_stop = memsize / ED_PAGE_SIZE + + ED_3COM_TX_PAGE_OFFSET_8BIT; + sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); + } + + sc->isa16bit = isa16bit; + + /* + * Initialize GA page start/stop registers. Probably only needed if + * doing DMA, but what the hell. + */ + ed_asic_outb(sc, ED_3COM_PSTR, sc->rec_page_start); + ed_asic_outb(sc, ED_3COM_PSPR, sc->rec_page_stop); + + /* + * Set IRQ. 3c503 only allows a choice of irq 2-5. + */ + error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); + if (error) + return (error); + + switch (irq) { + case 2: + case 9: + ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2); + break; + case 3: + ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3); + break; + case 4: + ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4); + break; + case 5: + ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5); + break; + default: + device_printf(dev, "Invalid irq configuration (%ld) must be 3-5,9 for 3c503\n", + irq); + return (ENXIO); + } + + /* + * Initialize GA configuration register. Set bank and enable shared + * mem. + */ + ed_asic_outb(sc, ED_3COM_GACFR, ED_3COM_GACFR_RSEL | + ED_3COM_GACFR_MBS0); + + /* + * Initialize "Vector Pointer" registers. These gawd-awful things are + * compared to 20 bits of the address on ISA, and if they match, the + * shared memory is disabled. We set them to 0xffff0...allegedly the + * reset vector. + */ + ed_asic_outb(sc, ED_3COM_VPTR2, 0xff); + ed_asic_outb(sc, ED_3COM_VPTR1, 0xff); + ed_asic_outb(sc, ED_3COM_VPTR0, 0x00); + + return (ed_clear_memory(dev)); +} + +#endif /* ED_3C503 */ diff --git a/sys/dev/ed/if_ed_hpp.c b/sys/dev/ed/if_ed_hpp.c new file mode 100644 index 000000000000..c993cc1ec2f9 --- /dev/null +++ b/sys/dev/ed/if_ed_hpp.c @@ -0,0 +1,663 @@ +/*- + * Copyright (c) 2005, M. Warner Losh + * All rights reserved. + * Copyright (c) 1995, David Greenman + * 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 unmodified, 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 AND CONTRIBUTORS ``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 CONTRIBUTORS 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 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#ifdef ED_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +static void ed_hpp_writemem(struct ed_softc *, uint8_t *, uint16_t, + uint16_t); + +/* + * Interrupt conversion table for the HP PC LAN+ + */ +static uint16_t ed_hpp_intr_val[] = { + 0, /* 0 */ + 0, /* 1 */ + 0, /* 2 */ + 3, /* 3 */ + 4, /* 4 */ + 5, /* 5 */ + 6, /* 6 */ + 7, /* 7 */ + 0, /* 8 */ + 9, /* 9 */ + 10, /* 10 */ + 11, /* 11 */ + 12, /* 12 */ + 0, /* 13 */ + 0, /* 14 */ + 15 /* 15 */ +}; + +#define ED_HPP_TEST_SIZE 16 + +/* + * Probe and vendor specific initialization for the HP PC Lan+ Cards. + * (HP Part nos: 27247B and 27252A). + * + * The card has an asic wrapper around a DS8390 core. The asic handles + * host accesses and offers both standard register IO and memory mapped + * IO. Memory mapped I/O allows better performance at the expense of greater + * chance of an incompatibility with existing ISA cards. + * + * The card has a few caveats: it isn't tolerant of byte wide accesses, only + * short (16 bit) or word (32 bit) accesses are allowed. Some card revisions + * don't allow 32 bit accesses; these are indicated by a bit in the software + * ID register (see if_edreg.h). + * + * Other caveats are: we should read the MAC address only when the card + * is inactive. + * + * For more information; please consult the CRYNWR packet driver. + * + * The AUI port is turned on using the "link2" option on the ifconfig + * command line. + */ +int +ed_probe_HP_pclanp(device_t dev, int port_rid, int flags) +{ + struct ed_softc *sc = device_get_softc(dev); + int error; + int n; /* temp var */ + int memsize; /* mem on board */ + u_char checksum; /* checksum of board address */ + u_char irq; /* board configured IRQ */ + uint8_t test_pattern[ED_HPP_TEST_SIZE]; /* read/write areas for */ + uint8_t test_buffer[ED_HPP_TEST_SIZE]; /* probing card */ + u_long conf_maddr, conf_msize, conf_irq, junk; + + error = ed_alloc_port(dev, 0, ED_HPP_IO_PORTS); + if (error) + return (error); + + /* Fill in basic information */ + sc->asic_offset = ED_HPP_ASIC_OFFSET; + sc->nic_offset = ED_HPP_NIC_OFFSET; + + sc->chip_type = ED_CHIP_TYPE_DP8390; + sc->isa16bit = 0; /* the 8390 core needs to be in byte mode */ + + /* + * Look for the HP PCLAN+ signature: "0x50,0x48,0x00,0x53" + */ + + if ((ed_asic_inb(sc, ED_HPP_ID) != 0x50) || + (ed_asic_inb(sc, ED_HPP_ID + 1) != 0x48) || + ((ed_asic_inb(sc, ED_HPP_ID + 2) & 0xF0) != 0) || + (ed_asic_inb(sc, ED_HPP_ID + 3) != 0x53)) + return ENXIO; + + /* + * Read the MAC address and verify checksum on the address. + */ + + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_MAC); + for (n = 0, checksum = 0; n < ETHER_ADDR_LEN; n++) + checksum += (sc->arpcom.ac_enaddr[n] = + ed_asic_inb(sc, ED_HPP_MAC_ADDR + n)); + + checksum += ed_asic_inb(sc, ED_HPP_MAC_ADDR + ETHER_ADDR_LEN); + + if (checksum != 0xFF) + return ENXIO; + + /* + * Verify that the software model number is 0. + */ + + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_ID); + if (((sc->hpp_id = ed_asic_inw(sc, ED_HPP_PAGE_4)) & + ED_HPP_ID_SOFT_MODEL_MASK) != 0x0000) + return ENXIO; + + /* + * Read in and save the current options configured on card. + */ + + sc->hpp_options = ed_asic_inw(sc, ED_HPP_OPTION); + + sc->hpp_options |= (ED_HPP_OPTION_NIC_RESET | + ED_HPP_OPTION_CHIP_RESET | ED_HPP_OPTION_ENABLE_IRQ); + + /* + * Reset the chip. This requires writing to the option register + * so take care to preserve the other bits. + */ + + ed_asic_outw(sc, ED_HPP_OPTION, + (sc->hpp_options & ~(ED_HPP_OPTION_NIC_RESET | + ED_HPP_OPTION_CHIP_RESET))); + + DELAY(5000); /* wait for chip reset to complete */ + + ed_asic_outw(sc, ED_HPP_OPTION, + (sc->hpp_options | (ED_HPP_OPTION_NIC_RESET | + ED_HPP_OPTION_CHIP_RESET | + ED_HPP_OPTION_ENABLE_IRQ))); + + DELAY(5000); + + if (!(ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST)) + return ENXIO; /* reset did not complete */ + + /* + * Read out configuration information. + */ + + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); + + irq = ed_asic_inb(sc, ED_HPP_HW_IRQ); + + /* + * Check for impossible IRQ. + */ + + if (irq >= (sizeof(ed_hpp_intr_val) / sizeof(ed_hpp_intr_val[0]))) + return ENXIO; + + /* + * If the kernel IRQ was specified with a '?' use the cards idea + * of the IRQ. If the kernel IRQ was explicitly specified, it + * should match that of the hardware. + */ + error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk); + if (error) + bus_set_resource(dev, SYS_RES_IRQ, 0, ed_hpp_intr_val[irq], 1); + else { + if (conf_irq != ed_hpp_intr_val[irq]) + return (ENXIO); + } + + /* + * Fill in softconfig info. + */ + + sc->vendor = ED_VENDOR_HP; + sc->type = ED_TYPE_HP_PCLANPLUS; + sc->type_str = "HP-PCLAN+"; + + sc->mem_shared = 0; /* we DON'T have dual ported RAM */ + sc->mem_start = 0; /* we use offsets inside the card RAM */ + + sc->hpp_mem_start = NULL;/* no memory mapped I/O by default */ + + /* + * The board has 32KB of memory. Is there a way to determine + * this programmatically? + */ + + memsize = 32768; + + /* + * Check if memory mapping of the I/O registers possible. + */ + if (sc->hpp_options & ED_HPP_OPTION_MEM_ENABLE) { + u_long mem_addr; + + /* + * determine the memory address from the board. + */ + + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); + mem_addr = (ed_asic_inw(sc, ED_HPP_HW_MEM_MAP) << 8); + + /* + * Check that the kernel specified start of memory and + * hardware's idea of it match. + */ + error = bus_get_resource(dev, SYS_RES_MEMORY, 0, + &conf_maddr, &conf_msize); + if (error) + return (error); + + if (mem_addr != conf_maddr) + return ENXIO; + + error = ed_alloc_memory(dev, 0, memsize); + if (error) + return (error); + + sc->hpp_mem_start = rman_get_virtual(sc->mem_res); + } + + /* + * Fill in the rest of the soft config structure. + */ + + /* + * The transmit page index. + */ + + sc->tx_page_start = ED_HPP_TX_PAGE_OFFSET; + + if (device_get_flags(dev) & ED_FLAGS_NO_MULTI_BUFFERING) + sc->txb_cnt = 1; + else + sc->txb_cnt = 2; + + /* + * Memory description + */ + + sc->mem_size = memsize; + sc->mem_ring = sc->mem_start + + (sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE); + sc->mem_end = sc->mem_start + sc->mem_size; + + /* + * Receive area starts after the transmit area and + * continues till the end of memory. + */ + + sc->rec_page_start = sc->tx_page_start + + (sc->txb_cnt * ED_TXBUF_SIZE); + sc->rec_page_stop = (sc->mem_size / ED_PAGE_SIZE); + + + sc->cr_proto = 0; /* value works */ + + /* + * Set the wrap registers for string I/O reads. + */ + + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_HW); + ed_asic_outw(sc, ED_HPP_HW_WRAP, + ((sc->rec_page_start / ED_PAGE_SIZE) | + (((sc->rec_page_stop / ED_PAGE_SIZE) - 1) << 8))); + + /* + * Reset the register page to normal operation. + */ + + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF); + + /* + * Verify that we can read/write from adapter memory. + * Create test pattern. + */ + + for (n = 0; n < ED_HPP_TEST_SIZE; n++) + test_pattern[n] = (n*n) ^ ~n; + +#undef ED_HPP_TEST_SIZE + + /* + * Check that the memory is accessible thru the I/O ports. + * Write out the contents of "test_pattern", read back + * into "test_buffer" and compare the two for any + * mismatch. + */ + + for (n = 0; n < (32768 / ED_PAGE_SIZE); n ++) { + ed_hpp_writemem(sc, test_pattern, (n * ED_PAGE_SIZE), + sizeof(test_pattern)); + ed_hpp_readmem(sc, (n * ED_PAGE_SIZE), + test_buffer, sizeof(test_pattern)); + + if (bcmp(test_pattern, test_buffer, + sizeof(test_pattern))) + return ENXIO; + } + + return (0); +} + +/* + * HP PC Lan+ : Set the physical link to use AUI or TP/TL. + */ + +void +ed_hpp_set_physical_link(struct ed_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + int lan_page; + + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); + lan_page = ed_asic_inw(sc, ED_HPP_PAGE_0); + + if (ifp->if_flags & IFF_ALTPHYS) { + /* + * Use the AUI port. + */ + + lan_page |= ED_HPP_LAN_AUI; + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); + ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page); + } else { + /* + * Use the ThinLan interface + */ + + lan_page &= ~ED_HPP_LAN_AUI; + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_LAN); + ed_asic_outw(sc, ED_HPP_PAGE_0, lan_page); + } + + /* + * Wait for the lan card to re-initialize itself + */ + DELAY(150000); /* wait 150 ms */ + + /* + * Restore normal pages. + */ + ed_asic_outw(sc, ED_HPP_PAGING, ED_HPP_PAGE_PERF); +} + +/* + * Support routines to handle the HP PC Lan+ card. + */ + +/* + * HP PC Lan+: Read from NIC memory, using either PIO or memory mapped + * IO. + */ + +void +ed_hpp_readmem(struct ed_softc *sc, long src, uint8_t *dst, uint16_t amount) +{ + int use_32bit_access = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS); + + /* Program the source address in RAM */ + ed_asic_outw(sc, ED_HPP_PAGE_2, src); + + /* + * The HP PC Lan+ card supports word reads as well as + * a memory mapped i/o port that is aliased to every + * even address on the board. + */ + if (sc->hpp_mem_start) { + /* Enable memory mapped access. */ + ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & + ~(ED_HPP_OPTION_MEM_DISABLE | + ED_HPP_OPTION_BOOT_ROM_ENB)); + + if (use_32bit_access && (amount > 3)) { + uint32_t *dl = (uint32_t *) dst; + volatile uint32_t *const sl = + (uint32_t *) sc->hpp_mem_start; + uint32_t *const fence = dl + (amount >> 2); + + /* Copy out NIC data. We could probably write this + as a `movsl'. The currently generated code is lousy. + */ + + while (dl < fence) + *dl++ = *sl; + + dst += (amount & ~3); + amount &= 3; + + } + + /* Finish off any words left, as a series of short reads */ + if (amount > 1) { + u_short *d = (u_short *) dst; + volatile u_short *const s = + (u_short *) sc->hpp_mem_start; + u_short *const fence = d + (amount >> 1); + + /* Copy out NIC data. */ + while (d < fence) + *d++ = *s; + + dst += (amount & ~1); + amount &= 1; + } + + /* + * read in a byte; however we need to always read 16 bits + * at a time or the hardware gets into a funny state + */ + + if (amount == 1) { + /* need to read in a short and copy LSB */ + volatile u_short *const s = + (volatile u_short *) sc->hpp_mem_start; + *dst = (*s) & 0xFF; + } + + /* Restore Boot ROM access. */ + ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); + } else { + /* Read in data using the I/O port */ + if (use_32bit_access && (amount > 3)) { + ed_asic_insl(sc, ED_HPP_PAGE_4, dst, amount >> 2); + dst += (amount & ~3); + amount &= 3; + } + if (amount > 1) { + ed_asic_insw(sc, ED_HPP_PAGE_4, dst, amount >> 1); + dst += (amount & ~1); + amount &= 1; + } + if (amount == 1) { /* read in a short and keep the LSB */ + *dst = ed_asic_inw(sc, ED_HPP_PAGE_4) & 0xFF; + } + } +} + +/* + * HP PC Lan+: Write to NIC memory, using either PIO or memory mapped + * IO. + * Only used in the probe routine to test the memory. 'len' must + * be even. + */ +static void +ed_hpp_writemem(struct ed_softc *sc, uint8_t *src, uint16_t dst, uint16_t len) +{ + /* reset remote DMA complete flag */ + ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC); + + /* program the write address in RAM */ + ed_asic_outw(sc, ED_HPP_PAGE_0, dst); + + if (sc->hpp_mem_start) { + u_short *s = (u_short *) src; + volatile u_short *d = (u_short *) sc->hpp_mem_start; + u_short *const fence = s + (len >> 1); + + /* + * Enable memory mapped access. + */ + ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & + ~(ED_HPP_OPTION_MEM_DISABLE | + ED_HPP_OPTION_BOOT_ROM_ENB)); + + /* + * Copy to NIC memory. + */ + while (s < fence) + *d = *s++; + + /* + * Restore Boot ROM access. + */ + ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); + } else { + /* write data using I/O writes */ + ed_asic_outsw(sc, ED_HPP_PAGE_4, src, len / 2); + } +} + +/* + * Write to HP PC Lan+ NIC memory. Access to the NIC can be by using + * outsw() or via the memory mapped interface to the same register. + * Writes have to be in word units; byte accesses won't work and may cause + * the NIC to behave weirdly. Long word accesses are permitted if the ASIC + * allows it. + */ + +u_short +ed_hpp_write_mbufs(struct ed_softc *sc, struct mbuf *m, int dst) +{ + int len, wantbyte; + unsigned short total_len; + unsigned char savebyte[2]; + volatile u_short * const d = + (volatile u_short *) sc->hpp_mem_start; + int use_32bit_accesses = !(sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS); + + /* select page 0 registers */ + ed_nic_outb(sc, ED_P0_CR, sc->cr_proto | ED_CR_STA); + + /* reset remote DMA complete flag */ + ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RDC); + + /* program the write address in RAM */ + ed_asic_outw(sc, ED_HPP_PAGE_0, dst); + + if (sc->hpp_mem_start) /* enable memory mapped I/O */ + ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options & + ~(ED_HPP_OPTION_MEM_DISABLE | + ED_HPP_OPTION_BOOT_ROM_ENB)); + + wantbyte = 0; + total_len = 0; + + if (sc->hpp_mem_start) { /* Memory mapped I/O port */ + while (m) { + total_len += (len = m->m_len); + if (len) { + caddr_t data = mtod(m, caddr_t); + /* finish the last word of the previous mbuf */ + if (wantbyte) { + savebyte[1] = *data; + *d = *((u_short *) savebyte); + data++; len--; wantbyte = 0; + } + /* output contiguous words */ + if ((len > 3) && (use_32bit_accesses)) { + volatile uint32_t *const dl = + (volatile uint32_t *) d; + uint32_t *sl = (uint32_t *) data; + uint32_t *fence = sl + (len >> 2); + + while (sl < fence) + *dl = *sl++; + + data += (len & ~3); + len &= 3; + } + /* finish off remain 16 bit writes */ + if (len > 1) { + u_short *s = (u_short *) data; + u_short *fence = s + (len >> 1); + + while (s < fence) + *d = *s++; + + data += (len & ~1); + len &= 1; + } + /* save last byte if needed */ + if ((wantbyte = (len == 1)) != 0) + savebyte[0] = *data; + } + m = m->m_next; /* to next mbuf */ + } + if (wantbyte) /* write last byte */ + *d = *((u_short *) savebyte); + } else { + /* use programmed I/O */ + while (m) { + total_len += (len = m->m_len); + if (len) { + caddr_t data = mtod(m, caddr_t); + /* finish the last word of the previous mbuf */ + if (wantbyte) { + savebyte[1] = *data; + ed_asic_outw(sc, ED_HPP_PAGE_4, + *((u_short *)savebyte)); + data++; + len--; + wantbyte = 0; + } + /* output contiguous words */ + if ((len > 3) && use_32bit_accesses) { + ed_asic_outsl(sc, ED_HPP_PAGE_4, + data, len >> 2); + data += (len & ~3); + len &= 3; + } + /* finish off remaining 16 bit accesses */ + if (len > 1) { + ed_asic_outsw(sc, ED_HPP_PAGE_4, + data, len >> 1); + data += (len & ~1); + len &= 1; + } + if ((wantbyte = (len == 1)) != 0) + savebyte[0] = *data; + + } /* if len != 0 */ + m = m->m_next; + } + if (wantbyte) /* spit last byte */ + ed_asic_outw(sc, ED_HPP_PAGE_4, *(u_short *)savebyte); + + } + + if (sc->hpp_mem_start) /* turn off memory mapped i/o */ + ed_asic_outw(sc, ED_HPP_OPTION, sc->hpp_options); + + return (total_len); +} + +#endif /* ED_HPP */ diff --git a/sys/dev/ed/if_ed_isa.c b/sys/dev/ed/if_ed_isa.c index 2b963d1ef39b..742789c5443b 100644 --- a/sys/dev/ed/if_ed_isa.c +++ b/sys/dev/ed/if_ed_isa.c @@ -29,6 +29,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_ed.h" + #include #include #include @@ -89,26 +91,30 @@ ed_isa_probe(dev) goto end; ed_release_resources(dev); +#ifdef ED_3C503 error = ed_probe_3Com(dev, 0, flags); if (error == 0) goto end; ed_release_resources(dev); +#endif +#ifdef ED_SIC error = ed_probe_SIC(dev, 0, flags); if (error == 0) goto end; ed_release_resources(dev); - +#endif error = ed_probe_Novell(dev, 0, flags); if (error == 0) goto end; ed_release_resources(dev); +#ifdef ED_HPP error = ed_probe_HP_pclanp(dev, 0, flags); if (error == 0) goto end; ed_release_resources(dev); - +#endif end: if (error == 0) error = ed_alloc_irq(dev, 0, 0); diff --git a/sys/dev/ed/if_ed_novell.c b/sys/dev/ed/if_ed_novell.c new file mode 100644 index 000000000000..235dee641323 --- /dev/null +++ b/sys/dev/ed/if_ed_novell.c @@ -0,0 +1,288 @@ +/*- + * Copyright (c) 2005, M. Warner Losh + * All rights reserved. + * Copyright (c) 1995, David Greenman + * 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 unmodified, 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 AND CONTRIBUTORS ``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 CONTRIBUTORS 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 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. + */ + + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* + * Probe and vendor-specific initialization routine for NE1000/2000 boards + */ +int +ed_probe_Novell_generic(device_t dev, int flags) +{ + struct ed_softc *sc = device_get_softc(dev); + u_int memsize, n; + u_char romdata[16], tmp; + static char test_pattern[32] = "THIS is A memory TEST pattern"; + char test_buffer[32]; + + /* XXX - do Novell-specific probe here */ + + /* Reset the board */ + if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_GWETHER) { + ed_asic_outb(sc, ED_NOVELL_RESET, 0); + DELAY(200); + } + tmp = ed_asic_inb(sc, ED_NOVELL_RESET); + + /* + * I don't know if this is necessary; probably cruft leftover from + * Clarkson packet driver code. Doesn't do a thing on the boards I've + * tested. -DG [note that an outb(0x84, 0) seems to work here, and is + * non-invasive...but some boards don't seem to reset and I don't have + * complete documentation on what the 'right' thing to do is...so we + * do the invasive thing for now. Yuck.] + */ + ed_asic_outb(sc, ED_NOVELL_RESET, tmp); + DELAY(5000); + + /* + * This is needed because some NE clones apparently don't reset the + * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX + * - this makes the probe invasive! ...Done against my better + * judgement. -DLG + */ + ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP); + + DELAY(5000); + + /* Make sure that we really have an 8390 based board */ + if (!ed_probe_generic8390(sc)) + return (ENXIO); + + sc->vendor = ED_VENDOR_NOVELL; + sc->mem_shared = 0; + sc->cr_proto = ED_CR_RD2; + + /* + * Test the ability to read and write to the NIC memory. This has the + * side affect of determining if this is an NE1000 or an NE2000. + */ + + /* + * This prevents packets from being stored in the NIC memory when the + * readmem routine turns on the start bit in the CR. + */ + ed_nic_outb(sc, ED_P0_RCR, ED_RCR_MON); + + /* Temporarily initialize DCR for byte operations */ + ed_nic_outb(sc, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS); + + ed_nic_outb(sc, ED_P0_PSTART, 8192 / ED_PAGE_SIZE); + ed_nic_outb(sc, ED_P0_PSTOP, 16384 / ED_PAGE_SIZE); + + sc->isa16bit = 0; + + /* + * Write a test pattern in byte mode. If this fails, then there + * probably isn't any memory at 8k - which likely means that the board + * is an NE2000. + */ + ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern)); + ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern)); + + if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) { + sc->type = ED_TYPE_NE1000; + sc->type_str = "NE1000"; + } else { + + /* neither an NE1000 nor a Linksys - try NE2000 */ + ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); + ed_nic_outb(sc, ED_P0_PSTART, 16384 / ED_PAGE_SIZE); + ed_nic_outb(sc, ED_P0_PSTOP, 32768 / ED_PAGE_SIZE); + + sc->isa16bit = 1; + + /* + * Write a test pattern in word mode. If this also fails, then + * we don't know what this board is. + */ + ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern)); + ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern)); + if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) { + sc->type = ED_TYPE_NE2000; + sc->type_str = "NE2000"; + } else { + return (ENXIO); + } + } + + + /* 8k of memory plus an additional 8k if 16bit */ + memsize = 8192 + sc->isa16bit * 8192; + +#if 0 /* probably not useful - NE boards only come two ways */ + /* allow kernel config file overrides */ + if (isa_dev->id_msize) + memsize = isa_dev->id_msize; +#endif + + sc->mem_size = memsize; + + /* NIC memory doesn't start at zero on an NE board */ + /* The start address is tied to the bus width */ + sc->mem_start = (char *) 8192 + sc->isa16bit * 8192; + sc->mem_end = sc->mem_start + memsize; + sc->tx_page_start = memsize / ED_PAGE_SIZE; + + if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_GWETHER) { + int x, i, msize = 0; + long mstart = 0; + char pbuf0[ED_PAGE_SIZE], pbuf[ED_PAGE_SIZE], tbuf[ED_PAGE_SIZE]; + + for (i = 0; i < ED_PAGE_SIZE; i++) + pbuf0[i] = 0; + + /* Clear all the memory. */ + for (x = 1; x < 256; x++) + ed_pio_writemem(sc, pbuf0, x * 256, ED_PAGE_SIZE); + + /* Search for the start of RAM. */ + for (x = 1; x < 256; x++) { + ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); + if (bcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) { + for (i = 0; i < ED_PAGE_SIZE; i++) + pbuf[i] = 255 - x; + ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE); + ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); + if (bcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0) { + mstart = x * ED_PAGE_SIZE; + msize = ED_PAGE_SIZE; + break; + } + } + } + + if (mstart == 0) { + device_printf(dev, "Cannot find start of RAM.\n"); + return (ENXIO); + } + /* Search for the start of RAM. */ + for (x = (mstart / ED_PAGE_SIZE) + 1; x < 256; x++) { + ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); + if (bcmp(pbuf0, tbuf, ED_PAGE_SIZE) == 0) { + for (i = 0; i < ED_PAGE_SIZE; i++) + pbuf[i] = 255 - x; + ed_pio_writemem(sc, pbuf, x * 256, ED_PAGE_SIZE); + ed_pio_readmem(sc, x * 256, tbuf, ED_PAGE_SIZE); + if (bcmp(pbuf, tbuf, ED_PAGE_SIZE) == 0) + msize += ED_PAGE_SIZE; + else { + break; + } + } else { + break; + } + } + + if (msize == 0) { + device_printf(dev, "Cannot find any RAM, start : %ld, x = %d.\n", mstart, x); + return (ENXIO); + } + device_printf(dev, "RAM start at %ld, size : %d.\n", mstart, msize); + + sc->mem_size = msize; + sc->mem_start = (caddr_t)(uintptr_t) mstart; + sc->mem_end = (caddr_t)(uintptr_t) (msize + mstart); + sc->tx_page_start = mstart / ED_PAGE_SIZE; + } + + /* + * Use one xmit buffer if < 16k, two buffers otherwise (if not told + * otherwise). + */ + if ((memsize < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) + sc->txb_cnt = 1; + else + sc->txb_cnt = 2; + + sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; + sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE; + + sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; + + ed_pio_readmem(sc, 0, romdata, 16); + for (n = 0; n < ETHER_ADDR_LEN; n++) + sc->arpcom.ac_enaddr[n] = romdata[n * (sc->isa16bit + 1)]; + + if ((ED_FLAGS_GETTYPE(flags) == ED_FLAGS_GWETHER) && + (sc->arpcom.ac_enaddr[2] == 0x86)) { + sc->type_str = "Gateway AT"; + } + + /* clear any pending interrupts that might have occurred above */ + ed_nic_outb(sc, ED_P0_ISR, 0xff); + + return (0); +} + +int +ed_probe_Novell(device_t dev, int port_rid, int flags) +{ + struct ed_softc *sc = device_get_softc(dev); + int error; + + error = ed_alloc_port(dev, port_rid, ED_NOVELL_IO_PORTS); + if (error) + return (error); + + sc->asic_offset = ED_NOVELL_ASIC_OFFSET; + sc->nic_offset = ED_NOVELL_NIC_OFFSET; + + return ed_probe_Novell_generic(dev, flags); +} diff --git a/sys/dev/ed/if_ed_sic.c b/sys/dev/ed/if_ed_sic.c new file mode 100644 index 000000000000..802f842a11ff --- /dev/null +++ b/sys/dev/ed/if_ed_sic.c @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 2005, M. Warner Losh + * All rights reserved. + * Copyright (c) 1995, David Greenman + * 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 unmodified, 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 AND CONTRIBUTORS ``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 CONTRIBUTORS 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 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#ifdef ED_SIC +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* + * Probe and vendor-specific initialization routine for SIC boards + */ +int +ed_probe_SIC(device_t dev, int port_rid, int flags) +{ + struct ed_softc *sc = device_get_softc(dev); + int error; + int i; + u_int memsize; + u_long pmem; + u_char sum; + + error = ed_alloc_port(dev, 0, ED_SIC_IO_PORTS); + if (error) + return (error); + + sc->asic_offset = ED_SIC_ASIC_OFFSET; + sc->nic_offset = ED_SIC_NIC_OFFSET; + + memsize = 16384; + /* XXX Needs to allow different msize */ + error = ed_alloc_memory(dev, 0, memsize); + if (error) + return (error); + + sc->mem_start = (caddr_t) rman_get_virtual(sc->mem_res); + sc->mem_size = memsize; + + pmem = rman_get_start(sc->mem_res); + error = ed_isa_mem_ok(dev, pmem, memsize); + if (error) + return (error); + + /* Reset card to force it into a known state. */ + ed_asic_outb(sc, 0, 0x00); + DELAY(100); + + /* + * Here we check the card ROM, if the checksum passes, and the + * type code and ethernet address check out, then we know we have + * an SIC card. + */ + ed_asic_outb(sc, 0, 0x81); + DELAY(100); + + sum = sc->mem_start[6]; + for (i = 0; i < ETHER_ADDR_LEN; i++) { + sum ^= (sc->arpcom.ac_enaddr[i] = sc->mem_start[i]); + } +#ifdef ED_DEBUG + device_printf(dev, "ed_probe_sic: got address %6D\n", + sc->arpcom.ac_enaddr, ":"); +#endif + if (sum != 0) { + return (ENXIO); + } + if ((sc->arpcom.ac_enaddr[0] | sc->arpcom.ac_enaddr[1] | + sc->arpcom.ac_enaddr[2]) == 0) { + return (ENXIO); + } + + sc->vendor = ED_VENDOR_SIC; + sc->type_str = "SIC"; + sc->isa16bit = 0; + sc->cr_proto = 0; + + /* + * SIC RAM page 0x0000-0x3fff(or 0x7fff) + */ + ed_asic_outb(sc, 0, 0x80); + DELAY(100); + + error = ed_clear_memory(dev); + if (error) + return (error); + + sc->mem_shared = 1; + sc->mem_end = sc->mem_start + sc->mem_size; + + /* + * allocate one xmit buffer if < 16k, two buffers otherwise + */ + if ((sc->mem_size < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) + sc->txb_cnt = 1; + else + sc->txb_cnt = 2; + sc->tx_page_start = 0; + + sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE * sc->txb_cnt; + sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE; + + sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; + + return (0); +} + +#endif /* ED_SIL */ diff --git a/sys/dev/ed/if_ed_wd80x3.c b/sys/dev/ed/if_ed_wd80x3.c new file mode 100644 index 000000000000..2ecbbb08bbe8 --- /dev/null +++ b/sys/dev/ed/if_ed_wd80x3.c @@ -0,0 +1,468 @@ +/*- + * Copyright (c) 2005, M. Warner Losh + * All rights reserved. + * Copyright (c) 1995, David Greenman + * 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 unmodified, 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 AND CONTRIBUTORS ``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 CONTRIBUTORS 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 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* + * Interrupt conversion table for WD/SMC ASIC/83C584 + */ +static uint16_t ed_intr_val[] = { + 9, + 3, + 5, + 7, + 10, + 11, + 15, + 4 +}; + +/* + * Interrupt conversion table for 83C790 + */ +static uint16_t ed_790_intr_val[] = { + 0, + 9, + 3, + 5, + 7, + 10, + 11, + 15 +}; + +static void +ed_disable_16bit_access(struct ed_softc *sc) +{ + /* + * Disable 16 bit access to shared memory + */ + if (sc->isa16bit) { + if (sc->chip_type == ED_CHIP_TYPE_WD790) + ed_asic_outb(sc, ED_WD_MSR, 0x00); + ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto & + ~ED_WD_LAAR_M16EN); + } +} + +/* + * Probe and vendor-specific initialization routine for SMC/WD80x3 boards + */ +int +ed_probe_WD80x3_generic(device_t dev, int flags, uint16_t *intr_vals[]) +{ + struct ed_softc *sc = device_get_softc(dev); + int error; + int i; + u_int memsize; + u_char iptr, isa16bit, sum, totalsum; + u_long irq, junk, pmem; + + sc->chip_type = ED_CHIP_TYPE_DP8390; + + if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { + totalsum = ED_WD_ROM_CHECKSUM_TOTAL_TOSH_ETHER; + ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_POW); + DELAY(10000); + } + else + totalsum = ED_WD_ROM_CHECKSUM_TOTAL; + + /* + * Attempt to do a checksum over the station address PROM. If it + * fails, it's probably not a SMC/WD board. There is a problem with + * this, though: some clone WD boards don't pass the checksum test. + * Danpex boards for one. + */ + for (sum = 0, i = 0; i < 8; ++i) + sum += ed_asic_inb(sc, ED_WD_PROM + i); + + if (sum != totalsum) { + + /* + * Checksum is invalid. This often happens with cheap WD8003E + * clones. In this case, the checksum byte (the eighth byte) + * seems to always be zero. + */ + if (ed_asic_inb(sc, ED_WD_CARD_ID) != ED_TYPE_WD8003E || + ed_asic_inb(sc, ED_WD_PROM + 7) != 0) + return (ENXIO); + } + /* reset card to force it into a known state. */ + if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) + ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW); + else + ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_RST); + + DELAY(100); + ed_asic_outb(sc, ED_WD_MSR, ed_asic_inb(sc, ED_WD_MSR) & ~ED_WD_MSR_RST); + /* wait in the case this card is reading its EEROM */ + DELAY(5000); + + sc->vendor = ED_VENDOR_WD_SMC; + sc->type = ed_asic_inb(sc, ED_WD_CARD_ID); + + /* + * Set initial values for width/size. + */ + memsize = 8192; + isa16bit = 0; + switch (sc->type) { + case ED_TYPE_WD8003S: + sc->type_str = "WD8003S"; + break; + case ED_TYPE_WD8003E: + sc->type_str = "WD8003E"; + break; + case ED_TYPE_WD8003EB: + sc->type_str = "WD8003EB"; + break; + case ED_TYPE_WD8003W: + sc->type_str = "WD8003W"; + break; + case ED_TYPE_WD8013EBT: + sc->type_str = "WD8013EBT"; + memsize = 16384; + isa16bit = 1; + break; + case ED_TYPE_WD8013W: + sc->type_str = "WD8013W"; + memsize = 16384; + isa16bit = 1; + break; + case ED_TYPE_WD8013EP: /* also WD8003EP */ + if (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) { + isa16bit = 1; + memsize = 16384; + sc->type_str = "WD8013EP"; + } else + sc->type_str = "WD8003EP"; + break; + case ED_TYPE_WD8013WC: + sc->type_str = "WD8013WC"; + memsize = 16384; + isa16bit = 1; + break; + case ED_TYPE_WD8013EBP: + sc->type_str = "WD8013EBP"; + memsize = 16384; + isa16bit = 1; + break; + case ED_TYPE_WD8013EPC: + sc->type_str = "WD8013EPC"; + memsize = 16384; + isa16bit = 1; + break; + case ED_TYPE_SMC8216C: /* 8216 has 16K shared mem -- 8416 has 8K */ + case ED_TYPE_SMC8216T: + if (sc->type == ED_TYPE_SMC8216C) + sc->type_str = "SMC8216/SMC8216C"; + else + sc->type_str = "SMC8216T"; + + ed_asic_outb(sc, ED_WD790_HWR, + ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); + switch (ed_asic_inb(sc, ED_WD790_RAR) & ED_WD790_RAR_SZ64) { + case ED_WD790_RAR_SZ64: + memsize = 65536; + break; + case ED_WD790_RAR_SZ32: + memsize = 32768; + break; + case ED_WD790_RAR_SZ16: + memsize = 16384; + break; + case ED_WD790_RAR_SZ8: + /* 8216 has 16K shared mem -- 8416 has 8K */ + if (sc->type == ED_TYPE_SMC8216C) + sc->type_str = "SMC8416C/SMC8416BT"; + else + sc->type_str = "SMC8416T"; + memsize = 8192; + break; + } + ed_asic_outb(sc, ED_WD790_HWR, + ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); + + isa16bit = 1; + sc->chip_type = ED_CHIP_TYPE_WD790; + break; + case ED_TYPE_TOSHIBA1: + sc->type_str = "Toshiba1"; + memsize = 32768; + isa16bit = 1; + break; + case ED_TYPE_TOSHIBA4: + sc->type_str = "Toshiba4"; + memsize = 32768; + isa16bit = 1; + break; + default: + sc->type_str = ""; + break; + } + + /* + * Make some adjustments to initial values depending on what is found + * in the ICR. + */ + if (isa16bit && (sc->type != ED_TYPE_WD8013EBT) + && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4) + && ((ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { + isa16bit = 0; + memsize = 8192; + } + + /* Override memsize? XXX */ + error = ed_alloc_memory(dev, 0, memsize); + if (error) + return (error); + sc->mem_start = (caddr_t) rman_get_virtual(sc->mem_res); + +#ifdef ED_DEBUG + printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%lu\n", + sc->type, sc->type_str, isa16bit, memsize, + rman_get_size(sc->mem_res)); + for (i = 0; i < 8; i++) + printf("%x -> %x\n", i, ed_asic_inb(sc, i)); +#endif + pmem = rman_get_start(sc->mem_res); + error = ed_isa_mem_ok(dev, pmem, memsize); + if (error) + return (error); + + /* + * (note that if the user specifies both of the following flags that + * '8bit' mode intentionally has precedence) + */ + if (flags & ED_FLAGS_FORCE_16BIT_MODE) + isa16bit = 1; + if (flags & ED_FLAGS_FORCE_8BIT_MODE) + isa16bit = 0; + + /* + * If possible, get the assigned interrupt number from the card and + * use it. + */ + if ((sc->type & ED_WD_SOFTCONFIG) && + (sc->chip_type != ED_CHIP_TYPE_WD790)) { + + /* + * Assemble together the encoded interrupt number. + */ + iptr = (ed_asic_inb(sc, ED_WD_ICR) & ED_WD_ICR_IR2) | + ((ed_asic_inb(sc, ED_WD_IRR) & + (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5); + + /* + * If no interrupt specified (or "?"), use what the board tells us. + */ + error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); + if (error && intr_vals[0] != NULL) + error = bus_set_resource(dev, SYS_RES_IRQ, 0, + intr_vals[0][iptr], 1); + if (error) + return (error); + + /* + * Enable the interrupt. + */ + ed_asic_outb(sc, ED_WD_IRR, + ed_asic_inb(sc, ED_WD_IRR) | ED_WD_IRR_IEN); + } + if (sc->chip_type == ED_CHIP_TYPE_WD790) { + ed_asic_outb(sc, ED_WD790_HWR, + ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH); + iptr = (((ed_asic_inb(sc, ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) | + (ed_asic_inb(sc, ED_WD790_GCR) & + (ED_WD790_GCR_IR1 | ED_WD790_GCR_IR0)) >> 2); + ed_asic_outb(sc, ED_WD790_HWR, + ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH); + + /* + * If no interrupt specified (or "?"), use what the board tells us. + */ + error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); + if (error && intr_vals[1] != NULL) + error = bus_set_resource(dev, SYS_RES_IRQ, 0, + intr_vals[1][iptr], 1); + if (error) + return (error); + + /* + * Enable interrupts. + */ + ed_asic_outb(sc, ED_WD790_ICR, + ed_asic_inb(sc, ED_WD790_ICR) | ED_WD790_ICR_EIL); + } + error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); + if (error) { + device_printf(dev, "%s cards don't support auto-detected/assigned interrupts.\n", + sc->type_str); + return (ENXIO); + } + sc->isa16bit = isa16bit; + sc->mem_shared = 1; + + /* + * allocate one xmit buffer if < 16k, two buffers otherwise + */ + if (memsize < 16384 || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) + sc->txb_cnt = 1; + else + sc->txb_cnt = 2; + sc->tx_page_start = ED_WD_PAGE_OFFSET; + sc->rec_page_start = ED_WD_PAGE_OFFSET + ED_TXBUF_SIZE * sc->txb_cnt; + sc->rec_page_stop = ED_WD_PAGE_OFFSET + memsize / ED_PAGE_SIZE; + sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * sc->rec_page_start); + sc->mem_size = memsize; + sc->mem_end = sc->mem_start + memsize; + + /* + * Get station address from on-board ROM + */ + for (i = 0; i < ETHER_ADDR_LEN; ++i) + sc->arpcom.ac_enaddr[i] = ed_asic_inb(sc, ED_WD_PROM + i); + + /* + * Set upper address bits and 8/16 bit access to shared memory. + */ + if (isa16bit) { + if (sc->chip_type == ED_CHIP_TYPE_WD790) + sc->wd_laar_proto = ed_asic_inb(sc, ED_WD_LAAR); + else + sc->wd_laar_proto = ED_WD_LAAR_L16EN | + ((pmem >> 19) & ED_WD_LAAR_ADDRHI); + /* + * Enable 16bit access + */ + ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto | + ED_WD_LAAR_M16EN); + } else { + if (((sc->type & ED_WD_SOFTCONFIG) || + (sc->type == ED_TYPE_TOSHIBA1) || + (sc->type == ED_TYPE_TOSHIBA4) || + (sc->type == ED_TYPE_WD8013EBT)) && + (sc->chip_type != ED_CHIP_TYPE_WD790)) { + sc->wd_laar_proto = (pmem >> 19) & + ED_WD_LAAR_ADDRHI; + ed_asic_outb(sc, ED_WD_LAAR, sc->wd_laar_proto); + } + } + + /* + * Set address and enable interface shared memory. + */ + if (sc->chip_type != ED_CHIP_TYPE_WD790) { + if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_TOSH_ETHER) { + ed_asic_outb(sc, ED_WD_MSR + 1, + ((pmem >> 8) & 0xe0) | 4); + ed_asic_outb(sc, ED_WD_MSR + 2, ((pmem >> 16) & 0x0f)); + ed_asic_outb(sc, ED_WD_MSR, + ED_WD_MSR_MENB | ED_WD_MSR_POW); + } else { + ed_asic_outb(sc, ED_WD_MSR, ((pmem >> 13) & + ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); + } + sc->cr_proto = ED_CR_RD2; + } else { + ed_asic_outb(sc, ED_WD_MSR, ED_WD_MSR_MENB); + ed_asic_outb(sc, ED_WD790_HWR, + (ed_asic_inb(sc, ED_WD790_HWR) | ED_WD790_HWR_SWH)); + ed_asic_outb(sc, ED_WD790_RAR, + ((pmem >> 13) & 0x0f) | ((pmem >> 11) & 0x40) | + (ed_asic_inb(sc, ED_WD790_RAR) & 0xb0)); + ed_asic_outb(sc, ED_WD790_HWR, + (ed_asic_inb(sc, ED_WD790_HWR) & ~ED_WD790_HWR_SWH)); + sc->cr_proto = 0; + } + + error = ed_clear_memory(dev); + if (error) { + ed_disable_16bit_access(sc); + return (error); + } + + /* + * Disable 16bit access to shared memory - we leave it + * disabled so that 1) machines reboot properly when the board + * is set 16 bit mode and there are conflicting 8bit + * devices/ROMS in the same 128k address space as this boards + * shared memory. and 2) so that other 8 bit devices with + * shared memory can be used in this 128k region, too. + */ + ed_disable_16bit_access(sc); + return (0); +} + +int +ed_probe_WD80x3(device_t dev, int port_rid, int flags) +{ + struct ed_softc *sc = device_get_softc(dev); + int error; + static uint16_t *intr_vals[] = {ed_intr_val, ed_790_intr_val}; + + error = ed_alloc_port(dev, port_rid, ED_WD_IO_PORTS); + if (error) + return (error); + + sc->asic_offset = ED_WD_ASIC_OFFSET; + sc->nic_offset = ED_WD_NIC_OFFSET; + + return ed_probe_WD80x3_generic(dev, flags, intr_vals); +} diff --git a/sys/dev/ed/if_edvar.h b/sys/dev/ed/if_edvar.h index 5020858bf8e7..4707f35dafdd 100644 --- a/sys/dev/ed/if_edvar.h +++ b/sys/dev/ed/if_edvar.h @@ -207,6 +207,7 @@ int ed_probe_HP_pclanp(device_t, int, int); int ed_attach(device_t); int ed_detach(device_t); int ed_clear_memory(device_t); +int ed_isa_mem_ok(device_t, u_long, u_int); /* XXX isa specific */ void ed_stop(struct ed_softc *); void ed_pio_readmem(struct ed_softc *, long, uint8_t *, uint16_t); void ed_pio_writemem(struct ed_softc *, uint8_t *, uint16_t, uint16_t); @@ -218,6 +219,11 @@ void ed_ifmedia_sts(struct ifnet *, struct ifmediareq *); void ed_child_detached(device_t, device_t); #endif +/* The following is unsatisfying XXX */ +void ed_hpp_set_physical_link(struct ed_softc *); +void ed_hpp_readmem(struct ed_softc *, long, uint8_t *, uint16_t); +u_short ed_hpp_write_mbufs(struct ed_softc *, struct mbuf *, int); + driver_intr_t edintr; extern devclass_t ed_devclass; diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 70267c4426b4..ba9a5633cf18 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -547,6 +547,9 @@ hint.cx.0.drq="7" #options NETGRAPH_CRONYX # Enable NETGRAPH support for Cronyx adapter(s) device ed #options ED_NO_MIIBUS # Disable ed miibus support +options ED_3C503 +options ED_HPP +options ED_SIC hint.ed.0.at="isa" hint.ed.0.port="0x280" hint.ed.0.irq="5" diff --git a/sys/modules/ed/Makefile b/sys/modules/ed/Makefile index dda16edcd34a..7f1524263a12 100644 --- a/sys/modules/ed/Makefile +++ b/sys/modules/ed/Makefile @@ -3,12 +3,12 @@ .PATH: ${.CURDIR}/../../dev/ed KMOD= if_ed -SRCS= if_ed.c if_ed_pccard.c if_ed_pci.c +SRCS= if_ed.c if_ed_pccard.c if_ed_pci.c if_ed_novell.c if_ed_wd80x3.c .if ${MACHINE} == "pc98" SRCS+= if_ed_cbus.c .else -SRCS+= if_ed_isa.c +SRCS+= if_ed_isa.c if_ed_3c503.c if_ed_hpp.c if_ed_sic.c .endif SRCS+= opt_ed.h opt_bdg.h bus_if.h card_if.h device_if.h isa_if.h pci_if.h \