/* * 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 = 0; 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 = bus_space_read_1(sc->mem_bst, sc->mem_bsh, 6); for (i = 0; i < ETHER_ADDR_LEN; i++) sum ^= (sc->enaddr[i] = bus_space_read_1(sc->mem_bst, sc->mem_bsh, i)); #ifdef ED_DEBUG device_printf(dev, "ed_probe_sic: got address %6D\n", sc->enaddr, ":"); #endif if (sum != 0) return (ENXIO); if ((sc->enaddr[0] | sc->enaddr[1] | sc->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; sc->sc_write_mbufs = ed_shmem_write_mbufs; return (0); }
/* * 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->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 = 0; 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); error = ed_clear_memory(dev); if (error == 0) { sc->sc_mediachg = ed_3c503_mediachg; sc->sc_write_mbufs = ed_shmem_write_mbufs; } return (error); }