Changeset View
Changeset View
Standalone View
Standalone View
sys/mips/atheros/ar531x/if_are.c
Show First 20 Lines • Show All 296 Lines • ▼ Show 20 Lines | #endif | ||||
ifp->if_softc = sc; | ifp->if_softc = sc; | ||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | ||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ||||
ifp->if_ioctl = are_ioctl; | ifp->if_ioctl = are_ioctl; | ||||
ifp->if_start = are_start; | ifp->if_start = are_start; | ||||
ifp->if_init = are_init; | ifp->if_init = are_init; | ||||
sc->are_if_flags = ifp->if_flags; | sc->are_if_flags = ifp->if_flags; | ||||
/* XXX: add real size */ | /* XXX: add real size */ | ||||
mizhka: Is it worth to remove this comment? | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, 9); | IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | ||||
ifp->if_snd.ifq_maxlen = 9; | ifp->if_snd.ifq_maxlen = ifqmaxlen; | ||||
IFQ_SET_READY(&ifp->if_snd); | IFQ_SET_READY(&ifp->if_snd); | ||||
/* Tell the upper layer(s) we support long frames. */ | /* Tell the upper layer(s) we support long frames. */ | ||||
ifp->if_capabilities |= IFCAP_VLAN_MTU; | ifp->if_capabilities |= IFCAP_VLAN_MTU; | ||||
ifp->if_capenable = ifp->if_capabilities; | ifp->if_capenable = ifp->if_capabilities; | ||||
if (are_dma_alloc(sc) != 0) { | if (are_dma_alloc(sc) != 0) { | ||||
▲ Show 20 Lines • Show All 365 Lines • ▼ Show 20 Lines | |||||
* Encapsulate an mbuf chain in a descriptor by coupling the mbuf data | * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data | ||||
* pointers to the fragment pointers. | * pointers to the fragment pointers. | ||||
*/ | */ | ||||
static int | static int | ||||
are_encap(struct are_softc *sc, struct mbuf **m_head) | are_encap(struct are_softc *sc, struct mbuf **m_head) | ||||
{ | { | ||||
struct are_txdesc *txd; | struct are_txdesc *txd; | ||||
struct are_desc *desc, *prev_desc; | struct are_desc *desc, *prev_desc; | ||||
struct mbuf *m; | |||||
bus_dma_segment_t txsegs[ARE_MAXFRAGS]; | bus_dma_segment_t txsegs[ARE_MAXFRAGS]; | ||||
uint32_t link_addr; | uint32_t link_addr; | ||||
int error, i, nsegs, prod, si, prev_prod; | int error, i, nsegs, prod, si, prev_prod; | ||||
int txstat; | int txstat; | ||||
int startcount; | |||||
int padlen; | |||||
startcount = sc->are_cdata.are_tx_cnt; | |||||
ARE_LOCK_ASSERT(sc); | ARE_LOCK_ASSERT(sc); | ||||
/* | |||||
* Some VIA Rhine wants packet buffers to be longword | |||||
* aligned, but very often our mbufs aren't. Rather than | |||||
* waste time trying to decide when to copy and when not | |||||
* to copy, just do it all the time. | |||||
*/ | |||||
m = m_defrag(*m_head, M_NOWAIT); | |||||
if (m == NULL) { | |||||
device_printf(sc->are_dev, "are_encap m_defrag error\n"); | |||||
m_freem(*m_head); | |||||
*m_head = NULL; | |||||
return (ENOBUFS); | |||||
} | |||||
*m_head = m; | |||||
/* | |||||
* The Rhine chip doesn't auto-pad, so we have to make | |||||
* sure to pad short frames out to the minimum frame length | |||||
* ourselves. | |||||
*/ | |||||
if ((*m_head)->m_pkthdr.len < ARE_MIN_FRAMELEN) { | |||||
m = *m_head; | |||||
padlen = ARE_MIN_FRAMELEN - m->m_pkthdr.len; | |||||
if (M_WRITABLE(m) == 0) { | |||||
/* Get a writable copy. */ | |||||
m = m_dup(*m_head, M_NOWAIT); | |||||
m_freem(*m_head); | |||||
if (m == NULL) { | |||||
device_printf(sc->are_dev, "are_encap m_dup error\n"); | |||||
*m_head = NULL; | |||||
return (ENOBUFS); | |||||
} | |||||
*m_head = m; | |||||
} | |||||
if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) { | |||||
m = m_defrag(m, M_NOWAIT); | |||||
if (m == NULL) { | |||||
device_printf(sc->are_dev, "are_encap m_defrag error\n"); | |||||
m_freem(*m_head); | |||||
*m_head = NULL; | |||||
return (ENOBUFS); | |||||
} | |||||
} | |||||
/* | |||||
* Manually pad short frames, and zero the pad space | |||||
* to avoid leaking data. | |||||
*/ | |||||
bzero(mtod(m, char *) + m->m_pkthdr.len, padlen); | |||||
m->m_pkthdr.len += padlen; | |||||
m->m_len = m->m_pkthdr.len; | |||||
*m_head = m; | |||||
} | |||||
prod = sc->are_cdata.are_tx_prod; | prod = sc->are_cdata.are_tx_prod; | ||||
txd = &sc->are_cdata.are_txdesc[prod]; | txd = &sc->are_cdata.are_txdesc[prod]; | ||||
error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag, txd->tx_dmamap, | error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag, | ||||
*m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); | txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); | ||||
if (error == EFBIG) { | if (error == EFBIG) { | ||||
panic("EFBIG"); | device_printf(sc->are_dev, "are_encap EFBIG error\n"); | ||||
m = m_defrag(*m_head, M_NOWAIT); | |||||
if (m == NULL) { | |||||
m_freem(*m_head); | |||||
*m_head = NULL; | |||||
return (ENOBUFS); | |||||
} | |||||
*m_head = m; | |||||
error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag, | |||||
txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); | |||||
if (error != 0) { | |||||
m_freem(*m_head); | |||||
*m_head = NULL; | |||||
return (error); | |||||
} | |||||
} else if (error != 0) | } else if (error != 0) | ||||
return (error); | return (error); | ||||
if (nsegs == 0) { | if (nsegs == 0) { | ||||
m_freem(*m_head); | m_freem(*m_head); | ||||
*m_head = NULL; | *m_head = NULL; | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
Show All 14 Lines | are_encap(struct are_softc *sc, struct mbuf **m_head) | ||||
* walk through it while are_link is not zero. The last one should | * walk through it while are_link is not zero. The last one should | ||||
* have COF flag set, to pickup next chain from NDPTR | * have COF flag set, to pickup next chain from NDPTR | ||||
*/ | */ | ||||
prev_prod = prod; | prev_prod = prod; | ||||
desc = prev_desc = NULL; | desc = prev_desc = NULL; | ||||
for (i = 0; i < nsegs; i++) { | for (i = 0; i < nsegs; i++) { | ||||
desc = &sc->are_rdata.are_tx_ring[prod]; | desc = &sc->are_rdata.are_tx_ring[prod]; | ||||
desc->are_stat = ADSTAT_OWN; | desc->are_stat = ADSTAT_OWN; | ||||
desc->are_devcs = ARE_DMASIZE(txsegs[i].ds_len) | ADCTL_CH; | desc->are_devcs = ARE_DMASIZE(txsegs[i].ds_len); | ||||
if (i == 0) | |||||
desc->are_devcs |= ADCTL_Tx_FS; | |||||
desc->are_addr = txsegs[i].ds_addr; | desc->are_addr = txsegs[i].ds_addr; | ||||
/* link with previous descriptor */ | /* link with previous descriptor */ | ||||
if (prev_desc) | /* end of descriptor */ | ||||
prev_desc->are_link = ARE_TX_RING_ADDR(sc, prod); | if (prod == ARE_TX_RING_CNT - 1) | ||||
desc->are_devcs |= ADCTL_ER; | |||||
sc->are_cdata.are_tx_cnt++; | sc->are_cdata.are_tx_cnt++; | ||||
prev_desc = desc; | prev_desc = desc; | ||||
ARE_INC(prod, ARE_TX_RING_CNT); | ARE_INC(prod, ARE_TX_RING_CNT); | ||||
} | } | ||||
/* | /* | ||||
* Set mark last fragment with LD flag | * Set mark last fragment with LD flag | ||||
Show All 9 Lines | are_encap(struct are_softc *sc, struct mbuf **m_head) | ||||
/* Sync descriptors. */ | /* Sync descriptors. */ | ||||
bus_dmamap_sync(sc->are_cdata.are_tx_ring_tag, | bus_dmamap_sync(sc->are_cdata.are_tx_ring_tag, | ||||
sc->are_cdata.are_tx_ring_map, | sc->are_cdata.are_tx_ring_map, | ||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | ||||
/* Start transmitting */ | /* Start transmitting */ | ||||
/* Check if new list is queued in NDPTR */ | /* Check if new list is queued in NDPTR */ | ||||
txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7; | txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7; | ||||
if (txstat == 0 || txstat == 6) { | if (startcount == 0 && (txstat == 0 || txstat == 6)) { | ||||
/* Transmit Process Stat is stop or suspended */ | desc = &sc->are_rdata.are_tx_ring[si]; | ||||
CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD); | desc->are_devcs |= ADCTL_Tx_FS; | ||||
} | } | ||||
else { | else { | ||||
link_addr = ARE_TX_RING_ADDR(sc, si); | link_addr = ARE_TX_RING_ADDR(sc, si); | ||||
/* Get previous descriptor */ | /* Get previous descriptor */ | ||||
si = (si + ARE_TX_RING_CNT - 1) % ARE_TX_RING_CNT; | si = (si + ARE_TX_RING_CNT - 1) % ARE_TX_RING_CNT; | ||||
desc = &sc->are_rdata.are_tx_ring[si]; | desc = &sc->are_rdata.are_tx_ring[si]; | ||||
desc->are_link = link_addr; | desc->are_devcs &= ~(ADCTL_Tx_IC | ADCTL_Tx_LS); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
are_start_locked(struct ifnet *ifp) | are_start_locked(struct ifnet *ifp) | ||||
{ | { | ||||
struct are_softc *sc; | struct are_softc *sc; | ||||
struct mbuf *m_head; | struct mbuf *m_head; | ||||
int enq; | int enq; | ||||
int txstat; | |||||
sc = ifp->if_softc; | sc = ifp->if_softc; | ||||
ARE_LOCK_ASSERT(sc); | ARE_LOCK_ASSERT(sc); | ||||
if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != | if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != | ||||
IFF_DRV_RUNNING || sc->are_link_status == 0 ) | IFF_DRV_RUNNING || sc->are_link_status == 0 ) | ||||
return; | return; | ||||
Show All 17 Lines | for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && | ||||
} | } | ||||
enq++; | enq++; | ||||
/* | /* | ||||
* If there's a BPF listener, bounce a copy of this frame | * If there's a BPF listener, bounce a copy of this frame | ||||
* to him. | * to him. | ||||
*/ | */ | ||||
ETHER_BPF_MTAP(ifp, m_head); | ETHER_BPF_MTAP(ifp, m_head); | ||||
} | |||||
if (enq > 0) { | |||||
txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7; | |||||
if (txstat == 0 || txstat == 6) { | |||||
/* Transmit Process Stat is stop or suspended */ | |||||
CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD); | |||||
} | |||||
} | } | ||||
} | } | ||||
static void | static void | ||||
are_stop(struct are_softc *sc) | are_stop(struct are_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
▲ Show 20 Lines • Show All 856 Lines • Show Last 20 Lines |
Is it worth to remove this comment?