diff options
author | imp <imp@FreeBSD.org> | 2005-02-09 20:03:40 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2005-02-09 20:03:40 +0000 |
commit | 8ea73f2d54b61e3b2d8dc144c0b297495fd036ca (patch) | |
tree | e520b94cdc40902296c7025be4da781935e62252 /sys/dev | |
parent | 8f0a058ccfd2cb813f106e7bc58590b321d6938c (diff) | |
download | FreeBSD-src-8ea73f2d54b61e3b2d8dc144c0b297495fd036ca.zip FreeBSD-src-8ea73f2d54b61e3b2d8dc144c0b297495fd036ca.tar.gz |
Break out obscure ISA cards into their own files, as well as ne2000
and wd80x3 support. Make the obscure ISA cards optional, and add
those options to NOTES on i386 (note: the ifdef around the whole code
is for module building). Tweak pc98 ed support to include wd80x3 too.
Add goo for alpha too.
The affected cards are the 3Com 3C503, HP LAN+ and SIC (whatever that
is). I couldn't find any of these for sale on ebay, so they are
untested. If you have one of these cards, and send it to me, I'll
ensure that you have no future problems with it...
Minor cleanups as well by using functions rather than cut and paste
code for some probing operations (where the function call overhead is
lost in the noise).
Remove use of kvtop, since they aren't required anymore. This driver
needs to get its memory mapped act together, however, and use bus
space. It doesn't right now.
This reduces the size of if_ed.ko from about 51k to 33k on my laptop.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ed/if_ed.c | 1745 | ||||
-rw-r--r-- | sys/dev/ed/if_ed_3c503.c | 341 | ||||
-rw-r--r-- | sys/dev/ed/if_ed_hpp.c | 663 | ||||
-rw-r--r-- | sys/dev/ed/if_ed_isa.c | 10 | ||||
-rw-r--r-- | sys/dev/ed/if_ed_novell.c | 288 | ||||
-rw-r--r-- | sys/dev/ed/if_ed_sic.c | 159 | ||||
-rw-r--r-- | sys/dev/ed/if_ed_wd80x3.c | 468 | ||||
-rw-r--r-- | sys/dev/ed/if_edvar.h | 6 |
8 files changed, 1958 insertions, 1722 deletions
diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c index 22f9704..4a349e5 100644 --- a/sys/dev/ed/if_ed.c +++ b/sys/dev/ed/if_ed.c @@ -68,8 +68,6 @@ __FBSDID("$FreeBSD$"); #include <net/bpf.h> -#include <machine/md_var.h> - #include <dev/ed/if_edreg.h> #include <dev/ed/if_edvar.h> @@ -91,68 +89,11 @@ 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 * works by looking at certain register values that are guaranteed @@ -189,1387 +130,6 @@ ed_probe_generic8390(struct ed_softc *sc) } /* - * 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. */ int @@ -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. @@ -3465,6 +1759,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) { struct ed_softc *sc = device_get_softc(dev); diff --git a/sys/dev/ed/if_ed_3c503.c b/sys/dev/ed/if_ed_3c503.c new file mode 100644 index 0000000..b46e107 --- /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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#ifdef ED_3C503 + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/syslog.h> + +#include <sys/bus.h> + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_mib.h> +#include <net/if_media.h> + +#include <net/bpf.h> + +#include <dev/ed/if_edreg.h> +#include <dev/ed/if_edvar.h> + +/* + * 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 0000000..c993cc1 --- /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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#ifdef ED_HPP + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/syslog.h> + +#include <sys/bus.h> + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_mib.h> +#include <net/if_media.h> + +#include <net/bpf.h> + +#include <dev/ed/if_edreg.h> +#include <dev/ed/if_edvar.h> + +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 2b963d1..742789c 100644 --- a/sys/dev/ed/if_ed_isa.c +++ b/sys/dev/ed/if_ed_isa.c @@ -29,6 +29,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_ed.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/socket.h> @@ -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 0000000..235dee6 --- /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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/syslog.h> + +#include <sys/bus.h> + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_mib.h> +#include <net/if_media.h> + +#include <net/bpf.h> + +#include <dev/ed/if_edreg.h> +#include <dev/ed/if_edvar.h> + +/* + * 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 0000000..802f842 --- /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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#ifdef ED_SIC +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/syslog.h> + +#include <sys/bus.h> + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_mib.h> +#include <net/if_media.h> + +#include <net/bpf.h> + +#include <dev/ed/if_edreg.h> +#include <dev/ed/if_edvar.h> + +/* + * 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 0000000..2ecbbb0 --- /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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ed.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/syslog.h> + +#include <sys/bus.h> + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_mib.h> +#include <net/if_media.h> + +#include <net/bpf.h> + +#include <dev/ed/if_edreg.h> +#include <dev/ed/if_edvar.h> + +/* + * 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 5020858..4707f35 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; |