Index: if_bce.c =================================================================== RCS file: /home/ncvs/src/sys/dev/bce/if_bce.c,v retrieving revision 1.2.4.2 diff -u -r1.2.4.2 if_bce.c --- if_bce.c 13 Apr 2006 22:42:07 -0000 1.2.4.2 +++ if_bce.c 3 Dec 2006 06:07:10 -0000 @@ -29,7 +29,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/dev/bce/if_bce.c,v 1.2.4.2 2006/04/13 22:42:07 ps Exp $"); +__FBSDID("$FreeBSD: src/sys/dev/bce/if_bce.c,v 1.2.2.6.2.1 2006/11/28 17:14:07 scottl Exp $"); /* * The following controllers are supported by this driver: @@ -53,7 +53,7 @@ /****************************************************************************/ /* BCE Driver Version */ /****************************************************************************/ -char bce_driver_version[] = "v0.9.5"; +char bce_driver_version[] = "v0.9.6"; /****************************************************************************/ @@ -276,7 +276,6 @@ /* */ /****************************************************************************/ static void bce_dma_map_addr (void *, bus_dma_segment_t *, int, int); -static void bce_dma_map_tx_desc (void *, bus_dma_segment_t *, int, bus_size_t, int); static int bce_dma_alloc (device_t); static void bce_dma_free (struct bce_softc *); static void bce_release_resources (struct bce_softc *); @@ -300,7 +299,7 @@ static void bce_free_rx_chain (struct bce_softc *); static void bce_free_tx_chain (struct bce_softc *); -static int bce_tx_encap (struct bce_softc *, struct mbuf *, u16 *, u16 *, u32 *); +static int bce_tx_encap (struct bce_softc *, struct mbuf **); static void bce_start_locked (struct ifnet *); static void bce_start (struct ifnet *); static int bce_ioctl (struct ifnet *, u_long, caddr_t); @@ -309,6 +308,7 @@ static void bce_ifmedia_sts (struct ifnet *, struct ifmediareq *); static void bce_init_locked (struct bce_softc *); static void bce_init (void *); +static void bce_mgmt_init_locked(struct bce_softc *sc); static void bce_init_context (struct bce_softc *); static void bce_get_mac_addr (struct bce_softc *); @@ -467,10 +467,10 @@ /* Allocate PCI memory resources. */ rid = PCIR_BAR(0); sc->bce_res = bus_alloc_resource_any( - dev, /* dev */ - SYS_RES_MEMORY, /* type */ - &rid, /* rid */ - RF_ACTIVE | PCI_RF_DENSE); /* flags */ + dev, /* dev */ + SYS_RES_MEMORY, /* type */ + &rid, /* rid */ + RF_ACTIVE | PCI_RF_DENSE); /* flags */ if (sc->bce_res == NULL) { BCE_PRINTF(sc, "%s(%d): PCI memory allocation failed\n", @@ -781,6 +781,11 @@ /* Add the supported sysctls to the kernel. */ bce_add_sysctls(sc); + /* Get the firmware running so IPMI still works */ + BCE_LOCK(sc); + bce_mgmt_init_locked(sc); + BCE_UNLOCK(sc); + goto bce_attach_exit; bce_attach_fail: @@ -1352,7 +1357,6 @@ REG_WR(sc, BCE_NVM_COMMAND, cmd); /* Wait for completion. */ - */ for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { u32 val; @@ -2126,135 +2130,24 @@ static void bce_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - struct bce_dmamap_arg *map_arg = arg; - struct bce_softc *sc = map_arg->sc; + bus_addr_t *busaddr = arg; /* Simulate a mapping failure. */ DBRUNIF(DB_RANDOMTRUE(bce_debug_dma_map_addr_failure), - BCE_PRINTF(sc, "%s(%d): Simulating DMA mapping error.\n", + printf("bce: %s(%d): Simulating DMA mapping error.\n", __FILE__, __LINE__); error = ENOMEM); /* Check for an error and signal the caller that an error occurred. */ - if (error || (nseg > map_arg->maxsegs)) { - BCE_PRINTF(sc, "%s(%d): DMA mapping error! error = %d, " - "nseg = %d, maxsegs = %d\n", - __FILE__, __LINE__, error, nseg, map_arg->maxsegs); - map_arg->maxsegs = 0; - goto bce_dma_map_addr_exit; - } - - map_arg->busaddr = segs->ds_addr; - -bce_dma_map_addr_exit: - return; -} - - -/****************************************************************************/ -/* Map TX buffers into TX buffer descriptors. */ -/* */ -/* Given a series of DMA memory containting an outgoing frame, map the */ -/* segments into the tx_bd structure used by the hardware. */ -/* */ -/* Returns: */ -/* Nothing. */ -/****************************************************************************/ -static void -bce_dma_map_tx_desc(void *arg, bus_dma_segment_t *segs, - int nseg, bus_size_t mapsize, int error) -{ - struct bce_dmamap_arg *map_arg; - struct bce_softc *sc; - struct tx_bd *txbd = NULL; - int i = 0; - u16 prod, chain_prod; - u32 prod_bseq; -#ifdef BCE_DEBUG - u16 debug_prod; -#endif - - map_arg = arg; - sc = map_arg->sc; - if (error) { - DBPRINT(sc, BCE_WARN, "%s(): Called with error = %d\n", - __FUNCTION__, error); - return; - } - - /* Signal error to caller if there's too many segments */ - if (nseg > map_arg->maxsegs) { - DBPRINT(sc, BCE_WARN, - "%s(): Mapped TX descriptors: max segs = %d, " - "actual segs = %d\n", - __FUNCTION__, map_arg->maxsegs, nseg); - - map_arg->maxsegs = 0; + printf("bce %s(%d): DMA mapping error! error = %d, " + "nseg = %d\n", __FILE__, __LINE__, error, nseg); + *busaddr = 0; return; } - /* prod points to an empty tx_bd at this point. */ - prod = map_arg->prod; - chain_prod = map_arg->chain_prod; - prod_bseq = map_arg->prod_bseq; - -#ifdef BCE_DEBUG - debug_prod = chain_prod; -#endif - - DBPRINT(sc, BCE_INFO_SEND, - "%s(): Start: prod = 0x%04X, chain_prod = %04X, " - "prod_bseq = 0x%08X\n", - __FUNCTION__, prod, chain_prod, prod_bseq); - - /* - * Cycle through each mbuf segment that makes up - * the outgoing frame, gathering the mapping info - * for that segment and creating a tx_bd to for - * the mbuf. - */ - - txbd = &map_arg->tx_chain[TX_PAGE(chain_prod)][TX_IDX(chain_prod)]; - - /* Setup the first tx_bd for the first segment. */ - txbd->tx_bd_haddr_lo = htole32(BCE_ADDR_LO(segs[i].ds_addr)); - txbd->tx_bd_haddr_hi = htole32(BCE_ADDR_HI(segs[i].ds_addr)); - txbd->tx_bd_mss_nbytes = htole16(segs[i].ds_len); - txbd->tx_bd_vlan_tag_flags = htole16(map_arg->tx_flags | - TX_BD_FLAGS_START); - prod_bseq += segs[i].ds_len; - - /* Setup any remaing segments. */ - for (i = 1; i < nseg; i++) { - prod = NEXT_TX_BD(prod); - chain_prod = TX_CHAIN_IDX(prod); - - txbd = &map_arg->tx_chain[TX_PAGE(chain_prod)][TX_IDX(chain_prod)]; - - txbd->tx_bd_haddr_lo = htole32(BCE_ADDR_LO(segs[i].ds_addr)); - txbd->tx_bd_haddr_hi = htole32(BCE_ADDR_HI(segs[i].ds_addr)); - txbd->tx_bd_mss_nbytes = htole16(segs[i].ds_len); - txbd->tx_bd_vlan_tag_flags = htole16(map_arg->tx_flags); - - prod_bseq += segs[i].ds_len; - } - - /* Set the END flag on the last TX buffer descriptor. */ - txbd->tx_bd_vlan_tag_flags |= htole16(TX_BD_FLAGS_END); - - DBRUN(BCE_INFO_SEND, bce_dump_tx_chain(sc, debug_prod, nseg)); - - DBPRINT(sc, BCE_INFO_SEND, - "%s(): End: prod = 0x%04X, chain_prod = %04X, " - "prod_bseq = 0x%08X\n", - __FUNCTION__, prod, chain_prod, prod_bseq); - - /* prod points to the last tx_bd at this point. */ - map_arg->maxsegs = nseg; - map_arg->prod = prod; - map_arg->chain_prod = chain_prod; - map_arg->prod_bseq = prod_bseq; + *busaddr = segs->ds_addr; + return; } @@ -2272,28 +2165,28 @@ { struct bce_softc *sc; int i, error, rc = 0; - struct bce_dmamap_arg map_arg; + bus_addr_t busaddr; sc = device_get_softc(dev); - + DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__); /* * Allocate the parent bus DMA tag appropriate for PCI. */ if (bus_dma_tag_create(NULL, /* parent */ - BCE_DMA_ALIGN, /* alignment */ - BCE_DMA_BOUNDARY, /* boundary */ - sc->max_bus_addr, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, /* filterfunc */ - NULL, /* filterarg */ - MAXBSIZE, /* maxsize */ - BUS_SPACE_UNRESTRICTED, /* nsegments */ - BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - 0, /* flags */ - NULL, /* locfunc */ - NULL, /* lockarg */ + 1, /* alignment */ + BCE_DMA_BOUNDARY, /* boundary */ + sc->max_bus_addr, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, /* filterfunc */ + NULL, /* filterarg */ + MAXBSIZE, /* maxsize */ + BUS_SPACE_UNRESTRICTED, /* nsegments */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ + 0, /* flags */ + NULL, /* locfunc */ + NULL, /* lockarg */ &sc->parent_tag)) { BCE_PRINTF(sc, "%s(%d): Could not allocate parent DMA tag!\n", __FILE__, __LINE__); @@ -2307,19 +2200,19 @@ * address of the block. */ if (bus_dma_tag_create( - sc->parent_tag, /* parent */ + sc->parent_tag, /* parent */ BCE_DMA_ALIGN, /* alignment */ BCE_DMA_BOUNDARY, /* boundary */ sc->max_bus_addr, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ - NULL, /* filterfunc */ - NULL, /* filterarg */ + NULL, /* filterfunc */ + NULL, /* filterarg */ BCE_STATUS_BLK_SZ, /* maxsize */ - 1, /* nsegments */ + 1, /* nsegments */ BCE_STATUS_BLK_SZ, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockarg */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ &sc->status_tag)) { BCE_PRINTF(sc, "%s(%d): Could not allocate status block DMA tag!\n", __FILE__, __LINE__); @@ -2328,9 +2221,9 @@ } if(bus_dmamem_alloc( - sc->status_tag, /* dmat */ + sc->status_tag, /* dmat */ (void **)&sc->status_block, /* vaddr */ - BUS_DMA_NOWAIT, /* flags */ + BUS_DMA_NOWAIT, /* flags */ &sc->status_map)) { BCE_PRINTF(sc, "%s(%d): Could not allocate status block DMA memory!\n", __FILE__, __LINE__); @@ -2340,26 +2233,23 @@ bzero((char *)sc->status_block, BCE_STATUS_BLK_SZ); - map_arg.sc = sc; - map_arg.maxsegs = 1; - error = bus_dmamap_load( - sc->status_tag, /* dmat */ + sc->status_tag, /* dmat */ sc->status_map, /* map */ sc->status_block, /* buf */ BCE_STATUS_BLK_SZ, /* buflen */ bce_dma_map_addr, /* callback */ - &map_arg, /* callbackarg */ + &busaddr, /* callbackarg */ BUS_DMA_NOWAIT); /* flags */ - if(error || (map_arg.maxsegs == 0)) { + if (error) { BCE_PRINTF(sc, "%s(%d): Could not map status block DMA memory!\n", __FILE__, __LINE__); rc = ENOMEM; goto bce_dma_alloc_exit; } - sc->status_block_paddr = map_arg.busaddr; + sc->status_block_paddr = busaddr; /* DRC - Fix for 64 bit addresses. */ DBPRINT(sc, BCE_INFO, "status_block_paddr = 0x%08X\n", (u32) sc->status_block_paddr); @@ -2370,19 +2260,19 @@ * address of the block. */ if (bus_dma_tag_create( - sc->parent_tag, /* parent */ + sc->parent_tag, /* parent */ BCE_DMA_ALIGN, /* alignment */ BCE_DMA_BOUNDARY, /* boundary */ sc->max_bus_addr, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ - NULL, /* filterfunc */ - NULL, /* filterarg */ + NULL, /* filterfunc */ + NULL, /* filterarg */ BCE_STATS_BLK_SZ, /* maxsize */ - 1, /* nsegments */ + 1, /* nsegments */ BCE_STATS_BLK_SZ, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockarg */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ &sc->stats_tag)) { BCE_PRINTF(sc, "%s(%d): Could not allocate statistics block DMA tag!\n", __FILE__, __LINE__); @@ -2391,9 +2281,9 @@ } if (bus_dmamem_alloc( - sc->stats_tag, /* dmat */ + sc->stats_tag, /* dmat */ (void **)&sc->stats_block, /* vaddr */ - BUS_DMA_NOWAIT, /* flags */ + BUS_DMA_NOWAIT, /* flags */ &sc->stats_map)) { BCE_PRINTF(sc, "%s(%d): Could not allocate statistics block DMA memory!\n", __FILE__, __LINE__); @@ -2403,26 +2293,23 @@ bzero((char *)sc->stats_block, BCE_STATS_BLK_SZ); - map_arg.sc = sc; - map_arg.maxsegs = 1; - error = bus_dmamap_load( - sc->stats_tag, /* dmat */ + sc->stats_tag, /* dmat */ sc->stats_map, /* map */ sc->stats_block, /* buf */ BCE_STATS_BLK_SZ, /* buflen */ bce_dma_map_addr, /* callback */ - &map_arg, /* callbackarg */ + &busaddr, /* callbackarg */ BUS_DMA_NOWAIT); /* flags */ - if(error || (map_arg.maxsegs == 0)) { + if(error) { BCE_PRINTF(sc, "%s(%d): Could not map statistics block DMA memory!\n", __FILE__, __LINE__); rc = ENOMEM; goto bce_dma_alloc_exit; } - sc->stats_block_paddr = map_arg.busaddr; + sc->stats_block_paddr = busaddr; /* DRC - Fix for 64 bit address. */ DBPRINT(sc,BCE_INFO, "stats_block_paddr = 0x%08X\n", (u32) sc->stats_block_paddr); @@ -2433,19 +2320,19 @@ * physical address of the block. */ if(bus_dma_tag_create( - sc->parent_tag, /* parent */ - BCM_PAGE_SIZE, /* alignment */ - BCE_DMA_BOUNDARY, /* boundary */ - sc->max_bus_addr, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, /* filterfunc */ - NULL, /* filterarg */ - BCE_TX_CHAIN_PAGE_SZ, /* maxsize */ - 1, /* nsegments */ - BCE_TX_CHAIN_PAGE_SZ, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockarg */ + sc->parent_tag, /* parent */ + BCM_PAGE_SIZE, /* alignment */ + BCE_DMA_BOUNDARY, /* boundary */ + sc->max_bus_addr, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, /* filterfunc */ + NULL, /* filterarg */ + BCE_TX_CHAIN_PAGE_SZ, /* maxsize */ + 1, /* nsegments */ + BCE_TX_CHAIN_PAGE_SZ, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ &sc->tx_bd_chain_tag)) { BCE_PRINTF(sc, "%s(%d): Could not allocate TX descriptor chain DMA tag!\n", __FILE__, __LINE__); @@ -2456,9 +2343,9 @@ for (i = 0; i < TX_PAGES; i++) { if(bus_dmamem_alloc( - sc->tx_bd_chain_tag, /* tag */ + sc->tx_bd_chain_tag, /* tag */ (void **)&sc->tx_bd_chain[i], /* vaddr */ - BUS_DMA_NOWAIT, /* flags */ + BUS_DMA_NOWAIT, /* flags */ &sc->tx_bd_chain_map[i])) { BCE_PRINTF(sc, "%s(%d): Could not allocate TX descriptor " "chain DMA memory!\n", __FILE__, __LINE__); @@ -2466,26 +2353,23 @@ goto bce_dma_alloc_exit; } - map_arg.maxsegs = 1; - map_arg.sc = sc; - error = bus_dmamap_load( - sc->tx_bd_chain_tag, /* dmat */ - sc->tx_bd_chain_map[i], /* map */ - sc->tx_bd_chain[i], /* buf */ - BCE_TX_CHAIN_PAGE_SZ, /* buflen */ - bce_dma_map_addr, /* callback */ - &map_arg, /* callbackarg */ - BUS_DMA_NOWAIT); /* flags */ + sc->tx_bd_chain_tag, /* dmat */ + sc->tx_bd_chain_map[i], /* map */ + sc->tx_bd_chain[i], /* buf */ + BCE_TX_CHAIN_PAGE_SZ, /* buflen */ + bce_dma_map_addr, /* callback */ + &busaddr, /* callbackarg */ + BUS_DMA_NOWAIT); /* flags */ - if(error || (map_arg.maxsegs == 0)) { + if (error) { BCE_PRINTF(sc, "%s(%d): Could not map TX descriptor chain DMA memory!\n", __FILE__, __LINE__); rc = ENOMEM; goto bce_dma_alloc_exit; } - sc->tx_bd_chain_paddr[i] = map_arg.busaddr; + sc->tx_bd_chain_paddr[i] = busaddr; /* DRC - Fix for 64 bit systems. */ DBPRINT(sc, BCE_INFO, "tx_bd_chain_paddr[%d] = 0x%08X\n", i, (u32) sc->tx_bd_chain_paddr[i]); @@ -2494,19 +2378,19 @@ /* Create a DMA tag for TX mbufs. */ if (bus_dma_tag_create( sc->parent_tag, /* parent */ - BCE_DMA_ALIGN, /* alignment */ - BCE_DMA_BOUNDARY, /* boundary */ + 1, /* alignment */ + BCE_DMA_BOUNDARY, /* boundary */ sc->max_bus_addr, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ - NULL, /* filterfunc */ - NULL, /* filterarg */ + NULL, /* filterfunc */ + NULL, /* filterarg */ MCLBYTES * BCE_MAX_SEGMENTS, /* maxsize */ BCE_MAX_SEGMENTS, /* nsegments */ - MCLBYTES, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockarg */ - &sc->tx_mbuf_tag)) { + MCLBYTES, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ + &sc->tx_mbuf_tag)) { BCE_PRINTF(sc, "%s(%d): Could not allocate TX mbuf DMA tag!\n", __FILE__, __LINE__); rc = ENOMEM; @@ -2531,18 +2415,18 @@ */ if (bus_dma_tag_create( sc->parent_tag, /* parent */ - BCM_PAGE_SIZE, /* alignment */ - BCE_DMA_BOUNDARY, /* boundary */ + BCM_PAGE_SIZE, /* alignment */ + BCE_DMA_BOUNDARY, /* boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ sc->max_bus_addr, /* lowaddr */ - NULL, /* filter */ - NULL, /* filterarg */ - BCE_RX_CHAIN_PAGE_SZ, /* maxsize */ - 1, /* nsegments */ - BCE_RX_CHAIN_PAGE_SZ, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockarg */ + NULL, /* filter */ + NULL, /* filterarg */ + BCE_RX_CHAIN_PAGE_SZ, /* maxsize */ + 1, /* nsegments */ + BCE_RX_CHAIN_PAGE_SZ, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ &sc->rx_bd_chain_tag)) { BCE_PRINTF(sc, "%s(%d): Could not allocate RX descriptor chain DMA tag!\n", __FILE__, __LINE__); @@ -2553,9 +2437,9 @@ for (i = 0; i < RX_PAGES; i++) { if (bus_dmamem_alloc( - sc->rx_bd_chain_tag, /* tag */ + sc->rx_bd_chain_tag, /* tag */ (void **)&sc->rx_bd_chain[i], /* vaddr */ - BUS_DMA_NOWAIT, /* flags */ + BUS_DMA_NOWAIT, /* flags */ &sc->rx_bd_chain_map[i])) { BCE_PRINTF(sc, "%s(%d): Could not allocate RX descriptor chain " "DMA memory!\n", __FILE__, __LINE__); @@ -2565,26 +2449,23 @@ bzero((char *)sc->rx_bd_chain[i], BCE_RX_CHAIN_PAGE_SZ); - map_arg.maxsegs = 1; - map_arg.sc = sc; - error = bus_dmamap_load( - sc->rx_bd_chain_tag, /* dmat */ + sc->rx_bd_chain_tag, /* dmat */ sc->rx_bd_chain_map[i], /* map */ - sc->rx_bd_chain[i], /* buf */ + sc->rx_bd_chain[i], /* buf */ BCE_RX_CHAIN_PAGE_SZ, /* buflen */ - bce_dma_map_addr, /* callback */ - &map_arg, /* callbackarg */ - BUS_DMA_NOWAIT); /* flags */ + bce_dma_map_addr, /* callback */ + &busaddr, /* callbackarg */ + BUS_DMA_NOWAIT); /* flags */ - if(error || (map_arg.maxsegs == 0)) { + if (error) { BCE_PRINTF(sc, "%s(%d): Could not map RX descriptor chain DMA memory!\n", __FILE__, __LINE__); rc = ENOMEM; goto bce_dma_alloc_exit; } - sc->rx_bd_chain_paddr[i] = map_arg.busaddr; + sc->rx_bd_chain_paddr[i] = busaddr; /* DRC - Fix for 64 bit systems. */ DBPRINT(sc, BCE_INFO, "rx_bd_chain_paddr[%d] = 0x%08X\n", i, (u32) sc->rx_bd_chain_paddr[i]); @@ -2594,19 +2475,19 @@ * Create a DMA tag for RX mbufs. */ if (bus_dma_tag_create( - sc->parent_tag, /* parent */ - BCE_DMA_ALIGN, /* alignment */ - BCE_DMA_BOUNDARY, /* boundary */ - sc->max_bus_addr, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, /* filterfunc */ - NULL, /* filterarg */ - MJUM9BYTES, /* maxsize */ - BCE_MAX_SEGMENTS, /* nsegments */ - MJUM9BYTES, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockarg */ + sc->parent_tag, /* parent */ + 1, /* alignment */ + BCE_DMA_BOUNDARY, /* boundary */ + sc->max_bus_addr, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, /* filterfunc */ + NULL, /* filterarg */ + MJUM9BYTES, /* maxsize */ + BCE_MAX_SEGMENTS, /* nsegments */ + MJUM9BYTES, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockarg */ &sc->rx_mbuf_tag)) { BCE_PRINTF(sc, "%s(%d): Could not allocate RX mbuf DMA tag!\n", __FILE__, __LINE__); @@ -3242,6 +3123,7 @@ DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__); + bce_mgmt_init_locked(sc); } @@ -4372,7 +4254,7 @@ if (sc->tx_mbuf_ptr[sw_tx_chain_cons] != NULL) { /* Validate that this is the last tx_bd. */ - DBRUNIF((!(txbd->tx_bd_vlan_tag_flags & TX_BD_FLAGS_END)), + DBRUNIF((!(txbd->tx_bd_flags & TX_BD_FLAGS_END)), BCE_PRINTF(sc, "%s(%d): tx_bd END flag not set but " "txmbuf == NULL!\n", __FILE__, __LINE__); bce_breakpoint(sc)); @@ -4571,6 +4453,43 @@ return; } +static void +bce_mgmt_init_locked(struct bce_softc *sc) +{ + u32 val; + struct ifnet *ifp; + + DBPRINT(sc, BCE_VERBOSE_RESET, "Entering %s()\n", __FUNCTION__); + + BCE_LOCK_ASSERT(sc); + + ifp = sc->bce_ifp; + + /* Check if the driver is still running and bail out if it is. */ + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + goto bce_mgmt_init_locked_exit; + + /* Initialize the on-boards CPUs */ + bce_init_cpus(sc); + + val = (BCM_PAGE_BITS - 8) << 24; + REG_WR(sc, BCE_RV2P_CONFIG, val); + + /* Enable all critical blocks in the MAC. */ + REG_WR(sc, BCE_MISC_ENABLE_SET_BITS, + BCE_MISC_ENABLE_SET_BITS_RX_V2P_ENABLE | + BCE_MISC_ENABLE_SET_BITS_RX_DMA_ENABLE | + BCE_MISC_ENABLE_SET_BITS_COMPLETION_ENABLE); + REG_RD(sc, BCE_MISC_ENABLE_SET_BITS); + DELAY(20); + + bce_ifmedia_upd(ifp); +bce_mgmt_init_locked_exit: + DBPRINT(sc, BCE_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__); + + return; +} + /****************************************************************************/ /* Handles controller initialization when called from an unlocked routine. */ @@ -4597,84 +4516,160 @@ /* 0 for success, positive value for failure. */ /****************************************************************************/ static int -bce_tx_encap(struct bce_softc *sc, struct mbuf *m_head, u16 *prod, - u16 *chain_prod, u32 *prod_bseq) +bce_tx_encap(struct bce_softc *sc, struct mbuf **m_head) { - u32 vlan_tag_flags = 0; - struct m_tag *mtag; - struct bce_dmamap_arg map_arg; + bus_dma_segment_t segs[BCE_MAX_SEGMENTS]; bus_dmamap_t map; - int i, error, rc = 0; + struct tx_bd *txbd = NULL; + struct m_tag *mtag; + struct mbuf *m0; + u16 vlan_tag = 0, flags = 0; + u16 chain_prod, prod; + u32 prod_bseq; + +#ifdef BCE_DEBUG + u16 debug_prod; +#endif + int i, error, nsegs, rc = 0; /* Transfer any checksum offload flags to the bd. */ - if (m_head->m_pkthdr.csum_flags) { - if (m_head->m_pkthdr.csum_flags & CSUM_IP) - vlan_tag_flags |= TX_BD_FLAGS_IP_CKSUM; - if (m_head->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) - vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; + m0 = *m_head; + if (m0->m_pkthdr.csum_flags) { + if (m0->m_pkthdr.csum_flags & CSUM_IP) + flags |= TX_BD_FLAGS_IP_CKSUM; + if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) + flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; } /* Transfer any VLAN tags to the bd. */ - mtag = VLAN_OUTPUT_TAG(sc->bce_ifp, m_head); - if (mtag != NULL) - vlan_tag_flags |= (TX_BD_FLAGS_VLAN_TAG | - (VLAN_TAG_VALUE(mtag) << 16)); + mtag = VLAN_OUTPUT_TAG(sc->bce_ifp, m0); + if (mtag != NULL) { + flags |= TX_BD_FLAGS_VLAN_TAG; + vlan_tag = VLAN_TAG_VALUE(mtag); + } /* Map the mbuf into DMAable memory. */ - map = sc->tx_mbuf_map[*chain_prod]; - map_arg.sc = sc; - map_arg.prod = *prod; - map_arg.chain_prod = *chain_prod; - map_arg.prod_bseq = *prod_bseq; - map_arg.tx_flags = vlan_tag_flags; - map_arg.maxsegs = USABLE_TX_BD - sc->used_tx_bd - - BCE_TX_SLACK_SPACE; + prod = sc->tx_prod; + chain_prod = TX_CHAIN_IDX(prod); + map = sc->tx_mbuf_map[chain_prod]; - KASSERT(map_arg.maxsegs > 0, ("Invalid TX maxsegs value!")); + /* Map the mbuf into our DMA address space. */ + error = bus_dmamap_load_mbuf_sg(sc->tx_mbuf_tag, map, m0, + segs, &nsegs, BUS_DMA_NOWAIT); - for (i = 0; i < TX_PAGES; i++) - map_arg.tx_chain[i] = sc->tx_bd_chain[i]; + if (error == EFBIG) { + + /* Try to defrag the mbuf if there are too many segments. */ + DBPRINT(sc, BCE_WARN, "%s(): fragmented mbuf (%d pieces)\n", + __FUNCTION__, map_arg.maxsegs); + + m0 = m_defrag(*m_head, M_DONTWAIT); + if (m0 == NULL) { + m_freem(*m_head); + *m_head = NULL; + return (ENOBUFS); + } + + *m_head = m0; + error = bus_dmamap_load_mbuf_sg(sc->tx_mbuf_tag, map, m0, + segs, &nsegs, BUS_DMA_NOWAIT); + + /* Still getting an error after a defrag. */ + if (error == ENOMEM) { + return (error); + } else if (error != 0) { + BCE_PRINTF(sc, + "%s(%d): Error mapping mbuf into TX chain!\n", + __FILE__, __LINE__); + m_freem(m0); + *m_head = NULL; + return (ENOBUFS); + } + } else if (error == ENOMEM) { + return (error); + } else if (error != 0) { + m_freem(m0); + *m_head = NULL; + return (error); + } - /* Map the mbuf into our DMA address space. */ - error = bus_dmamap_load_mbuf(sc->tx_mbuf_tag, map, m_head, - bce_dma_map_tx_desc, &map_arg, BUS_DMA_NOWAIT); + /* + * The chip seems to require that at least 16 descriptors be kept + * empty at all times. Make sure we honor that. + * XXX Would it be faster to assume worst case scenario for nsegs + * and do this calculation higher up? + */ + if (nsegs > (USABLE_TX_BD - sc->used_tx_bd - BCE_TX_SLACK_SPACE)) { + bus_dmamap_unload(sc->tx_mbuf_tag, map); + return (ENOBUFS); + } - if (error || map_arg.maxsegs == 0) { - BCE_PRINTF(sc, "%s(%d): Error mapping mbuf into TX chain!\n", - __FILE__, __LINE__); - rc = ENOBUFS; - goto bce_tx_encap_exit; + /* prod points to an empty tx_bd at this point. */ + prod_bseq = sc->tx_prod_bseq; + +#ifdef BCE_DEBUG + debug_prod = chain_prod; +#endif + + DBPRINT(sc, BCE_INFO_SEND, + "%s(): Start: prod = 0x%04X, chain_prod = %04X, " + "prod_bseq = 0x%08X\n", + __FUNCTION__, *prod, chain_prod, prod_bseq); + + /* + * Cycle through each mbuf segment that makes up + * the outgoing frame, gathering the mapping info + * for that segment and creating a tx_bd to for + * the mbuf. + */ + for (i = 0; i < nsegs ; i++) { + + chain_prod = TX_CHAIN_IDX(prod); + txbd= &sc->tx_bd_chain[TX_PAGE(chain_prod)][TX_IDX(chain_prod)]; + + txbd->tx_bd_haddr_lo = htole32(BCE_ADDR_LO(segs[i].ds_addr)); + txbd->tx_bd_haddr_hi = htole32(BCE_ADDR_HI(segs[i].ds_addr)); + txbd->tx_bd_mss_nbytes = htole16(segs[i].ds_len); + txbd->tx_bd_vlan_tag = htole16(vlan_tag); + txbd->tx_bd_flags = htole16(flags); + prod_bseq += segs[i].ds_len; + if (i == 0) + txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_START); + prod = NEXT_TX_BD(prod); } + /* Set the END flag on the last TX buffer descriptor. */ + txbd->tx_bd_flags |= htole16(TX_BD_FLAGS_END); + + DBRUN(BCE_INFO_SEND, bce_dump_tx_chain(sc, debug_prod, nseg)); + + DBPRINT(sc, BCE_INFO_SEND, + "%s(): End: prod = 0x%04X, chain_prod = %04X, " + "prod_bseq = 0x%08X\n", + __FUNCTION__, prod, chain_prod, prod_bseq); + /* - * Ensure that the map for this transmission + * Ensure that the mbuf pointer for this transmission * is placed at the array index of the last * descriptor in this chain. This is done * because a single map is used for all * segments of the mbuf and we don't want to - * delete the map before all of the segments + * unload the map before all of the segments * have been freed. */ - sc->tx_mbuf_map[*chain_prod] = - sc->tx_mbuf_map[map_arg.chain_prod]; - sc->tx_mbuf_map[map_arg.chain_prod] = map; - sc->tx_mbuf_ptr[map_arg.chain_prod] = m_head; - sc->used_tx_bd += map_arg.maxsegs; + sc->tx_mbuf_ptr[chain_prod] = m0; + sc->used_tx_bd += nsegs; DBRUNIF((sc->used_tx_bd > sc->tx_hi_watermark), sc->tx_hi_watermark = sc->used_tx_bd); DBRUNIF(1, sc->tx_mbuf_alloc++); - DBRUN(BCE_VERBOSE_SEND, bce_dump_tx_mbuf_chain(sc, *chain_prod, - map_arg.maxsegs)); - - /* prod still points the last used tx_bd at this point. */ - *prod = map_arg.prod; - *chain_prod = map_arg.chain_prod; - *prod_bseq = map_arg.prod_bseq; + DBRUN(BCE_VERBOSE_SEND, bce_dump_tx_mbuf_chain(sc, chain_prod, nsegs)); -bce_tx_encap_exit: + /* prod points to the next free tx_bd at this point. */ + sc->tx_prod = prod; + sc->tx_prod_bseq = prod_bseq; return(rc); } @@ -4693,7 +4688,6 @@ struct mbuf *m_head = NULL; int count = 0; u16 tx_prod, tx_chain_prod; - u32 tx_prod_bseq; /* If there's no link or the transmit queue is empty then just exit. */ if (!sc->bce_link || IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { @@ -4705,15 +4699,17 @@ /* prod points to the next free tx_bd. */ tx_prod = sc->tx_prod; tx_chain_prod = TX_CHAIN_IDX(tx_prod); - tx_prod_bseq = sc->tx_prod_bseq; DBPRINT(sc, BCE_INFO_SEND, "%s(): Start: tx_prod = 0x%04X, tx_chain_prod = %04X, " "tx_prod_bseq = 0x%08X\n", - __FUNCTION__, tx_prod, tx_chain_prod, tx_prod_bseq); + __FUNCTION__, tx_prod, tx_chain_prod, sc->tx_prod_bseq); - /* Keep adding entries while there is space in the ring. */ - while(sc->tx_mbuf_ptr[tx_chain_prod] == NULL) { + /* + * Keep adding entries while there is space in the ring. We keep + * BCE_TX_SLACK_SPACE entries unused at all times. + */ + while (sc->used_tx_bd < USABLE_TX_BD - BCE_TX_SLACK_SPACE) { /* Check for any frames to send. */ IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); @@ -4726,7 +4722,7 @@ * head of the queue and set the OACTIVE flag * to wait for the NIC to drain the chain. */ - if (bce_tx_encap(sc, m_head, &tx_prod, &tx_chain_prod, &tx_prod_bseq)) { + if (bce_tx_encap(sc, &m_head)) { IFQ_DRV_PREPEND(&ifp->if_snd, m_head); ifp->if_drv_flags |= IFF_DRV_OACTIVE; DBPRINT(sc, BCE_INFO_SEND, @@ -4739,9 +4735,6 @@ /* Send a copy of the frame to any BPF listeners. */ BPF_MTAP(ifp, m_head); - - tx_prod = NEXT_TX_BD(tx_prod); - tx_chain_prod = TX_CHAIN_IDX(tx_prod); } if (count == 0) { @@ -4752,13 +4745,12 @@ } /* Update the driver's counters. */ - sc->tx_prod = tx_prod; - sc->tx_prod_bseq = tx_prod_bseq; + tx_chain_prod = TX_CHAIN_IDX(sc->tx_prod); DBPRINT(sc, BCE_INFO_SEND, "%s(): End: tx_prod = 0x%04X, tx_chain_prod = 0x%04X, " "tx_prod_bseq = 0x%08X\n", - __FUNCTION__, tx_prod, tx_chain_prod, tx_prod_bseq); + __FUNCTION__, tx_prod, tx_chain_prod, sc->tx_prod_bseq); /* Start the transmit. */ REG_WR16(sc, MB_TX_CID_ADDR + BCE_L2CTX_TX_HOST_BIDX, sc->tx_prod); @@ -4818,9 +4810,11 @@ DBPRINT(sc, BCE_INFO, "Setting new MTU of %d\n", ifr->ifr_mtu); + BCE_LOCK(sc); ifp->if_mtu = ifr->ifr_mtu; ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - bce_init(sc); + bce_init_locked(sc); + BCE_UNLOCK(sc); break; /* Set interface. */ @@ -4831,8 +4825,13 @@ /* Check if the interface is up. */ if (ifp->if_flags & IFF_UP) { - /* Change the promiscuous/multicast flags as necessary. */ - bce_set_rx_mode(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + /* Change the promiscuous/multicast flags as necessary. */ + bce_set_rx_mode(sc); + } else { + /* Start the HW */ + bce_init_locked(sc); + } } else { /* The interface is down. Check if the driver is running. */ if (ifp->if_drv_flags & IFF_DRV_RUNNING) { @@ -4850,12 +4849,12 @@ case SIOCDELMULTI: DBPRINT(sc, BCE_VERBOSE, "Received SIOCADDMULTI/SIOCDELMULTI\n"); + BCE_LOCK(sc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - BCE_LOCK(sc); bce_set_rx_mode(sc); - BCE_UNLOCK(sc); error = 0; } + BCE_UNLOCK(sc); break; @@ -5004,10 +5003,12 @@ /* DBRUN(BCE_FATAL, bce_breakpoint(sc)); */ + BCE_LOCK(sc); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - bce_init(sc); + bce_init_locked(sc); ifp->if_oerrors++; + BCE_UNLOCK(sc); } @@ -5308,14 +5309,6 @@ */ ifp->if_collisions = (u_long) stats->stat_EtherStatsCollisions; - ifp->if_ibytes = BCE_STATS(IfHCInOctets); - - ifp->if_obytes = BCE_STATS(IfHCOutOctets); - - ifp->if_imcasts = BCE_STATS(IfHCInMulticastPkts); - - ifp->if_omcasts = BCE_STATS(IfHCOutMulticastPkts); - ifp->if_ierrors = (u_long) stats->stat_EtherStatsUndersizePkts + (u_long) stats->stat_EtherStatsOverrsizePkts + (u_long) stats->stat_IfInMBUFDiscards + @@ -6165,9 +6158,10 @@ else /* Normal tx_bd entry. */ BCE_PRINTF(sc, "tx_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = 0x%08X, " - "flags = 0x%08X\n", idx, + "vlan tag= 0x%4X, "flags = 0x%04X\n", idx, txbd->tx_bd_haddr_hi, txbd->tx_bd_haddr_lo, - txbd->tx_bd_mss_nbytes, txbd->tx_bd_vlan_tag_flags); + txbd->tx_bd_mss_nbytes, txbd->tx_bd_vlan_tag, + txbd->tx_bd_flags); } Index: if_bcefw.h =================================================================== RCS file: /home/ncvs/src/sys/dev/bce/if_bcefw.h,v retrieving revision 1.1.4.1 diff -u -r1.1.4.1 if_bcefw.h --- if_bcefw.h 12 Apr 2006 18:09:27 -0000 1.1.4.1 +++ if_bcefw.h 3 Dec 2006 06:07:10 -0000 @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/bce/if_bcefw.h,v 1.1.4.1 2006/04/12 18:09:27 ps Exp $ + * $FreeBSD: src/sys/dev/bce/if_bcefw.h,v 1.1.2.1 2006/04/12 17:45:26 ps Exp $ */ /* Index: if_bcereg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/bce/if_bcereg.h,v retrieving revision 1.1.4.2 diff -u -r1.1.4.2 if_bcereg.h --- if_bcereg.h 4 May 2006 07:31:56 -0000 1.1.4.2 +++ if_bcereg.h 3 Dec 2006 06:07:10 -0000 @@ -26,7 +26,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/bce/if_bcereg.h,v 1.1.4.2 2006/05/04 07:31:56 scottl Exp $ + * $FreeBSD: src/sys/dev/bce/if_bcereg.h,v 1.1.2.3.2.1 2006/11/28 17:14:07 scottl Exp $ */ #ifndef _BCE_H_DEFINED @@ -63,7 +63,6 @@ #include #include -#include /* for DELAY */ #include #include #include @@ -738,7 +737,8 @@ u32 tx_bd_haddr_hi; u32 tx_bd_haddr_lo; u32 tx_bd_mss_nbytes; - u32 tx_bd_vlan_tag_flags; + u16 tx_bd_flags; + u16 tx_bd_vlan_tag; #define TX_BD_FLAGS_CONN_FAULT (1<<0) #define TX_BD_FLAGS_TCP_UDP_CKSUM (1<<1) #define TX_BD_FLAGS_IP_CKSUM (1<<2) @@ -4614,7 +4614,16 @@ #define BCE_BUS_SPACE_MAXADDR 0xFFFFFFFFFF #endif +/* + * XXX Checksum offload involving IP fragments seems to cause problems on + * transmit. Disable it for now, hopefully there will be a more elegant + * solution later. + */ +#ifdef BCE_IP_CSUM #define BCE_IF_HWASSIST (CSUM_IP | CSUM_TCP | CSUM_UDP) +#else +#define BCE_IF_HWASSIST (CSUM_TCP | CSUM_UDP) +#endif #if __FreeBSD_version < 700000 #define BCE_IF_CAPABILITIES (IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | \ @@ -4645,23 +4654,6 @@ #define BCE_STATS_BLK_SZ sizeof(struct statistics_block) #define BCE_TX_CHAIN_PAGE_SZ BCM_PAGE_SIZE #define BCE_RX_CHAIN_PAGE_SZ BCM_PAGE_SIZE -/* - * Mbuf pointers. We need these to keep track of the virtual addresses - * of our mbuf chains since we can only convert from physical to virtual, - * not the other way around. - */ - -struct bce_dmamap_arg { - struct bce_softc *sc; /* Pointer back to device context */ - bus_addr_t busaddr; /* Physical address of mapped memory */ - u32 tx_flags; /* Flags for frame transmit */ - u16 prod; - u16 chain_prod; - int maxsegs; /* Max segments supported for this mapped memory */ - u32 prod_bseq; - struct tx_bd *tx_chain[TX_PAGES]; -}; - struct bce_softc {