if_dwc: Checksum offload

This commit is contained in:
Sebastian Huber 2015-03-30 14:30:04 +02:00
parent 5deeb69c7e
commit b99c023a08
2 changed files with 62 additions and 5 deletions

View File

@ -102,13 +102,22 @@ __FBSDID("$FreeBSD$");
#define DDESC_TDES0_TXLAST (1U << 29) #define DDESC_TDES0_TXLAST (1U << 29)
#define DDESC_TDES0_TXFIRST (1U << 28) #define DDESC_TDES0_TXFIRST (1U << 28)
#define DDESC_TDES0_TXCRCDIS (1U << 27) #define DDESC_TDES0_TXCRCDIS (1U << 27)
#define DDESC_TDES0_CIC_IP_HDR (0x1U << 22)
#define DDESC_TDES0_CIC_IP_HDR_PYL (0x2U << 22)
#define DDESC_TDES0_CIC_IP_HDR_PYL_PHDR (0x3U << 22)
#define DDESC_TDES0_TXRINGEND (1U << 21) #define DDESC_TDES0_TXRINGEND (1U << 21)
#define DDESC_TDES0_TXCHAIN (1U << 20) #define DDESC_TDES0_TXCHAIN (1U << 20)
#define DDESC_RDES0_OWN (1U << 31) #define DDESC_RDES0_OWN (1U << 31)
#define DDESC_RDES0_FL_MASK 0x3fff #define DDESC_RDES0_FL_MASK 0x3fff
#define DDESC_RDES0_FL_SHIFT 16 /* Frame Length */ #define DDESC_RDES0_FL_SHIFT 16 /* Frame Length */
#define DDESC_RDES0_ESA (1U << 0)
#define DDESC_RDES1_CHAINED (1U << 14) #define DDESC_RDES1_CHAINED (1U << 14)
#define DDESC_RDES4_IP_PYL_ERR (1U << 4)
#define DDESC_RDES4_IP_HDR_ERR (1U << 3)
#define DDESC_RDES4_IP_PYL_TYPE_MSK 0x7U
#define DDESC_RDES4_IP_PYL_UDP 1U
#define DDESC_RDES4_IP_PYL_TCP 2U
/* Alt descriptor bits. */ /* Alt descriptor bits. */
#define DDESC_CNTL_TXINT (1U << 31) #define DDESC_CNTL_TXINT (1U << 31)
@ -130,6 +139,10 @@ struct dwc_hwdesc
uint32_t tdes1; /* cntl for alt layout */ uint32_t tdes1; /* cntl for alt layout */
uint32_t addr; /* pointer to buffer data */ uint32_t addr; /* pointer to buffer data */
uint32_t addr_next; /* link to next descriptor */ uint32_t addr_next; /* link to next descriptor */
uint32_t tdes4;
uint32_t tdes5;
uint32_t timestamp_low;
uint32_t timestamp_high;
}; };
/* /*
@ -138,6 +151,9 @@ struct dwc_hwdesc
*/ */
#define DWC_DESC_RING_ALIGN 2048 #define DWC_DESC_RING_ALIGN 2048
#define DWC_CKSUM_ASSIST (CSUM_IP | CSUM_TCP | CSUM_UDP | \
CSUM_TCP_IPV6 | CSUM_UDP_IPV6)
static struct resource_spec dwc_spec[] = { static struct resource_spec dwc_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE },
@ -173,8 +189,8 @@ dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
} }
static void static void
dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_dma_segment_t segs[TX_MAX_DMA_SEGS], dwc_setup_txdesc(struct dwc_softc *sc, int csum_flags, int idx,
int nsegs) bus_dma_segment_t segs[TX_MAX_DMA_SEGS], int nsegs)
{ {
int i; int i;
@ -211,9 +227,17 @@ dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_dma_segment_t segs[TX_MAX_DM
flags = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXINT | flags = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXINT |
DDESC_TDES0_OWN; DDESC_TDES0_OWN;
if (i == 0) if (i == 0) {
flags |= DDESC_TDES0_TXFIRST; flags |= DDESC_TDES0_TXFIRST;
if ((csum_flags & (CSUM_TCP | CSUM_UDP |
CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) != 0)
flags |=
DDESC_TDES0_CIC_IP_HDR_PYL_PHDR;
else if ((csum_flags & CSUM_IP) != 0)
flags |= DDESC_TDES0_CIC_IP_HDR;
}
if (i == nsegs - 1) if (i == nsegs - 1)
flags |= DDESC_TDES0_TXLAST; flags |= DDESC_TDES0_TXLAST;
@ -262,7 +286,7 @@ dwc_setup_txbuf(struct dwc_softc *sc, struct mbuf *m, int *start_tx)
bus_dmamap_sync(sc->txbuf_tag, sc->txbuf_map[idx].map, bus_dmamap_sync(sc->txbuf_tag, sc->txbuf_map[idx].map,
BUS_DMASYNC_PREWRITE); BUS_DMASYNC_PREWRITE);
dwc_setup_txdesc(sc, idx, segs, nsegs); dwc_setup_txdesc(sc, m->m_pkthdr.csum_flags, idx, segs, nsegs);
ETHER_BPF_MTAP(sc->ifp, m); ETHER_BPF_MTAP(sc->ifp, m);
*start_tx = 1; *start_tx = 1;
@ -462,6 +486,7 @@ dwc_init_locked(struct dwc_softc *sc)
/* Enable transmitters */ /* Enable transmitters */
reg = READ4(sc, MAC_CONFIGURATION); reg = READ4(sc, MAC_CONFIGURATION);
reg |= (CONF_IPC);
reg |= (CONF_JD | CONF_ACS | CONF_BE); reg |= (CONF_JD | CONF_ACS | CONF_BE);
reg |= (CONF_TE | CONF_RE); reg |= (CONF_TE | CONF_RE);
WRITE4(sc, MAC_CONFIGURATION, reg); WRITE4(sc, MAC_CONFIGURATION, reg);
@ -770,6 +795,7 @@ dwc_rxfinish_locked(struct dwc_softc *sc)
struct mbuf *m; struct mbuf *m;
int error, idx, len; int error, idx, len;
uint32_t rdes0; uint32_t rdes0;
uint32_t rdes4;
ifp = sc->ifp; ifp = sc->ifp;
@ -791,6 +817,31 @@ dwc_rxfinish_locked(struct dwc_softc *sc)
m->m_pkthdr.len = len; m->m_pkthdr.len = len;
m->m_len = len; m->m_len = len;
/* Check checksum offload flags. */
if ((rdes0 & DDESC_RDES0_ESA) != 0) {
rdes4 = sc->rxdesc_ring[idx].tdes4;
/* TCP or UDP checks out, IP checks out too. */
if ((rdes4 & DDESC_RDES4_IP_PYL_TYPE_MSK) ==
DDESC_RDES4_IP_PYL_UDP ||
(rdes4 & DDESC_RDES4_IP_PYL_TYPE_MSK) ==
DDESC_RDES4_IP_PYL_TCP) {
m->m_pkthdr.csum_flags |=
CSUM_IP_CHECKED |
CSUM_IP_VALID |
CSUM_DATA_VALID |
CSUM_PSEUDO_HDR;
m->m_pkthdr.csum_data = 0xffff;
} else if ((rdes4 & (DDESC_RDES4_IP_PYL_ERR |
DDESC_RDES4_IP_HDR_ERR)) == 0) {
/* Only IP checks out. */
m->m_pkthdr.csum_flags |=
CSUM_IP_CHECKED |
CSUM_IP_VALID;
m->m_pkthdr.csum_data = 0xffff;
}
}
/* Remove trailing FCS */ /* Remove trailing FCS */
m_adj(m, -ETHER_CRC_LEN); m_adj(m, -ETHER_CRC_LEN);
@ -1014,6 +1065,7 @@ setup_dma(struct dwc_softc *sc)
"could not create new RX buffer.\n"); "could not create new RX buffer.\n");
goto out; goto out;
} }
sc->rxdesc_ring[idx].tdes4 = 0;
} }
out: out:
@ -1229,6 +1281,7 @@ dwc_attach(device_t dev)
} else } else
reg = (BUS_MODE_EIGHTXPBL); reg = (BUS_MODE_EIGHTXPBL);
reg |= (BUS_MODE_PBL_BEATS_8 << BUS_MODE_PBL_SHIFT); reg |= (BUS_MODE_PBL_BEATS_8 << BUS_MODE_PBL_SHIFT);
reg |= (BUS_MODE_ATDS);
WRITE4(sc, BUS_MODE, reg); WRITE4(sc, BUS_MODE, reg);
/* /*
@ -1256,8 +1309,10 @@ dwc_attach(device_t dev)
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_capabilities = IFCAP_VLAN_MTU; ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 |
IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM;
ifp->if_capenable = ifp->if_capabilities; ifp->if_capenable = ifp->if_capabilities;
ifp->if_hwassist = DWC_CKSUM_ASSIST;
ifp->if_start = dwc_txstart; ifp->if_start = dwc_txstart;
ifp->if_ioctl = dwc_ioctl; ifp->if_ioctl = dwc_ioctl;
ifp->if_init = dwc_init; ifp->if_init = dwc_init;

View File

@ -43,6 +43,7 @@
#define CONF_PS (1 << 15) /* GMII/MII */ #define CONF_PS (1 << 15) /* GMII/MII */
#define CONF_FES (1 << 14) /* MII speed select */ #define CONF_FES (1 << 14) /* MII speed select */
#define CONF_DM (1 << 11) /* Full Duplex Enable */ #define CONF_DM (1 << 11) /* Full Duplex Enable */
#define CONF_IPC (1 << 10) /* Checksum Enable */
#define CONF_ACS (1 << 7) #define CONF_ACS (1 << 7)
#define CONF_TE (1 << 3) #define CONF_TE (1 << 3)
#define CONF_RE (1 << 2) #define CONF_RE (1 << 2)
@ -220,6 +221,7 @@
#define BUS_MODE_PRIORXTX_11 0 #define BUS_MODE_PRIORXTX_11 0
#define BUS_MODE_PBL_SHIFT 8 /* Single block transfer size */ #define BUS_MODE_PBL_SHIFT 8 /* Single block transfer size */
#define BUS_MODE_PBL_BEATS_8 8 #define BUS_MODE_PBL_BEATS_8 8
#define BUS_MODE_ATDS (1 << 7) /* Alternate Descriptor Size */
#define BUS_MODE_SWR (1 << 0) /* Reset */ #define BUS_MODE_SWR (1 << 0) /* Reset */
#define TRANSMIT_POLL_DEMAND 0x1004 #define TRANSMIT_POLL_DEMAND 0x1004
#define RECEIVE_POLL_DEMAND 0x1008 #define RECEIVE_POLL_DEMAND 0x1008