Date: Thu, 21 Nov 2002 20:40:24 -0500 From: Don Bowman <don@sandvine.com> To: "'freebsd-stable@freebsd.org'" <freebsd-stable@freebsd.org>, "'freebsd-net@freebsd.org'" <freebsd-net@freebsd.org> Cc: "'mp@FreeBSD.org'" <mp@FreeBSD.org>, "'jdp@polstra.com'" <jdp@polstra.com>, "'m.barthelow@F5.com'" <m.barthelow@F5.com> Subject: bge bug w/ out of bounds return receiver, staying in rxeof all th e time, patch Message-ID: <FE045D4D9F7AED4CBFF1B3B813C8533701022FFD@mail.sandvine.com>
next in thread | raw e-mail | index | archive | help
(apologies if you got this more than once, but after 6 hours it hadn't shown up on the mailing list) There is a bug in the STABLE (and current) if_bge which causes the driver to loop forever in interrupt context (in bge_rxeof()). This is caused by the return ring length being 1024 in the driver, and erroneously decided to be 2048 in the chip, which causes it to return an index off the end off the ring. You will know you are running into this if your kernel locks up, ^T still works, and the debugger shows you in bge_rxeof() or a routine called from it. This situation can occur regardless of traffic. It seems to either work or not work from the get-go, so if you are going to run into it, it will be boolean from the machine startup. The patch attached solves this problem by changing the 16-bit writes into the chip's memory window to 32-bit writes. The patch also enables the PCI-VPD (See PCI 2.2) output (to help diagnose which version of the chip you have, whose board, how fast the PCI clock is etc). I would recommend a committer look this over and commit it. If you wish, I can make the patch *just* be the change (changing the 16-bit to 32-bit writes, without the VPD stuff), but the other changes seemed generally useful. Index: if_bge.c =================================================================== RCS file: /cvs/src/sys/dev/bge/if_bge.c,v retrieving revision 1.3.2.18 diff -U3 -r1.3.2.18 if_bge.c --- if_bge.c 2 Nov 2002 18:22:23 -0000 1.3.2.18 +++ if_bge.c 21 Nov 2002 20:13:23 -0000 @@ -114,6 +114,7 @@ #include <dev/bge/if_bgereg.h> #define BGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) +#define BGE_VPD /* "controller miibus0" required. See GENERIC if you get errors here. */ #include "miibus_if.h" @@ -178,6 +179,7 @@ static u_int8_t bge_eeprom_getbyte __P((struct bge_softc *, int, u_int8_t *)); static int bge_read_eeprom __P((struct bge_softc *, caddr_t, int, int)); +static void dump_manufacturing_information __P((struct bge_softc *)); static u_int32_t bge_crc __P((caddr_t)); static void bge_setmulti __P((struct bge_softc *)); @@ -200,11 +202,12 @@ static int bge_chipinit __P((struct bge_softc *)); static int bge_blockinit __P((struct bge_softc *)); -#ifdef notdef +#ifdef BGE_VPD +static void bge_vpd_crack __P((struct bge_softc *sc)); static u_int8_t bge_vpd_readbyte __P((struct bge_softc *, int)); static void bge_vpd_read_res __P((struct bge_softc *, struct vpd_res *, int)); -static void bge_vpd_read __P((struct bge_softc *)); +static void bge_vpd_read __P((struct bge_softc *, const char *)); #endif static u_int32_t bge_readmem_ind @@ -311,7 +314,7 @@ return; } -#ifdef notdef +#ifdef BGE_VPD static u_int8_t bge_vpd_readbyte(sc, addr) struct bge_softc *sc; @@ -355,9 +358,54 @@ return; } +/* + * Take the read-only (VPD-R) info and crack it into the other fields +*/ +static void +bge_vpd_crack(sc) + struct bge_softc *sc; +{ + int pos = 0; + int len = strlen(sc->bge_vpd_readonly); + sc->bge_vpd_pn = "unknown"; + sc->bge_vpd_ec = "unknown"; + sc->bge_vpd_mn = "unknown"; + sc->bge_vpd_sn = "unknown"; + sc->bge_vpd_rv = "unknown"; + while (pos < len) { + if (!strncmp(sc->bge_vpd_readonly+pos, VPD_PN, 2)) { + sc->bge_vpd_pn = (sc->bge_vpd_readonly+pos+3); + } else if (!strncmp(sc->bge_vpd_readonly+pos, VPD_EC, 2)) { + sc->bge_vpd_ec = (sc->bge_vpd_readonly+pos+3); + } else if (!strncmp(sc->bge_vpd_readonly+pos, VPD_MN, 2)) { + sc->bge_vpd_mn = (sc->bge_vpd_readonly+pos+3); + } else if (!strncmp(sc->bge_vpd_readonly+pos, VPD_SN, 2)) { + sc->bge_vpd_sn = (sc->bge_vpd_readonly+pos+3); + } else if (!strncmp(sc->bge_vpd_readonly+pos, VPD_RV, 2)) { + sc->bge_vpd_rv = (sc->bge_vpd_readonly+pos+3); + } + sc->bge_vpd_readonly[pos] = '\0'; + pos += 2; + pos += sc->bge_vpd_readonly[pos]; + pos++; + } + pos = 0; + len = strlen(sc->bge_vpd_readwrite); + while (pos < len) { + if (!strncmp(sc->bge_vpd_readwrite+pos, VPD_YA, 2)) { + sc->bge_vpd_asset_tag = (sc->bge_vpd_readwrite+pos+3); + } + sc->bge_vpd_readwrite[pos] = '\0'; + pos += 2; + pos += sc->bge_vpd_readwrite[pos]; + pos++; + } +} + static void -bge_vpd_read(sc) +bge_vpd_read(sc, defname) struct bge_softc *sc; + const char *defname; { int pos = 0, i; struct vpd_res res; @@ -366,14 +414,20 @@ free(sc->bge_vpd_prodname, M_DEVBUF); if (sc->bge_vpd_readonly != NULL) free(sc->bge_vpd_readonly, M_DEVBUF); + if (sc->bge_vpd_readwrite != NULL) + free(sc->bge_vpd_readwrite, M_DEVBUF); sc->bge_vpd_prodname = NULL; sc->bge_vpd_readonly = NULL; + sc->bge_vpd_readwrite = NULL; bge_vpd_read_res(sc, &res, pos); if (res.vr_id != VPD_RES_ID) { - printf("bge%d: bad VPD resource id: expected %x got %x\n", + printf("bge%d: bad VPD-ID resource id: expected %x got %x\n", sc->bge_unit, VPD_RES_ID, res.vr_id); + sc->bge_vpd_prodname = malloc(strlen(defname) + 1, + M_DEVBUF, M_NOWAIT); + strcpy(sc->bge_vpd_prodname, defname); return; } @@ -387,7 +441,7 @@ bge_vpd_read_res(sc, &res, pos); if (res.vr_id != VPD_RES_READ) { - printf("bge%d: bad VPD resource id: expected %x got %x\n", + printf("bge%d: bad VPD-R resource id: expected %x got %x\n", sc->bge_unit, VPD_RES_READ, res.vr_id); return; } @@ -396,6 +450,22 @@ sc->bge_vpd_readonly = malloc(res.vr_len, M_DEVBUF, M_NOWAIT); for (i = 0; i < res.vr_len + 1; i++) sc->bge_vpd_readonly[i] = bge_vpd_readbyte(sc, i + pos); + pos += i-1; + + bge_vpd_read_res(sc, &res, pos); + + if (res.vr_id != VPD_RES_WRITE) { + printf("bge%d: bad VPD-W resource id: expected %x got %x\n", + sc->bge_unit, VPD_RES_WRITE, res.vr_id); + return; + } + + pos += sizeof(res); + sc->bge_vpd_readwrite = malloc(res.vr_len, M_DEVBUF, M_NOWAIT); + for (i = 0; i < res.vr_len + 1; i++) + sc->bge_vpd_readwrite[i] = bge_vpd_readbyte(sc, i + pos); + + bge_vpd_crack(sc); return; } @@ -451,6 +521,32 @@ } /* + * Dump the information from the manufacturing info area of the eeprom + * which includes the rev, the types of phy, etc. +*/ +static void +dump_manufacturing_information(struct bge_softc *sc) +{ + char ee[140]; + if (!bge_read_eeprom(sc, ee, 0x74, 140)) { + printf("bge%d: %s(%c%c), mfg format: REV%c, mfg on: %u asicrev: %08x\n", + sc->bge_unit, + &ee[0x10], + ee[0x20],ee[0x21], + ee[0], + (unsigned int)htonl(*(unsigned int *)(&ee[0x24])), + sc->bge_asicrev); + printf("bge%d: phy-id: 0x%x BCM devid: 0x%04x, PCI sub-devid 0x%04x PCI PCI sub-vid 0x%04x\n", + sc->bge_unit, + (unsigned int )htonl(*(unsigned int *)(&ee[4])), + htons(*(unsigned short *)(&ee[0x2e])), + htons(*(unsigned short *)(&ee[0x30])), + htons(*(unsigned short *)(&ee[0x32]))); + printf("bge%d: clock-speed: %dMHz\n", sc->bge_unit,htons(*(unsigned short *)(&ee[0x34]))); + } +} + +/* * Read a sequence of bytes from the EEPROM. */ static int @@ -901,7 +997,8 @@ sc->bge_cdata.bge_rx_std_chain[i] = NULL; } bzero((char *)&sc->bge_rdata->bge_rx_std_ring[i], - sizeof(struct bge_rx_bd)); + sizeof(struct bge_rx_bd)); + } return; @@ -913,7 +1010,7 @@ { int i; struct bge_rcb *rcb; - struct bge_rcb_opaque *rcbo; + bge_max_len_flags len_flags; for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) { if (bge_newbuf_jumbo(sc, i, NULL) == ENOBUFS) @@ -923,9 +1020,9 @@ sc->bge_jumbo = i - 1; rcb = &sc->bge_rdata->bge_info.bge_jumbo_rx_rcb; - rcbo = (struct bge_rcb_opaque *)rcb; - rcb->bge_flags = 0; - CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcbo->bge_reg2); + len_flags.bge_len_flags = rcb->bge_len_flags.bge_len_flags; + len_flags.s.bge_flags = 0; + CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, len_flags.bge_len_flags); CSR_WRITE_4(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bge_jumbo); @@ -1047,6 +1144,25 @@ struct bge_softc *sc; { int i; + static int clock_speeds_l[] = { + 28, + 34, + 41, + 56, + 67, + 86, + 98 + }; + static int clock_speeds_h[] = { + 39, + 45, + 52, + 61, + 72, + 90, + 103, + 198 + }; /* Set endianness before we access any non-PCI registers. */ #if BYTE_ORDER == BIG_ENDIAN @@ -1083,16 +1199,29 @@ BGE_MEMWIN_WRITE(sc, i, 0); /* Set up the PCI DMA control register. */ - if (pci_read_config(sc->bge_dev, BGE_PCI_PCISTATE, 4) & - BGE_PCISTATE_PCI_BUSMODE) { + i = pci_read_config(sc->bge_dev, BGE_PCI_PCISTATE, 4); + if (i & BGE_PCISTATE_PCI_BUSMODE) { /* Conventional PCI bus */ pci_write_config(sc->bge_dev, BGE_PCI_DMA_RW_CTL, BGE_PCI_READ_CMD|BGE_PCI_WRITE_CMD|0x3F000F, 4); + printf("bge%d: Conventional PCI Mode %dMHz, %d bits\n", + sc->bge_unit, + (i&BGE_PCISTATE_PCI_BUSSPEED) ? 33 : 66, + (i&BGE_PCISTATE_32BIT_BUS) ? 32 : 64); } else { /* PCI-X bus */ pci_write_config(sc->bge_dev, BGE_PCI_DMA_RW_CTL, BGE_PCI_READ_CMD|BGE_PCI_WRITE_CMD|0x1B000F, 4); - } + printf("bge%d: PCI-X Mode %dMHz, %d bits\n", + sc->bge_unit, + (i&BGE_PCISTATE_PCI_BUSSPEED) ? 66 : 133, + (i&BGE_PCISTATE_32BIT_BUS) ? 32 : 64); + } + i = pci_read_config(sc->bge_dev, BGE_PCI_CLKCTL, 4); + printf("bge%d: PCI Clock Measured: %d - %d MHz\n", + sc->bge_unit, + clock_speeds_l[i & BGE_PCICLOCKCTL_DETECTED_SPEED], + clock_speeds_h[i & BGE_PCICLOCKCTL_DETECTED_SPEED]); /* * Set up general mode register. @@ -1133,6 +1262,7 @@ struct bge_rcb *rcb; struct bge_rcb_opaque *rcbo; int i; + bge_max_len_flags len_flags; /* * Initialize the memory window pointer register so that @@ -1202,12 +1332,13 @@ rcb = &sc->bge_rdata->bge_info.bge_std_rx_rcb; BGE_HOSTADDR(rcb->bge_hostaddr) = vtophys(&sc->bge_rdata->bge_rx_std_ring); - rcb->bge_max_len = BGE_MAX_FRAMELEN; + len_flags.s.bge_max_len = BGE_MAX_FRAMELEN; + len_flags.s.bge_flags = 0; + rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags; if (sc->bge_extram) rcb->bge_nicaddr = BGE_EXT_STD_RX_RINGS; else rcb->bge_nicaddr = BGE_STD_RX_RINGS; - rcb->bge_flags = 0; rcbo = (struct bge_rcb_opaque *)rcb; CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_HI, rcbo->bge_reg0); CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_LO, rcbo->bge_reg1); @@ -1224,12 +1355,13 @@ rcb = &sc->bge_rdata->bge_info.bge_jumbo_rx_rcb; BGE_HOSTADDR(rcb->bge_hostaddr) = vtophys(&sc->bge_rdata->bge_rx_jumbo_ring); - rcb->bge_max_len = BGE_MAX_FRAMELEN; + len_flags.s.bge_max_len = BGE_MAX_FRAMELEN; + len_flags.s.bge_flags = BGE_RCB_FLAG_RING_DISABLED; + rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags; if (sc->bge_extram) rcb->bge_nicaddr = BGE_EXT_JUMBO_RX_RINGS; else rcb->bge_nicaddr = BGE_JUMBO_RX_RINGS; - rcb->bge_flags = BGE_RCB_FLAG_RING_DISABLED; rcbo = (struct bge_rcb_opaque *)rcb; CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_HADDR_HI, rcbo->bge_reg0); @@ -1239,7 +1371,9 @@ /* Set up dummy disabled mini ring RCB */ rcb = &sc->bge_rdata->bge_info.bge_mini_rx_rcb; - rcb->bge_flags = BGE_RCB_FLAG_RING_DISABLED; + len_flags.s.bge_max_len = 0; + len_flags.s.bge_flags = BGE_RCB_FLAG_RING_DISABLED; + rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags; rcbo = (struct bge_rcb_opaque *)rcb; CSR_WRITE_4(sc, BGE_RX_MINI_RCB_MAXLEN_FLAGS, rcbo->bge_reg2); @@ -1259,8 +1393,9 @@ rcb = (struct bge_rcb *)(sc->bge_vhandle + BGE_MEMWIN_START + BGE_SEND_RING_RCB); for (i = 0; i < BGE_TX_RINGS_EXTSSRAM_MAX; i++) { - rcb->bge_flags = BGE_RCB_FLAG_RING_DISABLED; - rcb->bge_max_len = 0; + len_flags.s.bge_max_len = 0; + len_flags.s.bge_flags = BGE_RCB_FLAG_RING_DISABLED; + rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags; rcb->bge_nicaddr = 0; rcb++; } @@ -1272,17 +1407,20 @@ BGE_HOSTADDR(rcb->bge_hostaddr) = vtophys(&sc->bge_rdata->bge_tx_ring); rcb->bge_nicaddr = BGE_NIC_TXRING_ADDR(0, BGE_TX_RING_CNT); - rcb->bge_max_len = BGE_TX_RING_CNT; - rcb->bge_flags = 0; + len_flags.s.bge_max_len = BGE_TX_RING_CNT; + len_flags.s.bge_flags = 0; + rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags; /* Disable all unused RX return rings */ rcb = (struct bge_rcb *)(sc->bge_vhandle + BGE_MEMWIN_START + BGE_RX_RETURN_RING_RCB); - for (i = 0; i < BGE_RX_RINGS_MAX; i++) { + rcb++; + for (i = 1; i < BGE_RX_RINGS_MAX; i++) { rcb->bge_hostaddr.bge_addr_hi = 0; rcb->bge_hostaddr.bge_addr_lo = 0; - rcb->bge_flags = BGE_RCB_FLAG_RING_DISABLED; - rcb->bge_max_len = BGE_RETURN_RING_CNT; + len_flags.s.bge_max_len = BGE_RETURN_RING_CNT; + len_flags.s.bge_flags = BGE_RCB_FLAG_RING_DISABLED; + rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags; rcb->bge_nicaddr = 0; CSR_WRITE_4(sc, BGE_MBX_RX_CONS0_LO + (i * (sizeof(u_int64_t))), 0); @@ -1306,8 +1444,9 @@ BGE_HOSTADDR(rcb->bge_hostaddr) = vtophys(&sc->bge_rdata->bge_rx_return_ring); rcb->bge_nicaddr = 0x00000000; - rcb->bge_max_len = BGE_RETURN_RING_CNT; - rcb->bge_flags = 0; + len_flags.s.bge_max_len = BGE_RETURN_RING_CNT; + len_flags.s.bge_flags = 0; + rcb->bge_len_flags.bge_len_flags = len_flags.bge_len_flags; /* Set random backoff seed for TX */ CSR_WRITE_4(sc, BGE_TX_RANDOM_BACKOFF, @@ -1363,13 +1502,11 @@ CSR_WRITE_4(sc, BGE_HCC_STATS_TICKS, sc->bge_stat_ticks); /* Set up address of statistics block */ - CSR_WRITE_4(sc, BGE_HCC_STATS_BASEADDR, BGE_STATS_BLOCK); CSR_WRITE_4(sc, BGE_HCC_STATS_ADDR_HI, 0); CSR_WRITE_4(sc, BGE_HCC_STATS_ADDR_LO, vtophys(&sc->bge_rdata->bge_info.bge_stats)); /* Set up address of status block */ - CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_BASEADDR, BGE_STATUS_BLOCK); CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_HI, 0); CSR_WRITE_4(sc, BGE_HCC_STATUSBLK_ADDR_LO, vtophys(&sc->bge_rdata->bge_status_block)); @@ -1498,11 +1635,12 @@ while(t->bge_name != NULL) { if ((pci_get_vendor(dev) == t->bge_vid) && (pci_get_device(dev) == t->bge_did)) { -#ifdef notdef - bge_vpd_read(sc); +#ifdef BGE_VPD + bge_vpd_read(sc, t->bge_name); device_set_desc(dev, sc->bge_vpd_prodname); -#endif +#else device_set_desc(dev, t->bge_name); +#endif return(0); } t++; @@ -1632,6 +1770,18 @@ */ printf("bge%d: Ethernet address: %6D\n", unit, sc->arpcom.ac_enaddr, ":"); + if (sc->bge_vpd_readonly) + printf("bge%d: PN: <%s> SN: <%s> EC: <%s> MN: <%s> RV: <%s>\n", + unit, + sc->bge_vpd_pn, + sc->bge_vpd_sn, + sc->bge_vpd_ec, + sc->bge_vpd_mn, + sc->bge_vpd_rv); + if (sc->bge_vpd_asset_tag) + printf("bge%d: asset-tag: %s\n", unit, sc->bge_vpd_asset_tag); + + dump_manufacturing_information(sc); /* Allocate the general information block and ring buffers. */ sc->bge_rdata = contigmalloc(sizeof(struct bge_ring_data), M_DEVBUF, @@ -1656,10 +1806,34 @@ } /* Set default tuneable values. */ + /* How often should we update the statistics in host memory? */ sc->bge_stat_ticks = BGE_TICKS_PER_SEC; - sc->bge_rx_coal_ticks = 150; - sc->bge_tx_coal_ticks = 150; - sc->bge_rx_max_coal_bds = 64; + /* The coalescing works as follows: for each of Rx|Tx, there + * are two tunables: ticks, and packets. The first one to trip + * will cause an interrupt. For exampple, if the ticks is set to + * 1us, an interrupt will be generated no more than 1us after + * a packet has come in. If the bds is set to 10, then the + * interrupt would be after 10 packets had been received. + * If ticks=1 and bds=10, then the interrupt will come in + * min(1us, 10packets time), likely 1us. + * Tuning these to larger values reduces interrupts at the + * expense of latency to interactive applications. If you + * are serving files, make these large. If you are running + * telnet sessions, make them small. + * + * The settings below, 500us means a max interrupt rate + * of 2000/s due to the ticks elapsing, and 120 means + * a peak interrupt rate of ~2000/s due to avg packets (512) arriving + * (for min sized packets this would be 870, for max + * sized packets it would be 41: 1Gps / ((8*size)+96)) + */ + /* RX Interrupt no more than every 500 us */ + sc->bge_rx_coal_ticks = 512; + /* TX Interrupt no more than every 500 us */ + sc->bge_tx_coal_ticks = 512; + /* RX Interrupt no more than every 120 packets */ + sc->bge_rx_max_coal_bds = 128; + /* TX Interrupt no more than every 120 packets */ sc->bge_tx_max_coal_bds = 128; /* Set up ifnet structure */ @@ -1806,6 +1980,9 @@ if (sc->bge_vpd_readonly != NULL) free(sc->bge_vpd_readonly, M_DEVBUF); + if (sc->bge_vpd_readwrite != NULL) + free(sc->bge_vpd_readwrite, M_DEVBUF); + if (sc->bge_intrhand != NULL) bus_teardown_intr(dev, sc->bge_irq, sc->bge_intrhand); @@ -2082,63 +2259,74 @@ #ifdef notdef /* Avoid this for now -- checking this register is expensive. */ /* Make sure this is really our interrupt. */ - if (!(CSR_READ_4(sc, BGE_MISC_LOCAL_CTL) & BGE_MLC_INTR_STATE)) + if ((CSR_READ_4(sc, BGE_MISC_LOCAL_CTL) & BGE_MLC_INTR_STATE)) { return; + } #endif - /* Ack interrupt and stop others from occuring. */ - CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1); + while (sc->bge_rdata->bge_status_block.bge_status & + BGE_STATFLAG_UPDATED) { - /* - * Process link state changes. - * Grrr. The link status word in the status block does - * not work correctly on the BCM5700 rev AX and BX chips, - * according to all avaibable information. Hence, we have - * to enable MII interrupts in order to properly obtain - * async link changes. Unfortunately, this also means that - * we have to read the MAC status register to detect link - * changes, thereby adding an additional register access to - * the interrupt handler. - */ - - if (sc->bge_asicrev == BGE_ASICREV_BCM5700) { - u_int32_t status; - - status = CSR_READ_4(sc, BGE_MAC_STS); - if (status & BGE_MACSTAT_MI_INTERRUPT) { - sc->bge_link = 0; - untimeout(bge_tick, sc, sc->bge_stat_ch); - bge_tick(sc); - /* Clear the interrupt */ - CSR_WRITE_4(sc, BGE_MAC_EVT_ENB, - BGE_EVTENB_MI_INTERRUPT); - bge_miibus_readreg(sc->bge_dev, 1, BRGPHY_MII_ISR); - bge_miibus_writereg(sc->bge_dev, 1, BRGPHY_MII_IMR, - BRGPHY_INTRS); - } - } else { - if (sc->bge_rdata->bge_status_block.bge_status & - BGE_STATFLAG_LINKSTATE_CHANGED) { - sc->bge_link = 0; - untimeout(bge_tick, sc, sc->bge_stat_ch); - bge_tick(sc); - /* Clear the interrupt */ - CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED| - BGE_MACSTAT_CFG_CHANGED); - } - } + /* Ack interrupt and stop others from occuring. */ + CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1); - if (ifp->if_flags & IFF_RUNNING) { - /* Check RX return ring producer/consumer */ - bge_rxeof(sc); + /* Now clear the 'updated' bit */ + sc->bge_rdata->bge_status_block.bge_status &= ~BGE_STATFLAG_UPDATED; - /* Check TX ring producer/consumer */ - bge_txeof(sc); + /* + * Process link state changes. + * Grrr. The link status word in the status block does + * not work correctly on the BCM5700 rev AX and BX chips, + * according to all avaibable information. Hence, we have + * to enable MII interrupts in order to properly obtain + * async link changes. Unfortunately, this also means that + * we have to read the MAC status register to detect link + * changes, thereby adding an additional register access to + * the interrupt handler. + */ + + if (sc->bge_asicrev == BGE_ASICREV_BCM5700) { + u_int32_t status; + + status = CSR_READ_4(sc, BGE_MAC_STS); + if (status & BGE_MACSTAT_MI_INTERRUPT) { + sc->bge_link = 0; + untimeout(bge_tick, sc, sc->bge_stat_ch); + bge_tick(sc); + /* Clear the interrupt */ + CSR_WRITE_4(sc, BGE_MAC_EVT_ENB, + BGE_EVTENB_MI_INTERRUPT); + bge_miibus_readreg(sc->bge_dev, 1, BRGPHY_MII_ISR); + bge_miibus_writereg(sc->bge_dev, 1, BRGPHY_MII_IMR, + BRGPHY_INTRS); + } + } else { + if (sc->bge_rdata->bge_status_block.bge_status & + BGE_STATFLAG_LINKSTATE_CHANGED) { + sc->bge_link = 0; + untimeout(bge_tick, sc, sc->bge_stat_ch); + bge_tick(sc); + /* Clear the interrupt */ + CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED| + BGE_MACSTAT_CFG_CHANGED); + } + } + + + if (ifp->if_flags & IFF_RUNNING) { + /* Check RX return ring producer/consumer */ + bge_rxeof(sc); + + /* Check TX ring producer/consumer */ + bge_txeof(sc); + } + + bge_handle_events(sc); + + /* Re-enable interrupts. */ + CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0); + /* Force posted writes to complete */ + CSR_READ_4(sc, BGE_MBX_IRQ0_LO); } - - bge_handle_events(sc); - - /* Re-enable interrupts. */ - CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0); if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) bge_start(ifp); Index: if_bgereg.h =================================================================== RCS file: /cvs/src/sys/dev/bge/if_bgereg.h,v retrieving revision 1.1.2.7 diff -U3 -r1.1.2.7 if_bgereg.h --- if_bgereg.h 2 Nov 2002 18:17:55 -0000 1.1.2.7 +++ if_bgereg.h 21 Nov 2002 20:20:37 -0000 @@ -278,7 +278,26 @@ * unless the CLOCKCTL_RW bit of the PCI Misc. Host Control * register is set. */ -#define BGE_PCICLOCKCTL_DETECTED_SPEED 0x0000000F +#define BGE_PCICLOCKCTL_DETECTED_SPEED 0x00000007 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_28_1 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_34_3 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_40_6 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_46_8 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_56_2 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_67_1 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_85_9 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_L_98_4 + +#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_39_1 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_45_3 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_51_6 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_60_9 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_71_9 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_90_5 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_103 +#define BGE_PCICLOCKCTL_DETECTED_SPEED_H_198 + + #define BGE_PCICLOCKCTL_M66EN 0x00000080 #define BGE_PCICLOCKCTL_LOWPWR_CLKMODE 0x00000200 #define BGE_PCICLOCKCTL_RXCPU_CLK_DIS 0x00000400 @@ -1083,6 +1102,8 @@ #define BGE_HCCMODE_COAL_NOW 0x00000008 #define BGE_HCCMODE_MSI_BITS 0x0x000070 #define BGE_HCCMODE_STATBLK_SIZE 0x00000180 +#define BGE_HCCMODE_CLEAR_TX (1<<10) +#define BGE_HCCMODE_CLEAR_RX (1<<9) #define BGE_STATBLKSZ_FULL 0x00000000 #define BGE_STATBLKSZ_64BYTE 0x00000080 @@ -1678,11 +1699,23 @@ } bge_hostaddr; #define BGE_HOSTADDR(x) x.bge_addr_lo +typedef union { + struct { +#if BYTE_ORDER == BIG_ENDIAN + u_int16_t bge_max_len; + u_int16_t bge_flags; +#else + u_int16_t bge_flags; + u_int16_t bge_max_len; +#endif + } s; + u_int32_t bge_len_flags; +} bge_max_len_flags; + /* Ring control block structure */ struct bge_rcb { bge_hostaddr bge_hostaddr; - u_int16_t bge_flags; - u_int16_t bge_max_len; + bge_max_len_flags bge_len_flags; u_int32_t bge_nicaddr; }; @@ -2026,10 +2059,43 @@ u_int8_t vk_len; }; +/* + * VPD (PCI 2.2) is a standard to allow describing a product. + * + * Here is an example VPD (from a 3COM 3C996) + * 82 18 00 33 43 6f 6d 20 - 47 69 67 61 62 69 74 20--...3Com Gigabit + * 53 65 72 76 65 72 20 4e - 49 43 00 90 62 00 50 4e--Server NIC..b.PN + * 08 33 43 39 39 36 42 2d - 54 45 43 09 30 31 2d 30--.3C996B-TEC.01-0 + * 32 37 38 72 36 53 4e 0a - 48 52 54 52 45 46 30 38--278r6SN.HRTREF08 + * 37 43 4d 4e 04 31 30 42 - 37 52 56 34 42 00 00 00--7CMN.10B7RV4B... + * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................ + * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................ + * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................ + * 91 7c 00 59 41 0b 58 59 - 5a 30 31 32 33 34 35 36--.|.YA.XYZ0123456 + * 37 52 57 6b 00 00 00 00 - 00 00 00 00 00 00 00 00--7RWk............ + * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................ + * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................ + * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................ + * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................ + * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00--................ + * 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 78--...............x + */ #define VPD_RES_ID 0x82 /* ID string */ #define VPD_RES_READ 0x90 /* start of read only area */ -#define VPD_RES_WRITE 0x81 /* start of read/write area */ +#define VPD_RES_WRITE 0x91 /* start of read/write area */ #define VPD_RES_END 0x78 /* end tag */ +/* + * Within the VPD-R, we have subtags as <TAG><LEN>, the tags + * are two-char, the len is 1-char +*/ +#define VPD_PN "PN" /* Adapter Part Number */ +#define VPD_EC "EC" /* Adapter Engineering Level */ +#define VPD_MN "MN" /* Manufacture ID */ +#define VPD_SN "SN" /* Serial Number */ +#define VPD_CP "CP" /* Extended Capability */ +#define VPD_RV "RV" /* Checksum and Reserved */ +#define VPD_YA "YA" /* Asset Tag Identifier */ +#define VPD_RW "RW" /* Remaining Read / Write Area */ /* @@ -2059,9 +2125,9 @@ * allocated for the standard, mini and jumbo receive rings. */ -#define BGE_SSLOTS 256 -#define BGE_MSLOTS 256 -#define BGE_JSLOTS 384 +#define BGE_SSLOTS 512 +#define BGE_MSLOTS 0 /* Not used in this driver, only avail on bcm5700*/ +#define BGE_JSLOTS 32 #define BGE_JRAWLEN (BGE_JUMBO_FRAMELEN + ETHER_ALIGN + sizeof(u_int64_t)) #define BGE_JLEN (BGE_JRAWLEN + (sizeof(u_int64_t) - \ @@ -2165,6 +2231,13 @@ struct callout_handle bge_stat_ch; char *bge_vpd_prodname; char *bge_vpd_readonly; + char *bge_vpd_pn; /* pointer within the readonly*/ + char *bge_vpd_sn; /* pointer within the readonly*/ + char *bge_vpd_ec; /* pointer within the readonly*/ + char *bge_vpd_mn; /* pointer within the readonly*/ + char *bge_vpd_rv; /* pointer within the readonly*/ + char *bge_vpd_readwrite; + char *bge_vpd_asset_tag; /* pointer within the rw*/ }; #ifdef __alpha__ --don (don@sandvine.com www.sandvine.com) To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-net" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?FE045D4D9F7AED4CBFF1B3B813C8533701022FFD>