diff options
author | Nathan Binkert <nate@cvs.openbsd.org> | 2002-11-26 04:38:41 +0000 |
---|---|---|
committer | Nathan Binkert <nate@cvs.openbsd.org> | 2002-11-26 04:38:41 +0000 |
commit | ac8c6edd278d9a63a5be3372050dbe15052741a4 (patch) | |
tree | 7683b7da5a03f6cb6ff6151084a017467ac003ed /sys/dev/pci/if_bge.c | |
parent | 54990c61b63d1bdb38b084ae4cbade3108b7a87d (diff) |
Numerous bug fixes from freebsd and a few from me.
- Add support for the BCM5702X and BCM5703X chips
- Take care of an alignment bug in the PCI-X implementation of a couple revs
of the chip
- Disable memory write invalidate. (Supposedly doesn't always work)
- Add missing splx(s)
- Fix some typos
Diffstat (limited to 'sys/dev/pci/if_bge.c')
-rw-r--r-- | sys/dev/pci/if_bge.c | 163 |
1 files changed, 91 insertions, 72 deletions
diff --git a/sys/dev/pci/if_bge.c b/sys/dev/pci/if_bge.c index 50d4f0f96c8..dc3390693d0 100644 --- a/sys/dev/pci/if_bge.c +++ b/sys/dev/pci/if_bge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bge.c,v 1.14 2002/09/23 14:49:21 nate Exp $ */ +/* $OpenBSD: if_bge.c,v 1.15 2002/11/26 04:38:40 nate Exp $ */ /* * Copyright (c) 2001 Wind River Systems * Copyright (c) 1997, 1998, 1999, 2001 @@ -31,7 +31,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: if_bge.c,v 1.11 2002/04/04 06:01:31 wpaul Exp $ + * $FreeBSD: if_bge.c,v 1.25 2002/11/14 23:54:49 sam Exp $ */ /* @@ -58,7 +58,7 @@ * function in a 32-bit/64-bit 33/66Mhz bus, or a 64-bit/133Mhz bus. * * The BCM5701 is a single-chip solution incorporating both the BCM5700 - * MAC and a BCM5401 10/100/1000 PHY. Unlike the BCM5700, the BCM5700 + * MAC and a BCM5401 10/100/1000 PHY. Unlike the BCM5700, the BCM5701 * does not support external SSRAM. * * Broadcom also produces a variation of the BCM5700 under the "Altima" @@ -140,7 +140,7 @@ void bge_ifmedia_sts(struct ifnet *, struct ifmediareq *); u_int8_t bge_eeprom_getbyte(struct bge_softc *, int, u_int8_t *); int bge_read_eeprom(struct bge_softc *, caddr_t, int, int); -u_int32_t bge_crc(struct bge_softc *, caddr_t); +u_int32_t bge_crc(caddr_t); void bge_setmulti(struct bge_softc *); void bge_handle_events(struct bge_softc *); @@ -410,8 +410,12 @@ bge_miibus_readreg(dev, phy, reg) ifp = &sc->arpcom.ac_if; - if (sc->bge_asicrev == BGE_ASICREV_BCM5701_B5 && phy != 1) - return(0); + if (phy != 1) + switch(sc->bge_asicrev) { + case BGE_ASICREV_BCM5701_B5: + case BGE_ASICREV_BCM5703_A2: + return(0); + } CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_READ|BGE_MICOMM_BUSY| BGE_MIPHY(phy)|BGE_MIREG(reg)); @@ -659,10 +663,12 @@ bge_newbuf_std(sc, i, m) if (bus_dmamap_load_mbuf(sc->bge_dmatag, rxmap, m_new, BUS_DMA_NOWAIT)) return(ENOBUFS); - m_adj(m_new, ETHER_ALIGN); + if (!sc->bge_rx_alignment_bug) + m_adj(m_new, ETHER_ALIGN); sc->bge_cdata.bge_rx_std_chain[i] = m_new; r = &sc->bge_rdata->bge_rx_std_ring[i]; - BGE_HOSTADDR(r->bge_addr) = rxmap->dm_segs[0].ds_addr + ETHER_ALIGN; + BGE_HOSTADDR(r->bge_addr) = rxmap->dm_segs[0].ds_addr + + (!sc->bge_rx_alignment_bug ? ETHER_ALIGN : 0); r->bge_flags = BGE_RXBDFLAG_END; r->bge_len = m_new->m_len; r->bge_idx = i; @@ -710,12 +716,13 @@ bge_newbuf_jumbo(sc, i, m) m_new->m_ext.ext_size = BGE_JUMBO_FRAMELEN; } - m_adj(m_new, ETHER_ALIGN); + if (!sc->bge_rx_alignment_bug) + m_adj(m_new, ETHER_ALIGN); /* Set up the descriptor. */ r = &sc->bge_rdata->bge_rx_jumbo_ring[i]; sc->bge_cdata.bge_rx_jumbo_chain[i] = m_new; - BGE_HOSTADDR(r->bge_addr) = - BGE_JUMBO_DMA_ADDR(sc, m_new) + ETHER_ALIGN; + BGE_HOSTADDR(r->bge_addr) = BGE_JUMBO_DMA_ADDR(sc, m_new) + + (!sc->bge_rx_alignment_bug ? ETHER_ALIGN : 0); r->bge_flags = BGE_RXBDFLAG_END|BGE_RXBDFLAG_JUMBO_RING; r->bge_len = m_new->m_len; r->bge_idx = i; @@ -855,8 +862,7 @@ bge_init_tx_ring(sc) #define BGE_POLY 0xEDB88320 u_int32_t -bge_crc(sc, addr) - struct bge_softc *sc; +bge_crc(addr) caddr_t addr; { u_int32_t idx, bit, data, crc; @@ -897,7 +903,7 @@ bge_setmulti(sc) /* Now program new ones. */ ETHER_FIRST_MULTI(step, ac, enm); while (enm != NULL) { - h = bge_crc(sc, LLADDR((struct sockaddr_dl *)enm->enm_addrlo)); + h = bge_crc(LLADDR((struct sockaddr_dl *)enm->enm_addrlo)); hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F); ETHER_NEXT_MULTI(step, enm); } @@ -914,7 +920,6 @@ int bge_chipinit(sc) struct bge_softc *sc; { - u_int32_t cachesize; int i; struct pci_attach_args *pa = &(sc->bge_pa); @@ -958,8 +963,16 @@ bge_chipinit(sc) BGE_MEMWIN_WRITE(pa->pa_pc, pa->pa_tag, i, 0); /* Set up the PCI DMA control register. */ - pci_conf_write(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, - BGE_PCI_READ_CMD|BGE_PCI_WRITE_CMD|0x0F); + if (pci_conf_read(pa->pa_pc, pa->pa_tag, BGE_PCI_PCISTATE) & + BGE_PCISTATE_PCI_BUSMODE) { + /* Conventional PCI bus */ + pci_conf_write(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, + BGE_PCI_READ_CMD|BGE_PCI_WRITE_CMD|0x3F000F); + } else { + /* PCI-X bus */ + pci_conf_write(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, + BGE_PCI_READ_CMD|BGE_PCI_WRITE_CMD|0x1B000F); + } /* * Set up general mode register. @@ -979,56 +992,12 @@ bge_chipinit(sc) ); #endif - /* Get cache line size. */ - cachesize = pci_conf_read(pa->pa_pc, pa->pa_tag, BGE_PCI_CACHESZ); - /* - * Avoid violating PCI spec on certain chip revs. + * Disable memory write invalidate. Apparently it is not supported + * properly by these devices. */ - if (pci_conf_read(pa->pa_pc, pa->pa_tag, BGE_PCI_CMD) & - PCIM_CMD_MWIEN) { - switch(cachesize) { - case 1: - PCI_SETBIT(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, - BGE_PCI_WRITE_BNDRY_16BYTES); - break; - case 2: - PCI_SETBIT(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, - BGE_PCI_WRITE_BNDRY_32BYTES); - break; - case 4: - PCI_SETBIT(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, - BGE_PCI_WRITE_BNDRY_64BYTES); - break; - case 8: - PCI_SETBIT(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, - BGE_PCI_WRITE_BNDRY_128BYTES); - break; - case 16: - PCI_SETBIT(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, - BGE_PCI_WRITE_BNDRY_256BYTES); - break; - case 32: - PCI_SETBIT(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, - BGE_PCI_WRITE_BNDRY_512BYTES); - break; - case 64: - PCI_SETBIT(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, - BGE_PCI_WRITE_BNDRY_1024BYTES); - break; - default: - /* Disable PCI memory write and invalidate. */ -#if 0 - if (bootverbose) - printf("%s: cache line size %d not " - "supported; disabling PCI MWI\n", - sc->bge_dev.dv_xname, cachesize); -#endif - PCI_CLRBIT(pa->pa_pc, pa->pa_tag, BGE_PCI_CMD, - PCIM_CMD_MWIEN); - break; - } - } + PCI_CLRBIT(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, + PCI_COMMAND_INVALIDATE_ENABLE); #ifdef __brokenalpha__ /* @@ -1037,7 +1006,8 @@ bge_chipinit(sc) * restriction on some ALPHA platforms with early revision * 21174 PCI chipsets, such as the AlphaPC 164lx */ - PCI_SETBIT(sc, BGE_PCI_DMA_RW_CTL, BGE_PCI_READ_BNDRY_1024, 4); + PCI_SETBIT(pa->pa_pc, pa->pa_tag, BGE_PCI_DMA_RW_CTL, + BGE_PCI_READ_BNDRY_1024); #endif /* Set the timer prescaler (always 66Mhz) */ @@ -1423,12 +1393,17 @@ bge_probe(parent, match, aux) return (1); if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALTIMA && - PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALTIMA_AC100X) + (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALTIMA_AC100X || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALTIMA_AC9100)) return (1); if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_BROADCOM && (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM5700 || - PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM5701)) + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM5701 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM5702 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM5703 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM5702X || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_BROADCOM_BCM5703X)) return (1); if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SCHNEIDERKOCH && @@ -1457,6 +1432,7 @@ bge_attach(parent, self, aux) bus_dma_segment_t seg; int s, rseg; u_int32_t hwcfg = 0; + u_int32_t mac_addr = 0; u_int32_t command; struct ifnet *ifp; int unit, error = 0; @@ -1534,7 +1510,16 @@ bge_attach(parent, self, aux) /* * Get station address from the EEPROM. */ - if (bge_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr, + mac_addr = bge_readmem_ind(sc, 0x0c14); + if ((mac_addr >> 16) == 0x484b) { + sc->arpcom.ac_enaddr[0] = (u_char)(mac_addr >> 8); + sc->arpcom.ac_enaddr[1] = (u_char)mac_addr; + mac_addr = bge_readmem_ind(sc, 0x0c18); + sc->arpcom.ac_enaddr[2] = (u_char)(mac_addr >> 24); + sc->arpcom.ac_enaddr[3] = (u_char)(mac_addr >> 16); + sc->arpcom.ac_enaddr[4] = (u_char)(mac_addr >> 8); + sc->arpcom.ac_enaddr[5] = (u_char)mac_addr; + } else if (bge_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr, BGE_EE_MAC_OFFSET + 2, ETHER_ADDR_LEN)) { printf("bge%d: failed to read station address\n", unit); bge_release_resources(sc); @@ -1633,7 +1618,7 @@ bge_attach(parent, self, aux) /* Save ASIC rev. */ sc->bge_asicrev = - pci_conf_read(pa->pa_pc, pa->pa_tag, BGE_PCI_MISC_CTL) & + pci_conf_read(pc, pa->pa_tag, BGE_PCI_MISC_CTL) & BGE_PCIMISCCTL_ASICREV; /* Pretend all 5700s are the same */ @@ -1653,7 +1638,7 @@ bge_attach(parent, self, aux) sc->bge_tbi = 1; /* The SysKonnect SK-9D41 is a 1000baseSX card. */ - if ((pci_conf_read(pa->pa_pc, pa->pa_tag, BGE_PCI_SUBSYS) >> 16) == + if ((pci_conf_read(pc, pa->pa_tag, BGE_PCI_SUBSYS) >> 16) == SK_SUBSYSID_9D41) sc->bge_tbi = 1; @@ -1686,6 +1671,27 @@ bge_attach(parent, self, aux) } /* + * When using the BCM5701 in PCI-X mode, data corruption has + * been observed in the first few bytes of some received packets. + * Aligning the packet buffer in memory eliminates the corruption. + * Unfortunately, this misaligns the packet payloads. On platforms + * which do not support unaligned accesses, we will realign the + * payloads by copying the received packets. + */ + switch (sc->bge_asicrev) { + case BGE_ASICREV_BCM5701_A0: + case BGE_ASICREV_BCM5701_B0: + case BGE_ASICREV_BCM5701_B2: + case BGE_ASICREV_BCM5701_B5: + /* If in PCI-X mode, work around the alignment bug. */ + if ((pci_conf_read(pc, pa->pa_tag, BGE_PCI_PCISTATE) & + (BGE_PCISTATE_PCI_BUSMODE | BGE_PCISTATE_PCI_BUSSPEED)) == + BGE_PCISTATE_PCI_BUSSPEED) + sc->bge_rx_alignment_bug = 1; + break; + } + + /* * Call MI attach routine. */ DPRINTFN(5, ("if_attach\n")); @@ -1888,6 +1894,17 @@ bge_rxeof(sc) } ifp->if_ipackets++; +#ifdef __STRICT_ALIGNMENT + /* + * The i386 allows unaligned accesses, but for other + * platforms we must make sure the payload is aligned. + */ + if (sc->bge_rx_alignment_bug) { + bcopy(m->m_data, m->m_data + ETHER_ALIGN, + cur_rx->bge_len); + m->m_data += ETHER_ALIGN; + } +#endif m->m_pkthdr.len = m->m_len = cur_rx->bge_len; m->m_pkthdr.rcvif = ifp; @@ -2343,8 +2360,10 @@ bge_init(xsc) ifp = &sc->arpcom.ac_if; - if (ifp->if_flags & IFF_RUNNING) + if (ifp->if_flags & IFF_RUNNING) { + splx(s); return; + } /* Cancel pending I/O and flush buffers. */ bge_stop(sc); |