summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/re.c292
-rw-r--r--sys/dev/ic/rtl81x9reg.h8
2 files changed, 184 insertions, 116 deletions
diff --git a/sys/dev/ic/re.c b/sys/dev/ic/re.c
index 1c334c8900f..a669d327619 100644
--- a/sys/dev/ic/re.c
+++ b/sys/dev/ic/re.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: re.c,v 1.34 2006/07/02 03:20:48 brad Exp $ */
+/* $OpenBSD: re.c,v 1.35 2006/07/03 02:28:39 brad Exp $ */
/* $FreeBSD: if_re.c,v 1.31 2004/09/04 07:54:05 ru Exp $ */
/*
* Copyright (c) 1997, 1998-2003
@@ -153,11 +153,10 @@
int redebug = 0;
#define DPRINTF(x) if (redebug) printf x
-void re_attach(struct rl_softc *);
+int re_attach(struct rl_softc *);
int re_encap(struct rl_softc *, struct mbuf *, int *);
-int re_allocmem(struct rl_softc *);
int re_newbuf(struct rl_softc *, int, struct mbuf *);
int re_rx_list_init(struct rl_softc *);
int re_tx_list_init(struct rl_softc *);
@@ -724,101 +723,11 @@ done:
#endif
-int
-re_allocmem(struct rl_softc *sc)
-{
- int error;
- int nseg, rseg;
- int i;
-
- nseg = 32;
-
- /* Allocate DMA'able memory for the TX ring */
-
- error = bus_dmamap_create(sc->sc_dmat, RL_TX_LIST_SZ, 1,
- RL_TX_LIST_SZ, 0, BUS_DMA_ALLOCNOW,
- &sc->rl_ldata.rl_tx_list_map);
- if (error)
- return (ENOMEM);
- error = bus_dmamem_alloc(sc->sc_dmat, RL_TX_LIST_SZ,
- ETHER_ALIGN, 0,
- &sc->rl_ldata.rl_tx_listseg, 1, &rseg, BUS_DMA_NOWAIT);
- if (error)
- return (ENOMEM);
-
- /* Load the map for the TX ring. */
- error = bus_dmamem_map(sc->sc_dmat, &sc->rl_ldata.rl_tx_listseg,
- 1, RL_TX_LIST_SZ,
- (caddr_t *)&sc->rl_ldata.rl_tx_list, BUS_DMA_NOWAIT);
- if (error)
- return (ENOMEM);
- memset(sc->rl_ldata.rl_tx_list, 0, RL_TX_LIST_SZ);
-
- error = bus_dmamap_load(sc->sc_dmat, sc->rl_ldata.rl_tx_list_map,
- sc->rl_ldata.rl_tx_list, RL_TX_LIST_SZ, NULL, BUS_DMA_NOWAIT);
- if (error)
- return (ENOMEM);
-
- /* Create DMA maps for TX buffers */
-
- for (i = 0; i < RL_TX_DESC_CNT; i++) {
- error = bus_dmamap_create(sc->sc_dmat, MCLBYTES * nseg, nseg,
- MCLBYTES, 0, BUS_DMA_ALLOCNOW,
- &sc->rl_ldata.rl_tx_dmamap[i]);
- if (error) {
- printf("%s: can't create DMA map for TX\n",
- sc->sc_dev.dv_xname);
- return (ENOMEM);
- }
- }
-
- /* Allocate DMA'able memory for the RX ring */
-
- error = bus_dmamap_create(sc->sc_dmat, RL_RX_LIST_SZ, 1,
- RL_RX_LIST_SZ, 0, BUS_DMA_ALLOCNOW,
- &sc->rl_ldata.rl_rx_list_map);
- if (error)
- return (ENOMEM);
-
- error = bus_dmamem_alloc(sc->sc_dmat, RL_RX_LIST_SZ, RL_RING_ALIGN,
- 0, &sc->rl_ldata.rl_rx_listseg, 1, &rseg, BUS_DMA_NOWAIT);
- if (error)
- return (ENOMEM);
-
- /* Load the map for the RX ring. */
- error = bus_dmamem_map(sc->sc_dmat, &sc->rl_ldata.rl_rx_listseg,
- 1, RL_RX_LIST_SZ,
- (caddr_t *)&sc->rl_ldata.rl_rx_list, BUS_DMA_NOWAIT);
- if (error)
- return (ENOMEM);
- memset(sc->rl_ldata.rl_rx_list, 0, RL_RX_LIST_SZ);
-
- error = bus_dmamap_load(sc->sc_dmat, sc->rl_ldata.rl_rx_list_map,
- sc->rl_ldata.rl_rx_list, RL_RX_LIST_SZ, NULL, BUS_DMA_NOWAIT);
- if (error)
- return (ENOMEM);
-
- /* Create DMA maps for RX buffers */
-
- for (i = 0; i < RL_RX_DESC_CNT; i++) {
- error = bus_dmamap_create(sc->sc_dmat, MCLBYTES * nseg, nseg,
- MCLBYTES, 0, BUS_DMA_ALLOCNOW,
- &sc->rl_ldata.rl_rx_dmamap[i]);
- if (error) {
- printf("%s: can't create DMA map for RX\n",
- sc->sc_dev.dv_xname);
- return (ENOMEM);
- }
- }
-
- return (0);
-}
-
/*
* Attach the interface. Allocate softc structures, do ifmedia
* setup and ethernet/BPF attach.
*/
-void
+int
re_attach(struct rl_softc *sc)
{
u_char eaddr[ETHER_ADDR_LEN];
@@ -858,10 +767,101 @@ re_attach(struct rl_softc *sc)
printf(", address %s\n",
ether_sprintf(sc->sc_arpcom.ac_enaddr));
- error = re_allocmem(sc);
+ /* Allocate DMA'able memory for the TX ring */
+ if ((error = bus_dmamem_alloc(sc->sc_dmat, RL_TX_LIST_SZ,
+ RE_ETHER_ALIGN, 0, &sc->rl_ldata.rl_tx_listseg, 1,
+ &sc->rl_ldata.rl_tx_listnseg, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: can't allocate tx listseg, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_0;
+ }
+
+ /* Load the map for the TX ring. */
+ if ((error = bus_dmamem_map(sc->sc_dmat, &sc->rl_ldata.rl_tx_listseg,
+ sc->rl_ldata.rl_tx_listnseg, RL_TX_LIST_SZ,
+ (caddr_t *)&sc->rl_ldata.rl_tx_list,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: can't map tx list, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_1;
+ }
+ memset(sc->rl_ldata.rl_tx_list, 0, RL_TX_LIST_SZ);
- if (error)
- return;
+ if ((error = bus_dmamap_create(sc->sc_dmat, RL_TX_LIST_SZ, 1,
+ RL_TX_LIST_SZ, 0, BUS_DMA_ALLOCNOW,
+ &sc->rl_ldata.rl_tx_list_map)) != 0) {
+ printf("%s: can't create tx list map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_2;
+ }
+
+ if ((error = bus_dmamap_load(sc->sc_dmat,
+ sc->rl_ldata.rl_tx_list_map, sc->rl_ldata.rl_tx_list,
+ RL_TX_LIST_SZ, NULL, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: can't load tx list, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_3;
+ }
+
+ /* Create DMA maps for TX buffers */
+ for (i = 0; i < RL_TX_DESC_CNT; i++) {
+ error = bus_dmamap_create(sc->sc_dmat, MCLBYTES * RL_NTXSEGS,
+ RL_NTXSEGS, MCLBYTES, 0, BUS_DMA_ALLOCNOW,
+ &sc->rl_ldata.rl_tx_dmamap[i]);
+ if (error) {
+ printf("%s: can't create DMA map for TX\n",
+ sc->sc_dev.dv_xname);
+ goto fail_4;
+ }
+ }
+
+ /* Allocate DMA'able memory for the RX ring */
+ if ((error = bus_dmamem_alloc(sc->sc_dmat, RL_RX_LIST_SZ,
+ RL_RING_ALIGN, 0, &sc->rl_ldata.rl_rx_listseg, 1,
+ &sc->rl_ldata.rl_rx_listnseg, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: can't allocate rx listnseg, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_4;
+ }
+
+ /* Load the map for the RX ring. */
+ if ((error = bus_dmamem_map(sc->sc_dmat, &sc->rl_ldata.rl_rx_listseg,
+ sc->rl_ldata.rl_rx_listnseg, RL_RX_LIST_SZ,
+ (caddr_t *)&sc->rl_ldata.rl_rx_list,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: can't map rx list, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_5;
+
+ }
+ memset(sc->rl_ldata.rl_rx_list, 0, RL_RX_LIST_SZ);
+
+ if ((error = bus_dmamap_create(sc->sc_dmat, RL_RX_LIST_SZ, 1,
+ RL_RX_LIST_SZ, 0, BUS_DMA_ALLOCNOW,
+ &sc->rl_ldata.rl_rx_list_map)) != 0) {
+ printf("%s: can't create rx list map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_6;
+ }
+
+ if ((error = bus_dmamap_load(sc->sc_dmat,
+ sc->rl_ldata.rl_rx_list_map, sc->rl_ldata.rl_rx_list,
+ RL_RX_LIST_SZ, NULL, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: can't load rx list, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail_7;
+ }
+
+ /* Create DMA maps for RX buffers */
+ for (i = 0; i < RL_RX_DESC_CNT; i++) {
+ error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
+ 0, BUS_DMA_ALLOCNOW, &sc->rl_ldata.rl_rx_dmamap[i]);
+ if (error) {
+ printf("%s: can't create DMA map for RX\n",
+ sc->sc_dev.dv_xname);
+ goto fail_8;
+ }
+ }
ifp = &sc->sc_arpcom.ac_if;
ifp->if_softc = sc;
@@ -929,11 +929,52 @@ re_attach(struct rl_softc *sc)
printf("%s: attach aborted due to hardware diag failure\n",
sc->sc_dev.dv_xname);
ether_ifdetach(ifp);
- return;
+ goto fail_8;
}
#endif
DPRINTF(("leaving re_attach\n"));
+ return (1);
+
+fail_8:
+ /* Destroy DMA maps for RX buffers. */
+ for (i = 0; i < RL_RX_DESC_CNT; i++) {
+ if (sc->rl_ldata.rl_rx_dmamap[i] != NULL)
+ bus_dmamap_destroy(sc->sc_dmat,
+ sc->rl_ldata.rl_rx_dmamap[i]);
+ }
+
+ /* Free DMA'able memory for the RX ring. */
+ bus_dmamap_unload(sc->sc_dmat, sc->rl_ldata.rl_rx_list_map);
+fail_7:
+ bus_dmamap_destroy(sc->sc_dmat, sc->rl_ldata.rl_rx_list_map);
+fail_6:
+ bus_dmamem_unmap(sc->sc_dmat,
+ (caddr_t)sc->rl_ldata.rl_rx_list, RL_RX_LIST_SZ);
+fail_5:
+ bus_dmamem_free(sc->sc_dmat,
+ &sc->rl_ldata.rl_rx_listseg, sc->rl_ldata.rl_rx_listnseg);
+
+fail_4:
+ /* Destroy DMA maps for TX buffers. */
+ for (i = 0; i < RL_TX_DESC_CNT; i++) {
+ if (sc->rl_ldata.rl_tx_dmamap[i] != NULL)
+ bus_dmamap_destroy(sc->sc_dmat,
+ sc->rl_ldata.rl_tx_dmamap[i]);
+ }
+
+ /* Free DMA'able memory for the TX ring. */
+ bus_dmamap_unload(sc->sc_dmat, sc->rl_ldata.rl_tx_list_map);
+fail_3:
+ bus_dmamap_destroy(sc->sc_dmat, sc->rl_ldata.rl_tx_list_map);
+fail_2:
+ bus_dmamem_unmap(sc->sc_dmat,
+ (caddr_t)sc->rl_ldata.rl_tx_list, RL_TX_LIST_SZ);
+fail_1:
+ bus_dmamem_free(sc->sc_dmat,
+ &sc->rl_ldata.rl_tx_listseg, sc->rl_ldata.rl_tx_listnseg);
+fail_0:
+ return (1);
}
@@ -977,10 +1018,8 @@ re_newbuf(struct rl_softc *sc, int idx, struct mbuf *m)
#endif
map = sc->rl_ldata.rl_rx_dmamap[idx];
- error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT);
- if (map->dm_nsegs > 1)
- goto out;
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT);
if (error)
goto out;
@@ -1398,7 +1437,7 @@ re_intr(void *arg)
}
int
-re_encap(struct rl_softc *sc, struct mbuf *m_head, int *idx)
+re_encap(struct rl_softc *sc, struct mbuf *m, int *idx)
{
bus_dmamap_t map;
int error, i, curidx;
@@ -1425,28 +1464,31 @@ re_encap(struct rl_softc *sc, struct mbuf *m_head, int *idx)
* RL_TDESC_CMD_UDPCSUM does not take affect.
*/
- if ((m_head->m_pkthdr.csum_flags &
+ if ((m->m_pkthdr.csum_flags &
(M_IPV4_CSUM_OUT|M_TCPV4_CSUM_OUT|M_UDPV4_CSUM_OUT)) != 0) {
rl_flags |= RL_TDESC_CMD_IPCSUM;
- if (m_head->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
+ if (m->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
rl_flags |= RL_TDESC_CMD_TCPCSUM;
- if (m_head->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
+ if (m->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
rl_flags |= RL_TDESC_CMD_UDPCSUM;
}
#endif
map = sc->rl_ldata.rl_tx_dmamap[*idx];
- error = bus_dmamap_load_mbuf(sc->sc_dmat, map,
- m_head, BUS_DMA_NOWAIT);
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT);
if (error) {
+ /* XXX try to defrag if EFBIG? */
printf("%s: can't map mbuf (error %d)\n",
sc->sc_dev.dv_xname, error);
- return (ENOBUFS);
+ return (error);
+ }
+
+ if (map->dm_nsegs > sc->rl_ldata.rl_tx_free - 4) {
+ error = EFBIG;
+ goto fail_unload;
}
- if (map->dm_nsegs > sc->rl_ldata.rl_tx_free - 4)
- return (ENOBUFS);
/*
* Map the segment array into descriptors. Note that we set the
* start-of-frame and end-of-frame markers for either TX or RX, but
@@ -1462,8 +1504,16 @@ re_encap(struct rl_softc *sc, struct mbuf *m_head, int *idx)
curidx = *idx;
while (1) {
d = &sc->rl_ldata.rl_tx_list[curidx];
- if (letoh32(d->rl_cmdstat) & RL_RDESC_STAT_OWN)
- return (ENOBUFS);
+ if (letoh32(d->rl_cmdstat) & RL_RDESC_STAT_OWN) {
+ while (i > 0) {
+ sc->rl_ldata.rl_tx_list[
+ (curidx + RL_TX_DESC_CNT - i) %
+ RL_TX_DESC_CNT].rl_cmdstat = 0;
+ i--;
+ }
+ error = ENOBUFS;
+ goto fail_unload;
+ }
cmdstat = map->dm_segs[i].ds_len;
d->rl_bufaddr_lo =
@@ -1493,7 +1543,7 @@ re_encap(struct rl_softc *sc, struct mbuf *m_head, int *idx)
sc->rl_ldata.rl_tx_dmamap[*idx] =
sc->rl_ldata.rl_tx_dmamap[curidx];
sc->rl_ldata.rl_tx_dmamap[curidx] = map;
- sc->rl_ldata.rl_tx_mbuf[curidx] = m_head;
+ sc->rl_ldata.rl_tx_mbuf[curidx] = m;
sc->rl_ldata.rl_tx_free -= map->dm_nsegs;
/*
@@ -1527,6 +1577,11 @@ re_encap(struct rl_softc *sc, struct mbuf *m_head, int *idx)
*idx = curidx;
return (0);
+
+fail_unload:
+ bus_dmamap_unload(sc->sc_dmat, map);
+
+ return (error);
}
/*
@@ -1547,11 +1602,20 @@ re_start(struct ifnet *ifp)
idx = sc->rl_ldata.rl_tx_prodidx;
while (sc->rl_ldata.rl_tx_mbuf[idx] == NULL) {
+ int error;
+
IFQ_DEQUEUE(&ifp->if_snd, m_head);
if (m_head == NULL)
break;
- if (re_encap(sc, m_head, &idx)) {
+ error = re_encap(sc, m_head, &idx);
+ if (error == EFBIG &&
+ sc->rl_ldata.rl_tx_free == RL_TX_DESC_CNT) {
+ ifp->if_oerrors++;
+ m_freem(m_head);
+ continue;
+ }
+ if (error) {
IF_PREPEND(&ifp->if_snd, m_head);
ifp->if_flags |= IFF_OACTIVE;
break;
diff --git a/sys/dev/ic/rtl81x9reg.h b/sys/dev/ic/rtl81x9reg.h
index 13e65e1a423..d072443d22b 100644
--- a/sys/dev/ic/rtl81x9reg.h
+++ b/sys/dev/ic/rtl81x9reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtl81x9reg.h,v 1.24 2006/07/01 23:39:36 brad Exp $ */
+/* $OpenBSD: rtl81x9reg.h,v 1.25 2006/07/03 02:28:39 brad Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -607,7 +607,9 @@ struct rl_stats {
#define RL_JUMBO_FRAMELEN 7440
#define RL_JUMBO_MTU (RL_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
-#define MAX_NUM_MULTICAST_ADDRESSES 128
+#define RL_NTXSEGS 32
+
+#define MAX_NUM_MULTICAST_ADDRESSES 128
#define RL_INC(x) (x = (x + 1) % RL_TX_LIST_CNT)
#define RL_CUR_TXADDR(x) ((x->rl_cdata.cur_tx * 4) + RL_TXADDR0)
@@ -662,9 +664,11 @@ struct rl_list_data {
bus_dmamap_t rl_rx_list_map;
struct rl_desc *rl_rx_list;
bus_dma_segment_t rl_rx_listseg;
+ int rl_rx_listnseg;
bus_dmamap_t rl_tx_list_map;
struct rl_desc *rl_tx_list;
bus_dma_segment_t rl_tx_listseg;
+ int rl_tx_listnseg;
};
struct rl_softc {