Split common TX/RX descriptor DMA tag to TX and RX DMA tags
respectively and fix all bus_dma(9) issues seen when bounce buffers are used. o Setup frame handling had no bus_dmamap_sync(9) which prevented driver from configuring RX filter. Add missing bus_dmamap_sync(9) in both dc_setfilt_21143()/dc_setfilt_xircom() and dc_txeof(). o Use bus_addr_t for DMA segment instead of using u_int32_t. o Introduce dc_dma_alloc()/dc_dma_free() functions to allocate/free DMA'able memory. o Create two DMA descriptor list for each TX/RX lists. This change will minimize the size of bounce buffers that would be used in each TX/RX path. Previously driver had to copy both TX/RX lists when bounce buffer is active. o 21143 data sheet says descriptor list requires 4 bytes alignment. Remove PAGE_SIZE alignment restriction and use sizeof(struct dc_dec). o Setup frame requires 4 bytes alignment. Remove PAGE_SIZE alignment restriction and use sizeof(struct dc_dec). o Add missing DMA map unload for both setup frame and TX/RX descriptor list. o Overhaul RX handling logic such that make driver always allocate new RX buffer with dc_newbuf(). Previously driver allowed to copy received frame with m_devget(9) after passing the descriptor ownership to controller. This can lead to passing wrong frame to upper stack. o Introduce dc_discard_rxbuf() which will discard received frame and reuse loaded DMA map and RX mbuf. o Correct several wrong bus_dmamap_sync(9) usage in dc_rxeof and dc_txeof. The TX/RX descriptor lists are updated by both driver and HW so READ/WRITE semantics should be used. o If driver failed to allocate new RX buffer, update if_iqdrops counter instead of if_ierrors since driver received the frame without errors. o Make sure to unload loaded setup frame DMA map in dc_txeof and clear the mark of setup frame of the TX descriptor in dc_txeof(). o Add check for possible TX descriptor overruns in dc_encap() and move check for free buffer to caller, dc_start_locked(). o Swap the loaded DMA map and the last DMA map for multi-segmented frames. Since dc_txeof() assumes the last descriptor of the frame has the DMA map, driver should swap the first and the last DMA map in dc_encap(). Previously driver tried to unload not-yet-loaded DMA map such that the loaded DMA map was not unloaded at all for multi-segmented frames. o Rewrite DC_RXDESC/DC_TXDESC macro to simpler one. o Remove definition of ETHER_ALIGN, it's already defined in ethernet.h. With this changes, dc(4) works with bounce buffers and it shall also fix issues which might have shown in PAE environments. Tested by: marius
This commit is contained in:
parent
a84b4e80ca
commit
5f14ee2363
@ -233,7 +233,8 @@ static int dc_detach(device_t);
|
||||
static int dc_suspend(device_t);
|
||||
static int dc_resume(device_t);
|
||||
static const struct dc_type *dc_devtype(device_t);
|
||||
static int dc_newbuf(struct dc_softc *, int, int);
|
||||
static void dc_discard_rxbuf(struct dc_softc *, int);
|
||||
static int dc_newbuf(struct dc_softc *, int);
|
||||
static int dc_encap(struct dc_softc *, struct mbuf **);
|
||||
static void dc_pnic_rx_bug_war(struct dc_softc *, int);
|
||||
static int dc_rx_resync(struct dc_softc *);
|
||||
@ -253,6 +254,10 @@ static int dc_shutdown(device_t);
|
||||
static int dc_ifmedia_upd(struct ifnet *);
|
||||
static void dc_ifmedia_sts(struct ifnet *, struct ifmediareq *);
|
||||
|
||||
static int dc_dma_alloc(struct dc_softc *);
|
||||
static void dc_dma_free(struct dc_softc *);
|
||||
static void dc_dma_map_addr(void *, bus_dma_segment_t *, int, int);
|
||||
|
||||
static void dc_delay(struct dc_softc *);
|
||||
static void dc_eeprom_idle(struct dc_softc *);
|
||||
static void dc_eeprom_putbyte(struct dc_softc *, int);
|
||||
@ -1087,11 +1092,11 @@ dc_setfilt_21143(struct dc_softc *sc)
|
||||
i = sc->dc_cdata.dc_tx_prod;
|
||||
DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT);
|
||||
sc->dc_cdata.dc_tx_cnt++;
|
||||
sframe = &sc->dc_ldata->dc_tx_list[i];
|
||||
sframe = &sc->dc_ldata.dc_tx_list[i];
|
||||
sp = sc->dc_cdata.dc_sbuf;
|
||||
bzero(sp, DC_SFRAME_LEN);
|
||||
|
||||
sframe->dc_data = htole32(sc->dc_saddr);
|
||||
sframe->dc_data = htole32(DC_ADDR_LO(sc->dc_saddr));
|
||||
sframe->dc_ctl = htole32(DC_SFRAME_LEN | DC_TXCTL_SETUP |
|
||||
DC_TXCTL_TLINK | DC_FILTER_HASHPERF | DC_TXCTL_FINT);
|
||||
|
||||
@ -1130,6 +1135,7 @@ dc_setfilt_21143(struct dc_softc *sc)
|
||||
sp[41] = DC_SP_MAC(eaddr[2]);
|
||||
|
||||
sframe->dc_status = htole32(DC_TXSTAT_OWN);
|
||||
bus_dmamap_sync(sc->dc_stag, sc->dc_smap, BUS_DMASYNC_PREWRITE);
|
||||
CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
|
||||
|
||||
/*
|
||||
@ -1290,11 +1296,11 @@ dc_setfilt_xircom(struct dc_softc *sc)
|
||||
i = sc->dc_cdata.dc_tx_prod;
|
||||
DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT);
|
||||
sc->dc_cdata.dc_tx_cnt++;
|
||||
sframe = &sc->dc_ldata->dc_tx_list[i];
|
||||
sframe = &sc->dc_ldata.dc_tx_list[i];
|
||||
sp = sc->dc_cdata.dc_sbuf;
|
||||
bzero(sp, DC_SFRAME_LEN);
|
||||
|
||||
sframe->dc_data = htole32(sc->dc_saddr);
|
||||
sframe->dc_data = htole32(DC_ADDR_LO(sc->dc_saddr));
|
||||
sframe->dc_ctl = htole32(DC_SFRAME_LEN | DC_TXCTL_SETUP |
|
||||
DC_TXCTL_TLINK | DC_FILTER_HASHPERF | DC_TXCTL_FINT);
|
||||
|
||||
@ -1335,6 +1341,7 @@ dc_setfilt_xircom(struct dc_softc *sc)
|
||||
DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON);
|
||||
DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON);
|
||||
sframe->dc_status = htole32(DC_TXSTAT_OWN);
|
||||
bus_dmamap_sync(sc->dc_stag, sc->dc_smap, BUS_DMASYNC_PREWRITE);
|
||||
CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
|
||||
|
||||
/*
|
||||
@ -1806,7 +1813,7 @@ dc_parse_21143_srom(struct dc_softc *sc)
|
||||
static void
|
||||
dc_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
||||
{
|
||||
u_int32_t *paddr;
|
||||
bus_addr_t *paddr;
|
||||
|
||||
KASSERT(nseg == 1,
|
||||
("%s: wrong number of segments (%d)", __func__, nseg));
|
||||
@ -1814,6 +1821,208 @@ dc_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
||||
*paddr = segs->ds_addr;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_dma_alloc(struct dc_softc *sc)
|
||||
{
|
||||
int error, i;
|
||||
|
||||
error = bus_dma_tag_create(bus_get_dma_tag(sc->dc_dev), 1, 0,
|
||||
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0,
|
||||
NULL, NULL, &sc->dc_ptag);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"failed to allocate parent DMA tag\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
|
||||
error = bus_dma_tag_create(sc->dc_ptag, DC_LIST_ALIGN, 0,
|
||||
BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, DC_RX_LIST_SZ, 1,
|
||||
DC_RX_LIST_SZ, 0, NULL, NULL, &sc->dc_rx_ltag);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev, "failed to create RX list DMA tag\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
error = bus_dma_tag_create(sc->dc_ptag, DC_LIST_ALIGN, 0,
|
||||
BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, DC_TX_LIST_SZ, 1,
|
||||
DC_TX_LIST_SZ, 0, NULL, NULL, &sc->dc_tx_ltag);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev, "failed to create TX list DMA tag\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* RX descriptor list. */
|
||||
error = bus_dmamem_alloc(sc->dc_rx_ltag,
|
||||
(void **)&sc->dc_ldata.dc_rx_list, BUS_DMA_NOWAIT |
|
||||
BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->dc_rx_lmap);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"failed to allocate DMA'able memory for RX list\n");
|
||||
goto fail;
|
||||
}
|
||||
error = bus_dmamap_load(sc->dc_rx_ltag, sc->dc_rx_lmap,
|
||||
sc->dc_ldata.dc_rx_list, DC_RX_LIST_SZ, dc_dma_map_addr,
|
||||
&sc->dc_ldata.dc_rx_list_paddr, BUS_DMA_NOWAIT);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"failed to load DMA'able memory for RX list\n");
|
||||
goto fail;
|
||||
}
|
||||
/* TX descriptor list. */
|
||||
error = bus_dmamem_alloc(sc->dc_tx_ltag,
|
||||
(void **)&sc->dc_ldata.dc_tx_list, BUS_DMA_NOWAIT |
|
||||
BUS_DMA_ZERO | BUS_DMA_COHERENT, &sc->dc_tx_lmap);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"failed to allocate DMA'able memory for TX list\n");
|
||||
goto fail;
|
||||
}
|
||||
error = bus_dmamap_load(sc->dc_tx_ltag, sc->dc_tx_lmap,
|
||||
sc->dc_ldata.dc_tx_list, DC_TX_LIST_SZ, dc_dma_map_addr,
|
||||
&sc->dc_ldata.dc_tx_list_paddr, BUS_DMA_NOWAIT);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"cannot load DMA'able memory for TX list\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a busdma tag and DMA safe memory for the multicast
|
||||
* setup frame.
|
||||
*/
|
||||
error = bus_dma_tag_create(sc->dc_ptag, DC_LIST_ALIGN, 0,
|
||||
BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
DC_SFRAME_LEN + DC_MIN_FRAMELEN, 1, DC_SFRAME_LEN + DC_MIN_FRAMELEN,
|
||||
0, NULL, NULL, &sc->dc_stag);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"failed to create DMA tag for setup frame\n");
|
||||
goto fail;
|
||||
}
|
||||
error = bus_dmamem_alloc(sc->dc_stag, (void **)&sc->dc_cdata.dc_sbuf,
|
||||
BUS_DMA_NOWAIT, &sc->dc_smap);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"failed to allocate DMA'able memory for setup frame\n");
|
||||
goto fail;
|
||||
}
|
||||
error = bus_dmamap_load(sc->dc_stag, sc->dc_smap, sc->dc_cdata.dc_sbuf,
|
||||
DC_SFRAME_LEN, dc_dma_map_addr, &sc->dc_saddr, BUS_DMA_NOWAIT);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"cannot load DMA'able memory for setup frame\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Allocate a busdma tag for RX mbufs. */
|
||||
error = bus_dma_tag_create(sc->dc_ptag, DC_RXBUF_ALIGN, 0,
|
||||
BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
MCLBYTES, 1, MCLBYTES, 0, NULL, NULL, &sc->dc_rx_mtag);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev, "failed to create RX mbuf tag\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Allocate a busdma tag for TX mbufs. */
|
||||
error = bus_dma_tag_create(sc->dc_ptag, 1, 0,
|
||||
BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
MCLBYTES * DC_MAXFRAGS, DC_MAXFRAGS, MCLBYTES,
|
||||
0, NULL, NULL, &sc->dc_tx_mtag);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev, "failed to create TX mbuf tag\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Create the TX/RX busdma maps. */
|
||||
for (i = 0; i < DC_TX_LIST_CNT; i++) {
|
||||
error = bus_dmamap_create(sc->dc_tx_mtag, 0,
|
||||
&sc->dc_cdata.dc_tx_map[i]);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"failed to create TX mbuf dmamap\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < DC_RX_LIST_CNT; i++) {
|
||||
error = bus_dmamap_create(sc->dc_rx_mtag, 0,
|
||||
&sc->dc_cdata.dc_rx_map[i]);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"failed to create RX mbuf dmamap\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
error = bus_dmamap_create(sc->dc_rx_mtag, 0, &sc->dc_sparemap);
|
||||
if (error) {
|
||||
device_printf(sc->dc_dev,
|
||||
"failed to create spare RX mbuf dmamap\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
dc_dma_free(struct dc_softc *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* RX buffers. */
|
||||
if (sc->dc_rx_mtag != NULL) {
|
||||
for (i = 0; i < DC_RX_LIST_CNT; i++) {
|
||||
if (sc->dc_cdata.dc_rx_map[i] != NULL)
|
||||
bus_dmamap_destroy(sc->dc_rx_mtag,
|
||||
sc->dc_cdata.dc_rx_map[i]);
|
||||
}
|
||||
if (sc->dc_sparemap != NULL)
|
||||
bus_dmamap_destroy(sc->dc_rx_mtag, sc->dc_sparemap);
|
||||
bus_dma_tag_destroy(sc->dc_rx_mtag);
|
||||
}
|
||||
|
||||
/* TX buffers. */
|
||||
if (sc->dc_rx_mtag != NULL) {
|
||||
for (i = 0; i < DC_TX_LIST_CNT; i++) {
|
||||
if (sc->dc_cdata.dc_tx_map[i] != NULL)
|
||||
bus_dmamap_destroy(sc->dc_tx_mtag,
|
||||
sc->dc_cdata.dc_tx_map[i]);
|
||||
}
|
||||
bus_dma_tag_destroy(sc->dc_tx_mtag);
|
||||
}
|
||||
|
||||
/* RX descriptor list. */
|
||||
if (sc->dc_rx_ltag) {
|
||||
if (sc->dc_rx_lmap != NULL)
|
||||
bus_dmamap_unload(sc->dc_rx_ltag, sc->dc_rx_lmap);
|
||||
if (sc->dc_rx_lmap != NULL && sc->dc_ldata.dc_rx_list != NULL)
|
||||
bus_dmamem_free(sc->dc_rx_ltag, sc->dc_ldata.dc_rx_list,
|
||||
sc->dc_rx_lmap);
|
||||
bus_dma_tag_destroy(sc->dc_rx_ltag);
|
||||
}
|
||||
|
||||
/* TX descriptor list. */
|
||||
if (sc->dc_tx_ltag) {
|
||||
if (sc->dc_tx_lmap != NULL)
|
||||
bus_dmamap_unload(sc->dc_tx_ltag, sc->dc_tx_lmap);
|
||||
if (sc->dc_tx_lmap != NULL && sc->dc_ldata.dc_tx_list != NULL)
|
||||
bus_dmamem_free(sc->dc_tx_ltag, sc->dc_ldata.dc_tx_list,
|
||||
sc->dc_tx_lmap);
|
||||
bus_dma_tag_destroy(sc->dc_tx_ltag);
|
||||
}
|
||||
|
||||
/* multicast setup frame. */
|
||||
if (sc->dc_stag) {
|
||||
if (sc->dc_smap != NULL)
|
||||
bus_dmamap_unload(sc->dc_stag, sc->dc_smap);
|
||||
if (sc->dc_smap != NULL && sc->dc_cdata.dc_sbuf != NULL)
|
||||
bus_dmamem_free(sc->dc_stag, sc->dc_cdata.dc_sbuf,
|
||||
sc->dc_smap);
|
||||
bus_dma_tag_destroy(sc->dc_stag);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach the interface. Allocate softc structures, do ifmedia
|
||||
* setup and ethernet/BPF attach.
|
||||
@ -1827,7 +2036,7 @@ dc_attach(device_t dev)
|
||||
struct ifnet *ifp;
|
||||
struct dc_mediainfo *m;
|
||||
u_int32_t reg, revision;
|
||||
int error, i, mac_offset, phy, rid, tmp;
|
||||
int error, mac_offset, phy, rid, tmp;
|
||||
u_int8_t *mac;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
@ -2139,96 +2348,8 @@ dc_attach(device_t dev)
|
||||
error = 0;
|
||||
}
|
||||
|
||||
/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
|
||||
error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0,
|
||||
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
sizeof(struct dc_list_data), 1, sizeof(struct dc_list_data),
|
||||
0, NULL, NULL, &sc->dc_ltag);
|
||||
if (error) {
|
||||
device_printf(dev, "failed to allocate busdma tag\n");
|
||||
error = ENXIO;
|
||||
if ((error = dc_dma_alloc(sc)) != 0)
|
||||
goto fail;
|
||||
}
|
||||
error = bus_dmamem_alloc(sc->dc_ltag, (void **)&sc->dc_ldata,
|
||||
BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->dc_lmap);
|
||||
if (error) {
|
||||
device_printf(dev, "failed to allocate DMA safe memory\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
error = bus_dmamap_load(sc->dc_ltag, sc->dc_lmap, sc->dc_ldata,
|
||||
sizeof(struct dc_list_data), dc_dma_map_addr, &sc->dc_laddr,
|
||||
BUS_DMA_NOWAIT);
|
||||
if (error) {
|
||||
device_printf(dev, "cannot get address of the descriptors\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a busdma tag and DMA safe memory for the multicast
|
||||
* setup frame.
|
||||
*/
|
||||
error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0,
|
||||
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
DC_SFRAME_LEN + DC_MIN_FRAMELEN, 1, DC_SFRAME_LEN + DC_MIN_FRAMELEN,
|
||||
0, NULL, NULL, &sc->dc_stag);
|
||||
if (error) {
|
||||
device_printf(dev, "failed to allocate busdma tag\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
error = bus_dmamem_alloc(sc->dc_stag, (void **)&sc->dc_cdata.dc_sbuf,
|
||||
BUS_DMA_NOWAIT, &sc->dc_smap);
|
||||
if (error) {
|
||||
device_printf(dev, "failed to allocate DMA safe memory\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
error = bus_dmamap_load(sc->dc_stag, sc->dc_smap, sc->dc_cdata.dc_sbuf,
|
||||
DC_SFRAME_LEN, dc_dma_map_addr, &sc->dc_saddr, BUS_DMA_NOWAIT);
|
||||
if (error) {
|
||||
device_printf(dev, "cannot get address of the descriptors\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Allocate a busdma tag for mbufs. */
|
||||
error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
|
||||
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
MCLBYTES * DC_MAXFRAGS, DC_MAXFRAGS, MCLBYTES,
|
||||
0, NULL, NULL, &sc->dc_mtag);
|
||||
if (error) {
|
||||
device_printf(dev, "failed to allocate busdma tag\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Create the TX/RX busdma maps. */
|
||||
for (i = 0; i < DC_TX_LIST_CNT; i++) {
|
||||
error = bus_dmamap_create(sc->dc_mtag, 0,
|
||||
&sc->dc_cdata.dc_tx_map[i]);
|
||||
if (error) {
|
||||
device_printf(dev, "failed to init TX ring\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < DC_RX_LIST_CNT; i++) {
|
||||
error = bus_dmamap_create(sc->dc_mtag, 0,
|
||||
&sc->dc_cdata.dc_rx_map[i]);
|
||||
if (error) {
|
||||
device_printf(dev, "failed to init RX ring\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
error = bus_dmamap_create(sc->dc_mtag, 0, &sc->dc_sparemap);
|
||||
if (error) {
|
||||
device_printf(dev, "failed to init RX ring\n");
|
||||
error = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ifp = sc->dc_ifp = if_alloc(IFT_ETHER);
|
||||
if (ifp == NULL) {
|
||||
@ -2377,7 +2498,6 @@ dc_detach(device_t dev)
|
||||
struct dc_softc *sc;
|
||||
struct ifnet *ifp;
|
||||
struct dc_mediainfo *m;
|
||||
int i;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
KASSERT(mtx_initialized(&sc->dc_mtx), ("dc mutex not initialized"));
|
||||
@ -2412,27 +2532,7 @@ dc_detach(device_t dev)
|
||||
if (ifp)
|
||||
if_free(ifp);
|
||||
|
||||
if (sc->dc_cdata.dc_sbuf != NULL)
|
||||
bus_dmamem_free(sc->dc_stag, sc->dc_cdata.dc_sbuf, sc->dc_smap);
|
||||
if (sc->dc_ldata != NULL)
|
||||
bus_dmamem_free(sc->dc_ltag, sc->dc_ldata, sc->dc_lmap);
|
||||
if (sc->dc_mtag) {
|
||||
for (i = 0; i < DC_TX_LIST_CNT; i++)
|
||||
if (sc->dc_cdata.dc_tx_map[i] != NULL)
|
||||
bus_dmamap_destroy(sc->dc_mtag,
|
||||
sc->dc_cdata.dc_tx_map[i]);
|
||||
for (i = 0; i < DC_RX_LIST_CNT; i++)
|
||||
if (sc->dc_cdata.dc_rx_map[i] != NULL)
|
||||
bus_dmamap_destroy(sc->dc_mtag,
|
||||
sc->dc_cdata.dc_rx_map[i]);
|
||||
bus_dmamap_destroy(sc->dc_mtag, sc->dc_sparemap);
|
||||
}
|
||||
if (sc->dc_stag)
|
||||
bus_dma_tag_destroy(sc->dc_stag);
|
||||
if (sc->dc_mtag)
|
||||
bus_dma_tag_destroy(sc->dc_mtag);
|
||||
if (sc->dc_ltag)
|
||||
bus_dma_tag_destroy(sc->dc_ltag);
|
||||
dc_dma_free(sc);
|
||||
|
||||
free(sc->dc_pnic_rx_buf, M_DEVBUF);
|
||||
|
||||
@ -2459,7 +2559,7 @@ dc_list_tx_init(struct dc_softc *sc)
|
||||
int i, nexti;
|
||||
|
||||
cd = &sc->dc_cdata;
|
||||
ld = sc->dc_ldata;
|
||||
ld = &sc->dc_ldata;
|
||||
for (i = 0; i < DC_TX_LIST_CNT; i++) {
|
||||
if (i == DC_TX_LIST_CNT - 1)
|
||||
nexti = 0;
|
||||
@ -2474,7 +2574,7 @@ dc_list_tx_init(struct dc_softc *sc)
|
||||
|
||||
cd->dc_tx_prod = cd->dc_tx_cons = cd->dc_tx_cnt = 0;
|
||||
cd->dc_tx_pkts = 0;
|
||||
bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap,
|
||||
bus_dmamap_sync(sc->dc_tx_ltag, sc->dc_tx_lmap,
|
||||
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
||||
return (0);
|
||||
}
|
||||
@ -2493,10 +2593,10 @@ dc_list_rx_init(struct dc_softc *sc)
|
||||
int i, nexti;
|
||||
|
||||
cd = &sc->dc_cdata;
|
||||
ld = sc->dc_ldata;
|
||||
ld = &sc->dc_ldata;
|
||||
|
||||
for (i = 0; i < DC_RX_LIST_CNT; i++) {
|
||||
if (dc_newbuf(sc, i, 1) != 0)
|
||||
if (dc_newbuf(sc, i) != 0)
|
||||
return (ENOBUFS);
|
||||
if (i == DC_RX_LIST_CNT - 1)
|
||||
nexti = 0;
|
||||
@ -2506,7 +2606,7 @@ dc_list_rx_init(struct dc_softc *sc)
|
||||
}
|
||||
|
||||
cd->dc_rx_prod = 0;
|
||||
bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap,
|
||||
bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap,
|
||||
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
||||
return (0);
|
||||
}
|
||||
@ -2515,23 +2615,18 @@ dc_list_rx_init(struct dc_softc *sc)
|
||||
* Initialize an RX descriptor and attach an MBUF cluster.
|
||||
*/
|
||||
static int
|
||||
dc_newbuf(struct dc_softc *sc, int i, int alloc)
|
||||
dc_newbuf(struct dc_softc *sc, int i)
|
||||
{
|
||||
struct mbuf *m_new;
|
||||
bus_dmamap_t tmp;
|
||||
struct mbuf *m;
|
||||
bus_dmamap_t map;
|
||||
bus_dma_segment_t segs[1];
|
||||
int error, nseg;
|
||||
|
||||
if (alloc) {
|
||||
m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
|
||||
if (m_new == NULL)
|
||||
m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
|
||||
if (m == NULL)
|
||||
return (ENOBUFS);
|
||||
} else {
|
||||
m_new = sc->dc_cdata.dc_rx_chain[i];
|
||||
m_new->m_data = m_new->m_ext.ext_buf;
|
||||
}
|
||||
m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
|
||||
m_adj(m_new, sizeof(u_int64_t));
|
||||
m->m_len = m->m_pkthdr.len = MCLBYTES;
|
||||
m_adj(m, sizeof(u_int64_t));
|
||||
|
||||
/*
|
||||
* If this is a PNIC chip, zero the buffer. This is part
|
||||
@ -2539,31 +2634,31 @@ dc_newbuf(struct dc_softc *sc, int i, int alloc)
|
||||
* 82c169 chips.
|
||||
*/
|
||||
if (sc->dc_flags & DC_PNIC_RX_BUG_WAR)
|
||||
bzero(mtod(m_new, char *), m_new->m_len);
|
||||
bzero(mtod(m, char *), m->m_len);
|
||||
|
||||
/* No need to remap the mbuf if we're reusing it. */
|
||||
if (alloc) {
|
||||
error = bus_dmamap_load_mbuf_sg(sc->dc_mtag, sc->dc_sparemap,
|
||||
m_new, segs, &nseg, 0);
|
||||
error = bus_dmamap_load_mbuf_sg(sc->dc_rx_mtag, sc->dc_sparemap,
|
||||
m, segs, &nseg, 0);
|
||||
if (error) {
|
||||
m_freem(m_new);
|
||||
m_freem(m);
|
||||
return (error);
|
||||
}
|
||||
KASSERT(nseg == 1,
|
||||
("%s: wrong number of segments (%d)", __func__, nseg));
|
||||
sc->dc_ldata->dc_rx_list[i].dc_data = htole32(segs->ds_addr);
|
||||
bus_dmamap_unload(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i]);
|
||||
tmp = sc->dc_cdata.dc_rx_map[i];
|
||||
sc->dc_cdata.dc_rx_map[i] = sc->dc_sparemap;
|
||||
sc->dc_sparemap = tmp;
|
||||
sc->dc_cdata.dc_rx_chain[i] = m_new;
|
||||
}
|
||||
KASSERT(nseg == 1, ("%s: wrong number of segments (%d)", __func__,
|
||||
nseg));
|
||||
if (sc->dc_cdata.dc_rx_chain[i] != NULL)
|
||||
bus_dmamap_unload(sc->dc_rx_mtag, sc->dc_cdata.dc_rx_map[i]);
|
||||
|
||||
sc->dc_ldata->dc_rx_list[i].dc_ctl = htole32(DC_RXCTL_RLINK | DC_RXLEN);
|
||||
sc->dc_ldata->dc_rx_list[i].dc_status = htole32(DC_RXSTAT_OWN);
|
||||
bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i],
|
||||
map = sc->dc_cdata.dc_rx_map[i];
|
||||
sc->dc_cdata.dc_rx_map[i] = sc->dc_sparemap;
|
||||
sc->dc_sparemap = map;
|
||||
sc->dc_cdata.dc_rx_chain[i] = m;
|
||||
bus_dmamap_sync(sc->dc_rx_mtag, sc->dc_cdata.dc_rx_map[i],
|
||||
BUS_DMASYNC_PREREAD);
|
||||
bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap,
|
||||
|
||||
sc->dc_ldata.dc_rx_list[i].dc_ctl = htole32(DC_RXCTL_RLINK | DC_RXLEN);
|
||||
sc->dc_ldata.dc_rx_list[i].dc_data =
|
||||
htole32(DC_ADDR_LO(segs[0].ds_addr));
|
||||
sc->dc_ldata.dc_rx_list[i].dc_status = htole32(DC_RXSTAT_OWN);
|
||||
bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap,
|
||||
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
||||
return (0);
|
||||
}
|
||||
@ -2632,13 +2727,13 @@ dc_pnic_rx_bug_war(struct dc_softc *sc, int idx)
|
||||
u_int32_t rxstat = 0;
|
||||
|
||||
i = sc->dc_pnic_rx_bug_save;
|
||||
cur_rx = &sc->dc_ldata->dc_rx_list[idx];
|
||||
cur_rx = &sc->dc_ldata.dc_rx_list[idx];
|
||||
ptr = sc->dc_pnic_rx_buf;
|
||||
bzero(ptr, DC_RXLEN * 5);
|
||||
|
||||
/* Copy all the bytes from the bogus buffers. */
|
||||
while (1) {
|
||||
c = &sc->dc_ldata->dc_rx_list[i];
|
||||
c = &sc->dc_ldata.dc_rx_list[i];
|
||||
rxstat = le32toh(c->dc_status);
|
||||
m = sc->dc_cdata.dc_rx_chain[i];
|
||||
bcopy(mtod(m, char *), ptr, DC_RXLEN);
|
||||
@ -2646,7 +2741,7 @@ dc_pnic_rx_bug_war(struct dc_softc *sc, int idx)
|
||||
/* If this is the last buffer, break out. */
|
||||
if (i == idx || rxstat & DC_RXSTAT_LASTFRAG)
|
||||
break;
|
||||
dc_newbuf(sc, i, 0);
|
||||
dc_discard_rxbuf(sc, i);
|
||||
DC_INC(i, DC_RX_LIST_CNT);
|
||||
}
|
||||
|
||||
@ -2695,7 +2790,9 @@ dc_rx_resync(struct dc_softc *sc)
|
||||
pos = sc->dc_cdata.dc_rx_prod;
|
||||
|
||||
for (i = 0; i < DC_RX_LIST_CNT; i++) {
|
||||
cur_rx = &sc->dc_ldata->dc_rx_list[pos];
|
||||
bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap,
|
||||
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
|
||||
cur_rx = &sc->dc_ldata.dc_rx_list[pos];
|
||||
if (!(le32toh(cur_rx->dc_status) & DC_RXSTAT_OWN))
|
||||
break;
|
||||
DC_INC(pos, DC_RX_LIST_CNT);
|
||||
@ -2711,6 +2808,22 @@ dc_rx_resync(struct dc_softc *sc)
|
||||
return (EAGAIN);
|
||||
}
|
||||
|
||||
static void
|
||||
dc_discard_rxbuf(struct dc_softc *sc, int i)
|
||||
{
|
||||
struct mbuf *m;
|
||||
|
||||
if (sc->dc_flags & DC_PNIC_RX_BUG_WAR) {
|
||||
m = sc->dc_cdata.dc_rx_chain[i];
|
||||
bzero(mtod(m, char *), m->m_len);
|
||||
}
|
||||
|
||||
sc->dc_ldata.dc_rx_list[i].dc_ctl = htole32(DC_RXCTL_RLINK | DC_RXLEN);
|
||||
sc->dc_ldata.dc_rx_list[i].dc_status = htole32(DC_RXSTAT_OWN);
|
||||
bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap, BUS_DMASYNC_PREREAD |
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
}
|
||||
|
||||
/*
|
||||
* A frame has been uploaded: pass the resulting mbuf chain up to
|
||||
* the higher level protocols.
|
||||
@ -2718,7 +2831,7 @@ dc_rx_resync(struct dc_softc *sc)
|
||||
static int
|
||||
dc_rxeof(struct dc_softc *sc)
|
||||
{
|
||||
struct mbuf *m, *m0;
|
||||
struct mbuf *m;
|
||||
struct ifnet *ifp;
|
||||
struct dc_desc *cur_rx;
|
||||
int i, total_len, rx_npkts;
|
||||
@ -2727,13 +2840,13 @@ dc_rxeof(struct dc_softc *sc)
|
||||
DC_LOCK_ASSERT(sc);
|
||||
|
||||
ifp = sc->dc_ifp;
|
||||
i = sc->dc_cdata.dc_rx_prod;
|
||||
total_len = 0;
|
||||
rx_npkts = 0;
|
||||
|
||||
bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_POSTREAD);
|
||||
while (!(le32toh(sc->dc_ldata->dc_rx_list[i].dc_status) &
|
||||
DC_RXSTAT_OWN)) {
|
||||
bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap, BUS_DMASYNC_POSTREAD |
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
for (i = sc->dc_cdata.dc_rx_prod;
|
||||
(ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
|
||||
DC_INC(i, DC_RX_LIST_CNT)) {
|
||||
#ifdef DEVICE_POLLING
|
||||
if (ifp->if_capenable & IFCAP_POLLING) {
|
||||
if (sc->rxcycles <= 0)
|
||||
@ -2741,10 +2854,12 @@ dc_rxeof(struct dc_softc *sc)
|
||||
sc->rxcycles--;
|
||||
}
|
||||
#endif
|
||||
cur_rx = &sc->dc_ldata->dc_rx_list[i];
|
||||
cur_rx = &sc->dc_ldata.dc_rx_list[i];
|
||||
rxstat = le32toh(cur_rx->dc_status);
|
||||
if ((rxstat & DC_RXSTAT_OWN) != 0)
|
||||
break;
|
||||
m = sc->dc_cdata.dc_rx_chain[i];
|
||||
bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i],
|
||||
bus_dmamap_sync(sc->dc_rx_mtag, sc->dc_cdata.dc_rx_map[i],
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
total_len = DC_RXBYTES(rxstat);
|
||||
|
||||
@ -2752,10 +2867,8 @@ dc_rxeof(struct dc_softc *sc)
|
||||
if ((rxstat & DC_WHOLEFRAME) != DC_WHOLEFRAME) {
|
||||
if (rxstat & DC_RXSTAT_FIRSTFRAG)
|
||||
sc->dc_pnic_rx_bug_save = i;
|
||||
if ((rxstat & DC_RXSTAT_LASTFRAG) == 0) {
|
||||
DC_INC(i, DC_RX_LIST_CNT);
|
||||
if ((rxstat & DC_RXSTAT_LASTFRAG) == 0)
|
||||
continue;
|
||||
}
|
||||
dc_pnic_rx_bug_war(sc, i);
|
||||
rxstat = le32toh(cur_rx->dc_status);
|
||||
total_len = DC_RXBYTES(rxstat);
|
||||
@ -2777,11 +2890,10 @@ dc_rxeof(struct dc_softc *sc)
|
||||
ifp->if_ierrors++;
|
||||
if (rxstat & DC_RXSTAT_COLLSEEN)
|
||||
ifp->if_collisions++;
|
||||
dc_newbuf(sc, i, 0);
|
||||
if (rxstat & DC_RXSTAT_CRCERR) {
|
||||
DC_INC(i, DC_RX_LIST_CNT);
|
||||
dc_discard_rxbuf(sc, i);
|
||||
if (rxstat & DC_RXSTAT_CRCERR)
|
||||
continue;
|
||||
} else {
|
||||
else {
|
||||
dc_init_locked(sc);
|
||||
return (rx_npkts);
|
||||
}
|
||||
@ -2800,23 +2912,27 @@ dc_rxeof(struct dc_softc *sc)
|
||||
* if the allocation fails, then use m_devget and leave the
|
||||
* existing buffer in the receive ring.
|
||||
*/
|
||||
if (dc_newbuf(sc, i, 1) == 0) {
|
||||
if (dc_newbuf(sc, i) != 0) {
|
||||
dc_discard_rxbuf(sc, i);
|
||||
ifp->if_iqdrops++;
|
||||
continue;
|
||||
}
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
m->m_pkthdr.len = m->m_len = total_len;
|
||||
DC_INC(i, DC_RX_LIST_CNT);
|
||||
} else
|
||||
#endif
|
||||
#else
|
||||
{
|
||||
struct mbuf *m0;
|
||||
|
||||
m0 = m_devget(mtod(m, char *), total_len,
|
||||
ETHER_ALIGN, ifp, NULL);
|
||||
dc_newbuf(sc, i, 0);
|
||||
DC_INC(i, DC_RX_LIST_CNT);
|
||||
dc_discard_rxbuf(sc, i);
|
||||
if (m0 == NULL) {
|
||||
ifp->if_ierrors++;
|
||||
ifp->if_iqdrops++;
|
||||
continue;
|
||||
}
|
||||
m = m0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ifp->if_ipackets++;
|
||||
DC_UNLOCK(sc);
|
||||
@ -2836,9 +2952,9 @@ dc_rxeof(struct dc_softc *sc)
|
||||
static void
|
||||
dc_txeof(struct dc_softc *sc)
|
||||
{
|
||||
struct dc_desc *cur_tx = NULL;
|
||||
struct dc_desc *cur_tx;
|
||||
struct ifnet *ifp;
|
||||
int idx;
|
||||
int idx, setup;
|
||||
u_int32_t ctl, txstat;
|
||||
|
||||
if (sc->dc_cdata.dc_tx_cnt == 0)
|
||||
@ -2850,19 +2966,26 @@ dc_txeof(struct dc_softc *sc)
|
||||
* Go through our tx list and free mbufs for those
|
||||
* frames that have been transmitted.
|
||||
*/
|
||||
bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_POSTREAD);
|
||||
idx = sc->dc_cdata.dc_tx_cons;
|
||||
while (idx != sc->dc_cdata.dc_tx_prod) {
|
||||
|
||||
cur_tx = &sc->dc_ldata->dc_tx_list[idx];
|
||||
bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_tx_lmap, BUS_DMASYNC_POSTREAD |
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
setup = 0;
|
||||
for (idx = sc->dc_cdata.dc_tx_cons; idx != sc->dc_cdata.dc_tx_prod;
|
||||
DC_INC(idx, DC_TX_LIST_CNT), sc->dc_cdata.dc_tx_cnt--) {
|
||||
cur_tx = &sc->dc_ldata.dc_tx_list[idx];
|
||||
txstat = le32toh(cur_tx->dc_status);
|
||||
ctl = le32toh(cur_tx->dc_ctl);
|
||||
|
||||
if (txstat & DC_TXSTAT_OWN)
|
||||
break;
|
||||
|
||||
if (!(ctl & DC_TXCTL_LASTFRAG) || ctl & DC_TXCTL_SETUP) {
|
||||
if (sc->dc_cdata.dc_tx_chain[idx] == NULL)
|
||||
continue;
|
||||
|
||||
if (ctl & DC_TXCTL_SETUP) {
|
||||
cur_tx->dc_ctl = htole32(ctl & ~DC_TXCTL_SETUP);
|
||||
setup++;
|
||||
bus_dmamap_sync(sc->dc_stag, sc->dc_smap,
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
/*
|
||||
* Yes, the PNIC is so brain damaged
|
||||
* that it will sometimes generate a TX
|
||||
@ -2877,9 +3000,6 @@ dc_txeof(struct dc_softc *sc)
|
||||
dc_setfilt(sc);
|
||||
}
|
||||
sc->dc_cdata.dc_tx_chain[idx] = NULL;
|
||||
}
|
||||
sc->dc_cdata.dc_tx_cnt--;
|
||||
DC_INC(idx, DC_TX_LIST_CNT);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2919,27 +3039,23 @@ dc_txeof(struct dc_softc *sc)
|
||||
ifp->if_opackets++;
|
||||
ifp->if_collisions += (txstat & DC_TXSTAT_COLLCNT) >> 3;
|
||||
|
||||
if (sc->dc_cdata.dc_tx_chain[idx] != NULL) {
|
||||
bus_dmamap_sync(sc->dc_mtag,
|
||||
sc->dc_cdata.dc_tx_map[idx],
|
||||
bus_dmamap_sync(sc->dc_tx_mtag, sc->dc_cdata.dc_tx_map[idx],
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
bus_dmamap_unload(sc->dc_mtag,
|
||||
sc->dc_cdata.dc_tx_map[idx]);
|
||||
bus_dmamap_unload(sc->dc_tx_mtag, sc->dc_cdata.dc_tx_map[idx]);
|
||||
m_freem(sc->dc_cdata.dc_tx_chain[idx]);
|
||||
sc->dc_cdata.dc_tx_chain[idx] = NULL;
|
||||
}
|
||||
|
||||
sc->dc_cdata.dc_tx_cnt--;
|
||||
DC_INC(idx, DC_TX_LIST_CNT);
|
||||
}
|
||||
sc->dc_cdata.dc_tx_cons = idx;
|
||||
|
||||
if (DC_TX_LIST_CNT - sc->dc_cdata.dc_tx_cnt > DC_TX_LIST_RSVD)
|
||||
if (sc->dc_cdata.dc_tx_cnt <= DC_TX_LIST_CNT - DC_TX_LIST_RSVD) {
|
||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
||||
|
||||
if (sc->dc_cdata.dc_tx_cnt == 0)
|
||||
sc->dc_wdog_timer = 0;
|
||||
}
|
||||
if (setup > 0)
|
||||
bus_dmamap_sync(sc->dc_tx_ltag, sc->dc_tx_lmap,
|
||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
||||
}
|
||||
|
||||
static void
|
||||
dc_tick(void *xsc)
|
||||
@ -3226,16 +3342,11 @@ static int
|
||||
dc_encap(struct dc_softc *sc, struct mbuf **m_head)
|
||||
{
|
||||
bus_dma_segment_t segs[DC_MAXFRAGS];
|
||||
bus_dmamap_t map;
|
||||
struct dc_desc *f;
|
||||
struct mbuf *m;
|
||||
int cur, defragged, error, first, frag, i, idx, nseg;
|
||||
|
||||
/*
|
||||
* If there's no way we can send any packets, return now.
|
||||
*/
|
||||
if (DC_TX_LIST_CNT - sc->dc_cdata.dc_tx_cnt <= DC_TX_LIST_RSVD)
|
||||
return (ENOBUFS);
|
||||
|
||||
m = NULL;
|
||||
defragged = 0;
|
||||
if (sc->dc_flags & DC_TX_COALESCE &&
|
||||
@ -3269,7 +3380,7 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head)
|
||||
}
|
||||
|
||||
idx = sc->dc_cdata.dc_tx_prod;
|
||||
error = bus_dmamap_load_mbuf_sg(sc->dc_mtag,
|
||||
error = bus_dmamap_load_mbuf_sg(sc->dc_tx_mtag,
|
||||
sc->dc_cdata.dc_tx_map[idx], *m_head, segs, &nseg, 0);
|
||||
if (error == EFBIG) {
|
||||
if (defragged != 0 || (m = m_collapse(*m_head, M_DONTWAIT,
|
||||
@ -3279,7 +3390,7 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head)
|
||||
return (defragged != 0 ? error : ENOBUFS);
|
||||
}
|
||||
*m_head = m;
|
||||
error = bus_dmamap_load_mbuf_sg(sc->dc_mtag,
|
||||
error = bus_dmamap_load_mbuf_sg(sc->dc_tx_mtag,
|
||||
sc->dc_cdata.dc_tx_map[idx], *m_head, segs, &nseg, 0);
|
||||
if (error != 0) {
|
||||
m_freem(*m_head);
|
||||
@ -3296,26 +3407,34 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head)
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
/* Check descriptor overruns. */
|
||||
if (sc->dc_cdata.dc_tx_cnt + nseg > DC_TX_LIST_CNT - DC_TX_LIST_RSVD) {
|
||||
bus_dmamap_unload(sc->dc_tx_mtag, sc->dc_cdata.dc_tx_map[idx]);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
bus_dmamap_sync(sc->dc_tx_mtag, sc->dc_cdata.dc_tx_map[idx],
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
|
||||
first = cur = frag = sc->dc_cdata.dc_tx_prod;
|
||||
for (i = 0; i < nseg; i++) {
|
||||
if ((sc->dc_flags & DC_TX_ADMTEK_WAR) &&
|
||||
(frag == (DC_TX_LIST_CNT - 1)) &&
|
||||
(first != sc->dc_cdata.dc_tx_first)) {
|
||||
bus_dmamap_unload(sc->dc_mtag,
|
||||
bus_dmamap_unload(sc->dc_tx_mtag,
|
||||
sc->dc_cdata.dc_tx_map[first]);
|
||||
m_freem(*m_head);
|
||||
*m_head = NULL;
|
||||
return (ENOBUFS);
|
||||
}
|
||||
|
||||
f = &sc->dc_ldata->dc_tx_list[frag];
|
||||
f = &sc->dc_ldata.dc_tx_list[frag];
|
||||
f->dc_ctl = htole32(DC_TXCTL_TLINK | segs[i].ds_len);
|
||||
if (i == 0) {
|
||||
f->dc_status = 0;
|
||||
f->dc_ctl |= htole32(DC_TXCTL_FIRSTFRAG);
|
||||
} else
|
||||
f->dc_status = htole32(DC_TXSTAT_OWN);
|
||||
f->dc_data = htole32(segs[i].ds_addr);
|
||||
f->dc_data = htole32(DC_ADDR_LO(segs[i].ds_addr));
|
||||
cur = frag;
|
||||
DC_INC(frag, DC_TX_LIST_CNT);
|
||||
}
|
||||
@ -3323,23 +3442,30 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head)
|
||||
sc->dc_cdata.dc_tx_prod = frag;
|
||||
sc->dc_cdata.dc_tx_cnt += nseg;
|
||||
sc->dc_cdata.dc_tx_chain[cur] = *m_head;
|
||||
sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG);
|
||||
sc->dc_ldata.dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG);
|
||||
if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG)
|
||||
sc->dc_ldata->dc_tx_list[first].dc_ctl |=
|
||||
sc->dc_ldata.dc_tx_list[first].dc_ctl |=
|
||||
htole32(DC_TXCTL_FINT);
|
||||
if (sc->dc_flags & DC_TX_INTR_ALWAYS)
|
||||
sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT);
|
||||
sc->dc_ldata.dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT);
|
||||
if (sc->dc_flags & DC_TX_USE_TX_INTR &&
|
||||
++sc->dc_cdata.dc_tx_pkts >= 8) {
|
||||
sc->dc_cdata.dc_tx_pkts = 0;
|
||||
sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT);
|
||||
sc->dc_ldata.dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT);
|
||||
}
|
||||
sc->dc_ldata->dc_tx_list[first].dc_status = htole32(DC_TXSTAT_OWN);
|
||||
sc->dc_ldata.dc_tx_list[first].dc_status = htole32(DC_TXSTAT_OWN);
|
||||
|
||||
bus_dmamap_sync(sc->dc_tx_ltag, sc->dc_tx_lmap,
|
||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
||||
|
||||
/*
|
||||
* Swap the last and the first dmamaps to ensure the map for
|
||||
* this transmission is placed at the last descriptor.
|
||||
*/
|
||||
map = sc->dc_cdata.dc_tx_map[cur];
|
||||
sc->dc_cdata.dc_tx_map[cur] = sc->dc_cdata.dc_tx_map[first];
|
||||
sc->dc_cdata.dc_tx_map[first] = map;
|
||||
|
||||
bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx],
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap,
|
||||
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -3365,9 +3491,8 @@ static void
|
||||
dc_start_locked(struct ifnet *ifp)
|
||||
{
|
||||
struct dc_softc *sc;
|
||||
struct mbuf *m_head = NULL;
|
||||
unsigned int queued = 0;
|
||||
int idx;
|
||||
struct mbuf *m_head;
|
||||
int queued;
|
||||
|
||||
sc = ifp->if_softc;
|
||||
|
||||
@ -3377,9 +3502,16 @@ dc_start_locked(struct ifnet *ifp)
|
||||
IFF_DRV_RUNNING || sc->dc_link == 0)
|
||||
return;
|
||||
|
||||
idx = sc->dc_cdata.dc_tx_first = sc->dc_cdata.dc_tx_prod;
|
||||
sc->dc_cdata.dc_tx_first = sc->dc_cdata.dc_tx_prod;
|
||||
|
||||
while (sc->dc_cdata.dc_tx_chain[idx] == NULL) {
|
||||
for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) {
|
||||
/*
|
||||
* If there's no way we can send any packets, return now.
|
||||
*/
|
||||
if (sc->dc_cdata.dc_tx_cnt > DC_TX_LIST_CNT - DC_TX_LIST_RSVD) {
|
||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
||||
break;
|
||||
}
|
||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
|
||||
if (m_head == NULL)
|
||||
break;
|
||||
@ -3391,7 +3523,6 @@ dc_start_locked(struct ifnet *ifp)
|
||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
||||
break;
|
||||
}
|
||||
idx = sc->dc_cdata.dc_tx_prod;
|
||||
|
||||
queued++;
|
||||
/*
|
||||
@ -3778,7 +3909,7 @@ dc_stop(struct dc_softc *sc)
|
||||
DC_LOCK_ASSERT(sc);
|
||||
|
||||
ifp = sc->dc_ifp;
|
||||
ld = sc->dc_ldata;
|
||||
ld = &sc->dc_ldata;
|
||||
cd = &sc->dc_cdata;
|
||||
|
||||
callout_stop(&sc->dc_stat_ch);
|
||||
@ -3798,11 +3929,17 @@ dc_stop(struct dc_softc *sc)
|
||||
*/
|
||||
for (i = 0; i < DC_RX_LIST_CNT; i++) {
|
||||
if (cd->dc_rx_chain[i] != NULL) {
|
||||
bus_dmamap_sync(sc->dc_rx_mtag,
|
||||
cd->dc_rx_map[i], BUS_DMASYNC_POSTREAD);
|
||||
bus_dmamap_unload(sc->dc_rx_mtag,
|
||||
cd->dc_rx_map[i]);
|
||||
m_freem(cd->dc_rx_chain[i]);
|
||||
cd->dc_rx_chain[i] = NULL;
|
||||
}
|
||||
}
|
||||
bzero(&ld->dc_rx_list, sizeof(ld->dc_rx_list));
|
||||
bzero(ld->dc_rx_list, DC_RX_LIST_SZ);
|
||||
bus_dmamap_sync(sc->dc_rx_ltag, sc->dc_rx_lmap,
|
||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
||||
|
||||
/*
|
||||
* Free the TX list buffers.
|
||||
@ -3810,17 +3947,22 @@ dc_stop(struct dc_softc *sc)
|
||||
for (i = 0; i < DC_TX_LIST_CNT; i++) {
|
||||
if (cd->dc_tx_chain[i] != NULL) {
|
||||
ctl = le32toh(ld->dc_tx_list[i].dc_ctl);
|
||||
if ((ctl & DC_TXCTL_SETUP) ||
|
||||
!(ctl & DC_TXCTL_LASTFRAG)) {
|
||||
cd->dc_tx_chain[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
bus_dmamap_unload(sc->dc_mtag, cd->dc_tx_map[i]);
|
||||
if (ctl & DC_TXCTL_SETUP) {
|
||||
bus_dmamap_sync(sc->dc_stag, sc->dc_smap,
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
} else {
|
||||
bus_dmamap_sync(sc->dc_tx_mtag,
|
||||
cd->dc_tx_map[i], BUS_DMASYNC_POSTWRITE);
|
||||
bus_dmamap_unload(sc->dc_tx_mtag,
|
||||
cd->dc_tx_map[i]);
|
||||
m_freem(cd->dc_tx_chain[i]);
|
||||
}
|
||||
cd->dc_tx_chain[i] = NULL;
|
||||
}
|
||||
}
|
||||
bzero(&ld->dc_tx_list, sizeof(ld->dc_tx_list));
|
||||
bzero(ld->dc_tx_list, DC_TX_LIST_SZ);
|
||||
bus_dmamap_sync(sc->dc_tx_ltag, sc->dc_tx_lmap,
|
||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -471,11 +471,15 @@ struct dc_desc {
|
||||
|
||||
#define DC_INC(x, y) (x) = (x + 1) % y
|
||||
|
||||
#define DC_LIST_ALIGN (sizeof(struct dc_desc))
|
||||
#define DC_RXBUF_ALIGN 4
|
||||
|
||||
/* Macros to easily get the DMA address of a descriptor. */
|
||||
#define DC_RXDESC(sc, i) (sc->dc_laddr + \
|
||||
(uintptr_t)(sc->dc_ldata->dc_rx_list + i) - (uintptr_t)sc->dc_ldata)
|
||||
#define DC_TXDESC(sc, i) (sc->dc_laddr + \
|
||||
(uintptr_t)(sc->dc_ldata->dc_tx_list + i) - (uintptr_t)sc->dc_ldata)
|
||||
#define DC_ADDR_LO(x) ((uint64_t)(x) & 0xFFFFFFFF)
|
||||
#define DC_RXDESC(sc, i) \
|
||||
(DC_ADDR_LO(sc->dc_ldata.dc_rx_list_paddr + (sizeof(struct dc_desc) * i)))
|
||||
#define DC_TXDESC(sc, i) \
|
||||
(DC_ADDR_LO(sc->dc_ldata.dc_tx_list_paddr + (sizeof(struct dc_desc) * i)))
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define DC_SP_MAC(x) ((x) << 16)
|
||||
@ -484,10 +488,15 @@ struct dc_desc {
|
||||
#endif
|
||||
|
||||
struct dc_list_data {
|
||||
struct dc_desc dc_rx_list[DC_RX_LIST_CNT];
|
||||
struct dc_desc dc_tx_list[DC_TX_LIST_CNT];
|
||||
struct dc_desc *dc_rx_list;
|
||||
bus_addr_t dc_rx_list_paddr;
|
||||
struct dc_desc *dc_tx_list;
|
||||
bus_addr_t dc_tx_list_paddr;
|
||||
};
|
||||
|
||||
#define DC_RX_LIST_SZ ((sizeof(struct dc_desc) * DC_RX_LIST_CNT))
|
||||
#define DC_TX_LIST_SZ ((sizeof(struct dc_desc) * DC_TX_LIST_CNT))
|
||||
|
||||
struct dc_chain_data {
|
||||
struct mbuf *dc_rx_chain[DC_RX_LIST_CNT];
|
||||
struct mbuf *dc_tx_chain[DC_TX_LIST_CNT];
|
||||
@ -722,14 +731,17 @@ struct dc_softc {
|
||||
device_t dc_dev; /* device info */
|
||||
bus_space_handle_t dc_bhandle; /* bus space handle */
|
||||
bus_space_tag_t dc_btag; /* bus space tag */
|
||||
bus_dma_tag_t dc_ltag; /* tag for descriptor ring */
|
||||
bus_dmamap_t dc_lmap; /* map for descriptor ring */
|
||||
u_int32_t dc_laddr; /* DMA address of dc_ldata */
|
||||
bus_dma_tag_t dc_mtag; /* tag for mbufs */
|
||||
bus_dma_tag_t dc_ptag; /* parent DMA tag */
|
||||
bus_dmamap_t dc_sparemap;
|
||||
bus_dma_tag_t dc_rx_ltag; /* tag for RX descriptors */
|
||||
bus_dmamap_t dc_rx_lmap;
|
||||
bus_dma_tag_t dc_tx_ltag; /* tag for TX descriptors */
|
||||
bus_dmamap_t dc_tx_lmap;
|
||||
bus_dma_tag_t dc_stag; /* tag for the setup frame */
|
||||
bus_dmamap_t dc_smap; /* map for the setup frame */
|
||||
u_int32_t dc_saddr; /* DMA address of setup frame */
|
||||
bus_addr_t dc_saddr; /* DMA address of setup frame */
|
||||
bus_dma_tag_t dc_rx_mtag; /* tag for RX mbufs */
|
||||
bus_dma_tag_t dc_tx_mtag; /* tag for TX mbufs */
|
||||
void *dc_intrhand;
|
||||
struct resource *dc_irq;
|
||||
struct resource *dc_res;
|
||||
@ -749,7 +761,7 @@ struct dc_softc {
|
||||
u_int32_t dc_eaddr[2];
|
||||
u_int8_t *dc_srom;
|
||||
struct dc_mediainfo *dc_mi;
|
||||
struct dc_list_data *dc_ldata;
|
||||
struct dc_list_data dc_ldata;
|
||||
struct dc_chain_data dc_cdata;
|
||||
struct callout dc_stat_ch;
|
||||
struct callout dc_wdog_ch;
|
||||
@ -796,7 +808,6 @@ struct dc_softc {
|
||||
bus_space_barrier(sc->dc_btag, sc->dc_bhandle, reg, 4, flags)
|
||||
|
||||
#define DC_TIMEOUT 1000
|
||||
#define ETHER_ALIGN 2
|
||||
|
||||
/*
|
||||
* General constants that are fun to know.
|
||||
|
Loading…
Reference in New Issue
Block a user