Protect bnx_tick() with splnet.

Bring in fixes and improvements from OpenBSD:
revision 1.25
- Simplify the arguments to bnx_tx_encap.
- Don't copy the bd_chain head pointers into temporary objects, they are
available globally.

From scottl@FreeBSD

revision 1.26
Overhaul the transmit path:
- Eliminate the bnx_dmamap_arg structure.
- Refactor the loop that fills the buffer descriptor so that it can be done
with a single set of logic in a single loop instead of two sets of logic.
- Eliminate the need to cache and pass descriptor indexes between the start
loop and the encap function.
- Change the start loop to always check the ifnet sendq for more work.

From scottl@FreeBSD

revision 1.27
make the exit label naming scheme match the current function names, removes
a FreeBSD-ism from the original driver.

revision 1.28 -> 1.30
- Ensure that at least 16 TX descriptors are kept unused in the ring.
- Use more complete error handling for TX load problems.

From scottl@FreeBSD

revision 1.31
replace a few more instances of hand rolled code with the LIST_FOREACH macro.

revision 1.33
In bnx_start, check the used_tx_bd count rather than the descriptors
mbuf pointer to see if the transmit ring is full.  The mbuf pointer
is set only in the last descriptor of a multi-descriptor packet.
By relying on the mbuf pointers of the earlier descriptors, the
driver would sometimes overwrite a descriptor belonging to a
packet that wasn't completed yet.  Also, tx_chain_prod wasn't
updated inside the loop, causing the wrong descriptor to be checked
after the first iteration.  The upshot of all this was the loss of
some transmitted packets at medium to high packet rates.

In bnx_tx_encap, remove a couple of old statements that shuffled
around the tx_mbuf_map pointers.  These now correspond 1-to-1 with
the transmit descriptors, and they are not supposed to be changed.

Correct a couple of inaccurate comments.

From jdp@FreeBSD

revision 1.43
Allow the bnx(4) driver to make use of all of the available hardware
multicast hash slots. The bnx(4) hardware supports 8 slots instead of
4 like the bge(4) hardware.

From Mike Karels via FreeBSD

Tested by Brad, biorn@ and Johan M:son Lindman
This commit is contained in:
bouyer 2007-04-09 14:23:03 +00:00
parent e8b43103b0
commit a17f6ef0b7
2 changed files with 139 additions and 230 deletions

View File

@ -1,5 +1,5 @@
/* $NetBSD: if_bnx.c,v 1.3 2007/03/04 06:02:19 christos Exp $ */
/* $OpenBSD: if_bnx.c,v 1.21 2006/08/21 03:32:11 brad Exp $ */
/* $NetBSD: if_bnx.c,v 1.4 2007/04/09 14:23:03 bouyer Exp $ */
/* $OpenBSD: if_bnx.c,v 1.43 2007/01/30 03:21:10 krw Exp $ */
/*-
* Copyright (c) 2006 Broadcom Corporation
@ -35,7 +35,7 @@
#if 0
__FBSDID("$FreeBSD: src/sys/dev/bce/if_bce.c,v 1.3 2006/04/13 14:12:26 ru Exp $");
#endif
__KERNEL_RCSID(0, "$NetBSD: if_bnx.c,v 1.3 2007/03/04 06:02:19 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_bnx.c,v 1.4 2007/04/09 14:23:03 bouyer Exp $");
/*
* The following controllers are supported by this driver:
@ -304,7 +304,6 @@ int bnx_nvram_write(struct bnx_softc *, u_int32_t, u_int8_t *, int);
int bnx_dma_alloc(struct bnx_softc *);
void bnx_dma_free(struct bnx_softc *);
void bnx_release_resources(struct bnx_softc *);
void bnx_dma_map_tx_desc(void *, bus_dmamap_t);
/****************************************************************************/
/* BNX Firmware Synchronization and Load */
@ -328,8 +327,7 @@ int bnx_init_rx_chain(struct bnx_softc *);
void bnx_free_rx_chain(struct bnx_softc *);
void bnx_free_tx_chain(struct bnx_softc *);
int bnx_tx_encap(struct bnx_softc *, struct mbuf *, u_int16_t *,
u_int16_t *, u_int32_t *);
int bnx_tx_encap(struct bnx_softc *, struct mbuf **);
void bnx_start(struct ifnet *);
int bnx_ioctl(struct ifnet *, u_long, void *);
void bnx_watchdog(struct ifnet *);
@ -662,7 +660,7 @@ bnx_attach(struct device *parent, struct device *self, void *aux)
ifp->if_baudrate = IF_Gbps(2.5);
else
ifp->if_baudrate = IF_Gbps(1);
IFQ_SET_MAXLEN(&ifp->if_snd, USABLE_TX_BD);
IFQ_SET_MAXLEN(&ifp->if_snd, USABLE_TX_BD - 1);
IFQ_SET_READY(&ifp->if_snd);
bcopy(sc->bnx_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
@ -1958,121 +1956,6 @@ bnx_dma_free(struct bnx_softc *sc)
DBPRINT(sc, BNX_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
}
/****************************************************************************/
/* 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. */
/****************************************************************************/
void
bnx_dma_map_tx_desc(void *arg, bus_dmamap_t map)
{
struct bnx_dmamap_arg *map_arg;
struct bnx_softc *sc;
struct tx_bd *txbd = NULL;
int i = 0, nseg;
u_int16_t prod, chain_prod;
u_int32_t prod_bseq, addr;
#ifdef BNX_DEBUG
u_int16_t debug_prod;
#endif
map_arg = arg;
sc = map_arg->sc;
nseg = map->dm_nsegs;
/* Signal error to caller if there's too many segments */
if (nseg > map_arg->maxsegs) {
DBPRINT(sc, BNX_WARN, "%s(): Mapped TX descriptors: max segs "
"= %d, " "actual segs = %d\n",
__FUNCTION__, map_arg->maxsegs, nseg);
map_arg->maxsegs = 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 BNX_DEBUG
debug_prod = chain_prod;
#endif
DBPRINT(sc, BNX_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 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. */
addr = (u_int32_t)(map->dm_segs[i].ds_addr);
txbd->tx_bd_haddr_lo = htole32(addr);
addr = (u_int32_t)((u_int64_t)map->dm_segs[i].ds_addr >> 32);
txbd->tx_bd_haddr_hi = htole32(addr);
txbd->tx_bd_mss_nbytes = htole16(map->dm_segs[i].ds_len);
txbd->tx_bd_vlan_tag_flags = htole16(map_arg->tx_flags |
TX_BD_FLAGS_START);
prod_bseq += map->dm_segs[i].ds_len;
bus_dmamap_sync(sc->bnx_dmatag,
sc->tx_bd_chain_map[TX_PAGE(chain_prod)],
sizeof(struct tx_bd) * TX_IDX(chain_prod),
sizeof(struct tx_bd), BUS_DMASYNC_PREWRITE);
/* 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)];
addr = (u_int32_t)(map->dm_segs[i].ds_addr);
txbd->tx_bd_haddr_lo = htole32(addr);
addr = (u_int32_t)((u_int64_t)map->dm_segs[i].ds_addr >> 32);
txbd->tx_bd_haddr_hi = htole32(addr);
txbd->tx_bd_mss_nbytes = htole16(map->dm_segs[i].ds_len);
txbd->tx_bd_vlan_tag_flags = htole16(map_arg->tx_flags);
prod_bseq += map->dm_segs[i].ds_len;
bus_dmamap_sync(sc->bnx_dmatag,
sc->tx_bd_chain_map[TX_PAGE(chain_prod)],
sizeof(struct tx_bd) * TX_IDX(chain_prod),
sizeof(struct tx_bd), BUS_DMASYNC_PREWRITE);
}
/* Set the END flag on the last TX buffer descriptor. */
txbd->tx_bd_vlan_tag_flags |= htole16(TX_BD_FLAGS_END);
bus_dmamap_sync(sc->bnx_dmatag,
sc->tx_bd_chain_map[TX_PAGE(chain_prod)],
sizeof(struct tx_bd) * TX_IDX(chain_prod),
sizeof(struct tx_bd), BUS_DMASYNC_PREWRITE);
DBRUN(BNX_INFO_SEND, bnx_dump_tx_chain(sc, debug_prod, nseg));
DBPRINT(sc, BNX_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;
}
/****************************************************************************/
/* Allocate any DMA memory needed by the driver. */
/* */
@ -3601,8 +3484,7 @@ bnx_ifmedia_upd(struct ifnet *ifp)
sc->bnx_link = 0;
if (mii->mii_instance) {
struct mii_softc *miisc;
for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
miisc = LIST_NEXT(miisc, mii_list))
LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
mii_phy_reset(miisc);
}
mii_mediachg(mii);
@ -3932,7 +3814,7 @@ bnx_rx_intr(struct bnx_softc *sc)
}
m_copydata(m, 0, ETHER_HDR_LEN, (void *)&vh);
vh.evl_proto = vh.evl_encap_proto;
vh.evl_tag = l2fhdr->l2_fhdr_vlan_tag >> 16;
vh.evl_tag = l2fhdr->l2_fhdr_vlan_tag;
vh.evl_encap_proto = htons(ETHERTYPE_VLAN);
m_adj(m, ETHER_HDR_LEN);
if ((m = m_prepend(m, sizeof(vh), M_DONTWAIT)) == NULL)
@ -4178,17 +4060,17 @@ bnx_init(struct ifnet *ifp)
if ((error = bnx_reset(sc, BNX_DRV_MSG_CODE_RESET)) != 0) {
aprint_error("bnx: Controller reset failed!\n");
goto bnx_init_locked_exit;
goto bnx_init_exit;
}
if ((error = bnx_chipinit(sc)) != 0) {
aprint_error("bnx: Controller initialization failed!\n");
goto bnx_init_locked_exit;
goto bnx_init_exit;
}
if ((error = bnx_blockinit(sc)) != 0) {
aprint_error("bnx: Block initialization failed!\n");
goto bnx_init_locked_exit;
goto bnx_init_exit;
}
/* Calculate and program the Ethernet MRU size. */
@ -4230,7 +4112,7 @@ bnx_init(struct ifnet *ifp)
callout_reset(&sc->bnx_timeout, hz, bnx_tick, sc);
bnx_init_locked_exit:
bnx_init_exit:
DBPRINT(sc, BNX_VERBOSE_RESET, "Exiting %s()\n", __FUNCTION__);
splx(s);
@ -4246,88 +4128,132 @@ bnx_init_locked_exit:
/* 0 for success, positive value for failure. */
/****************************************************************************/
int
bnx_tx_encap(struct bnx_softc *sc, struct mbuf *m_head, u_int16_t *prod,
u_int16_t *chain_prod, u_int32_t *prod_bseq)
bnx_tx_encap(struct bnx_softc *sc, struct mbuf **m_head)
{
u_int32_t vlan_tag_flags = 0;
struct bnx_dmamap_arg map_arg;
bus_dmamap_t map;
int i, rc = 0;
struct tx_bd *txbd = NULL;
struct mbuf *m0;
u_int16_t vlan_tag = 0, flags = 0;
u_int16_t chain_prod, prod;
#ifdef BNX_DEBUG
u_int16_t debug_prod;
#endif
u_int32_t addr, prod_bseq;
int i, error, rc = 0;
struct m_tag *mtag;
m0 = *m_head;
/* Transfer any checksum offload flags to the bd. */
if (m_head->m_pkthdr.csum_flags) {
if (m_head->m_pkthdr.csum_flags & M_CSUM_IPv4)
vlan_tag_flags |= TX_BD_FLAGS_IP_CKSUM;
if (m_head->m_pkthdr.csum_flags &
if (m0->m_pkthdr.csum_flags) {
if (m0->m_pkthdr.csum_flags & M_CSUM_IPv4)
flags |= TX_BD_FLAGS_IP_CKSUM;
if (m0->m_pkthdr.csum_flags &
(M_CSUM_TCPv4 | M_CSUM_UDPv4))
vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
}
/* Transfer any VLAN tags to the bd. */
mtag = VLAN_OUTPUT_TAG(&sc->ethercom, m_head);
if (mtag != NULL)
vlan_tag_flags |= (TX_BD_FLAGS_VLAN_TAG |
VLAN_TAG_VALUE(mtag));
mtag = VLAN_OUTPUT_TAG(&sc->ethercom, 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 - BNX_TX_SLACK_SPACE;
#if 0
KASSERT(map_arg.maxsegs > 0, ("Invalid TX maxsegs value!"));
#endif
for (i = 0; i < TX_PAGES; i++)
map_arg.tx_chain[i] = sc->tx_bd_chain[i];
prod = sc->tx_prod;
chain_prod = TX_CHAIN_IDX(prod);
map = sc->tx_mbuf_map[chain_prod];
/* Map the mbuf into our DMA address space. */
if (bus_dmamap_load_mbuf(sc->bnx_dmatag, map, m_head,
BUS_DMA_NOWAIT)) {
error = bus_dmamap_load_mbuf(sc->bnx_dmatag, map, m0, BUS_DMA_NOWAIT);
if (error != 0) {
aprint_error("%s: Error mapping mbuf into TX chain!\n",
sc->bnx_dev.dv_xname);
rc = ENOBUFS;
goto bnx_tx_encap_exit;
m_freem(m0);
*m_head = NULL;
return (error);
}
bus_dmamap_sync(sc->bnx_dmatag, map, 0, map->dm_mapsize,
BUS_DMASYNC_PREWRITE);
bnx_dma_map_tx_desc(&map_arg, map);
/*
* 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
* map->dm_nsegs and do this calculation higher up?
*/
if (map->dm_nsegs > (USABLE_TX_BD - sc->used_tx_bd - BNX_TX_SLACK_SPACE)) {
bus_dmamap_unload(sc->bnx_dmatag, map);
return (ENOBUFS);
}
/* prod points to an empty tx_bd at this point. */
prod_bseq = sc->tx_prod_bseq;
#ifdef BNX_DEBUG
debug_prod = chain_prod;
#endif
DBPRINT(sc, BNX_INFO_SEND,
"%s(): Start: prod = 0x%04X, chain_prod = %04X, "
"prod_bseq = 0x%08X\n",
__FUNCTION__, *prod, chain_prod, prod_bseq);
/*
* Ensure that the map 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
* have been freed.
* Cycle through each mbuf segment that makes up
* the outgoing frame, gathering the mapping info
* for that segment and creating a tx_bd for the
* mbuf.
*/
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;
for (i = 0; i < map->dm_nsegs ; i++) {
chain_prod = TX_CHAIN_IDX(prod);
txbd = &sc->tx_bd_chain[TX_PAGE(chain_prod)][TX_IDX(chain_prod)];
addr = (u_int32_t)(map->dm_segs[i].ds_addr);
txbd->tx_bd_haddr_lo = htole32(addr);
addr = (u_int32_t)((u_int64_t)map->dm_segs[i].ds_addr >> 32);
txbd->tx_bd_haddr_hi = htole32(addr);
txbd->tx_bd_mss_nbytes = htole16(map->dm_segs[i].ds_len);
txbd->tx_bd_vlan_tag = htole16(vlan_tag);
txbd->tx_bd_flags = htole16(flags);
prod_bseq += map->dm_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(BNX_INFO_SEND, bnx_dump_tx_chain(sc, debug_prod, nseg));
DBPRINT(sc, BNX_INFO_SEND,
"%s(): End: prod = 0x%04X, chain_prod = %04X, "
"prod_bseq = 0x%08X\n",
__FUNCTION__, prod, chain_prod, prod_bseq);
/*
* 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 unload the map before
* all of the segments have been freed.
*/
sc->tx_mbuf_ptr[chain_prod] = m0;
sc->used_tx_bd += map->dm_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(BNX_VERBOSE_SEND, bnx_dump_tx_mbuf_chain(sc, *chain_prod,
DBRUN(BNX_VERBOSE_SEND, bnx_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;
/* prod points to the next free tx_bd at this point. */
sc->tx_prod = prod;
sc->tx_prod_bseq = prod_bseq;
bnx_tx_encap_exit:
return(rc);
return (rc);
}
/****************************************************************************/
@ -4343,26 +4269,27 @@ bnx_start(struct ifnet *ifp)
struct mbuf *m_head = NULL;
int count = 0;
u_int16_t tx_prod, tx_chain_prod;
u_int32_t tx_prod_bseq;
/* If there's no link or the transmit queue is empty then just exit. */
if (!sc->bnx_link || IFQ_IS_EMPTY(&ifp->if_snd)) {
DBPRINT(sc, BNX_INFO_SEND,
"%s(): No link or transmit queue empty.\n", __FUNCTION__);
goto bnx_start_locked_exit;
goto bnx_start_exit;
}
/* 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, BNX_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
* BNX_TX_SLACK_SPACE entries unused at all times.
*/
while (sc->used_tx_bd < USABLE_TX_BD - BNX_TX_SLACK_SPACE) {
/* Check for any frames to send. */
IFQ_POLL(&ifp->if_snd, m_head);
if (m_head == NULL)
@ -4370,12 +4297,10 @@ bnx_start(struct ifnet *ifp)
/*
* Pack the data into the transmit ring. If we
* don't have room, place the mbuf back at the
* head of the queue and set the OACTIVE flag
* to wait for the NIC to drain the chain.
* don't have room, set the OACTIVE flag to wait
* for the NIC to drain the chain.
*/
if (bnx_tx_encap(sc, m_head, &tx_prod, &tx_chain_prod,
&tx_prod_bseq)) {
if (bnx_tx_encap(sc, &m_head)) {
ifp->if_flags |= IFF_OACTIVE;
DBPRINT(sc, BNX_INFO_SEND, "TX chain is closed for "
"business! Total tx_bd used = %d\n",
@ -4391,24 +4316,21 @@ bnx_start(struct ifnet *ifp)
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, m_head);
#endif
tx_prod = NEXT_TX_BD(tx_prod);
tx_chain_prod = TX_CHAIN_IDX(tx_prod);
}
if (count == 0) {
/* no packets were dequeued */
DBPRINT(sc, BNX_VERBOSE_SEND,
"%s(): No packets were dequeued\n", __FUNCTION__);
goto bnx_start_locked_exit;
goto bnx_start_exit;
}
/* 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, BNX_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);
tx_chain_prod, sc->tx_prod_bseq);
/* Start the transmit. */
REG_WR16(sc, MB_TX_CID_ADDR + BNX_L2CTX_TX_HOST_BIDX, sc->tx_prod);
@ -4417,7 +4339,7 @@ bnx_start(struct ifnet *ifp)
/* Set the tx timeout. */
ifp->if_timer = BNX_TX_TIMEOUT;
bnx_start_locked_exit:
bnx_start_exit:
return;
}
@ -4447,7 +4369,7 @@ bnx_ioctl(struct ifnet *ifp, u_long command, void *data)
} else if (!(ifp->if_flags & IFF_RUNNING))
bnx_init(ifp);
} else if (ifp->if_flags & IFF_RUNNING)
} else if (ifp->if_flags & IFF_RUNNING)
bnx_stop(sc);
sc->bnx_if_flags = ifp->if_flags;
@ -4619,7 +4541,7 @@ bnx_intr(void *xsc)
/* Re-enable interrupts. */
REG_WR(sc, BNX_PCICFG_INT_ACK_CMD,
BNX_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx |
BNX_PCICFG_INT_ACK_CMD_MASK_INT);
BNX_PCICFG_INT_ACK_CMD_MASK_INT);
REG_WR(sc, BNX_PCICFG_INT_ACK_CMD,
BNX_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx);
@ -4643,7 +4565,7 @@ bnx_set_rx_mode(struct bnx_softc *sc)
struct ifnet *ifp = &ec->ec_if;
struct ether_multi *enm;
struct ether_multistep step;
u_int32_t hashes[4] = { 0, 0, 0, 0 };
u_int32_t hashes[NUM_MC_HASH_REGISTERS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
u_int32_t rx_mode, sort_mode;
int h, i;
@ -4690,12 +4612,12 @@ allmulti:
goto allmulti;
}
h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) &
0x7F;
hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F);
0xFF;
hashes[(h & 0xE0) >> 5] |= 1 << (h & 0x1F);
ETHER_NEXT_MULTI(step, enm);
}
for (i = 0; i < 4; i++)
for (i = 0; i < NUM_MC_HASH_REGISTERS; i++)
REG_WR(sc, BNX_EMAC_MULTICAST_HASH0 + (i * 4),
hashes[i]);
@ -4928,6 +4850,7 @@ bnx_tick(void *xsc)
struct ifnet *ifp = &sc->ethercom.ec_if;
struct mii_data *mii = NULL;
u_int32_t msg;
int s = splnet();
/* Tell the firmware that the driver is still running. */
#ifdef BNX_DEBUG
@ -4945,7 +4868,7 @@ bnx_tick(void *xsc)
/* If link is up already up then we're done. */
if (sc->bnx_link)
goto bnx_tick_locked_exit;
goto bnx_tick_exit;
/* DRC - ToDo: Add SerDes support and check SerDes link here. */
@ -4961,7 +4884,8 @@ bnx_tick(void *xsc)
bnx_start(ifp);
}
bnx_tick_locked_exit:
bnx_tick_exit:
splx(s);
return;
}
@ -5075,9 +4999,10 @@ bnx_dump_txbd(struct bnx_softc *sc, int idx, struct tx_bd *txbd)
else
/* Normal tx_bd entry. */
BNX_PRINTF(sc, "tx_bd[0x%04X]: haddr = 0x%08X:%08X, nbytes = "
"0x%08X, flags = 0x%08X\n", idx,
"0x%08X, vlan tag = 0x%4X, flags = 0x%08X\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);
}
void

View File

@ -1,5 +1,5 @@
/* $NetBSD: if_bnxreg.h,v 1.1 2006/12/17 23:02:06 bouyer Exp $ */
/* $OpenBSD: if_bnxreg.h,v 1.11 2006/08/21 03:22:09 brad Exp $ */
/* $NetBSD: if_bnxreg.h,v 1.2 2007/04/09 14:23:16 bouyer Exp $ */
/* $OpenBSD: if_bnxreg.h,v 1.17 2006/11/20 21:26:27 brad Exp $ */
/*-
* Copyright (c) 2006 Broadcom Corporation
@ -698,7 +698,8 @@ struct tx_bd {
u_int32_t tx_bd_haddr_hi;
u_int32_t tx_bd_haddr_lo;
u_int32_t tx_bd_mss_nbytes;
u_int32_t tx_bd_vlan_tag_flags;
u_int16_t tx_bd_flags;
u_int16_t 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)
@ -4587,23 +4588,6 @@ struct fw_info {
#define BNX_STATS_BLK_SZ sizeof(struct statistics_block)
#define BNX_TX_CHAIN_PAGE_SZ BCM_PAGE_SIZE
#define BNX_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 bnx_dmamap_arg {
struct bnx_softc *sc; /* Pointer back to device context */
bus_addr_t busaddr; /* Physical address of mapped memory */
u_int32_t tx_flags; /* Flags for frame transmit */
u_int16_t prod;
u_int16_t chain_prod;
int maxsegs; /* Max segments supported for this mapped memory */
u_int32_t prod_bseq;
struct tx_bd *tx_chain[TX_PAGES];
};
struct bnx_softc
{