MFC the mxge 10GbE driver.
This commit is contained in:
parent
d14b21a132
commit
3ab81827ae
@ -169,6 +169,7 @@ MAN= aac.4 \
|
||||
msk.4 \
|
||||
mtio.4 \
|
||||
multicast.4 \
|
||||
mxge.4 \
|
||||
my.4 \
|
||||
natm.4 \
|
||||
natmip.4 \
|
||||
@ -461,6 +462,7 @@ MLINKS+=lp.4 plip.4
|
||||
MLINKS+=md.4 vn.4
|
||||
MLINKS+=mem.4 kmem.4
|
||||
MLINKS+=mn.4 if_mn.4
|
||||
MLINKS+=mxge.4 if_mxge.4
|
||||
MLINKS+=my.4 if_my.4
|
||||
MLINKS+=netintro.4 net.4 \
|
||||
netintro.4 networking.4
|
||||
|
@ -1507,197 +1507,6 @@ mxge_submit_req(mxge_tx_buf_t *tx, mcp_kreq_ether_send_t *src,
|
||||
mb();
|
||||
}
|
||||
|
||||
static void
|
||||
mxge_encap_tso(mxge_softc_t *sc, struct mbuf *m, int busdma_seg_cnt,
|
||||
int ip_off)
|
||||
{
|
||||
mxge_tx_buf_t *tx;
|
||||
mcp_kreq_ether_send_t *req;
|
||||
bus_dma_segment_t *seg;
|
||||
struct ip *ip;
|
||||
struct tcphdr *tcp;
|
||||
uint32_t low, high_swapped;
|
||||
int len, seglen, cum_len, cum_len_next;
|
||||
int next_is_first, chop, cnt, rdma_count, small;
|
||||
uint16_t pseudo_hdr_offset, cksum_offset, mss;
|
||||
uint8_t flags, flags_next;
|
||||
static int once;
|
||||
|
||||
mss = m->m_pkthdr.tso_segsz;
|
||||
|
||||
/* negative cum_len signifies to the
|
||||
* send loop that we are still in the
|
||||
* header portion of the TSO packet.
|
||||
*/
|
||||
|
||||
/* ensure we have the ethernet, IP and TCP
|
||||
header together in the first mbuf, copy
|
||||
it to a scratch buffer if not */
|
||||
if (__predict_false(m->m_len < ip_off + sizeof (*ip))) {
|
||||
m_copydata(m, 0, ip_off + sizeof (*ip),
|
||||
sc->scratch);
|
||||
ip = (struct ip *)(sc->scratch + ip_off);
|
||||
} else {
|
||||
ip = (struct ip *)(mtod(m, char *) + ip_off);
|
||||
}
|
||||
if (__predict_false(m->m_len < ip_off + (ip->ip_hl << 2)
|
||||
+ sizeof (*tcp))) {
|
||||
m_copydata(m, 0, ip_off + (ip->ip_hl << 2)
|
||||
+ sizeof (*tcp), sc->scratch);
|
||||
ip = (struct ip *)(mtod(m, char *) + ip_off);
|
||||
}
|
||||
|
||||
tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2));
|
||||
cum_len = -(ip_off + ((ip->ip_hl + tcp->th_off) << 2));
|
||||
|
||||
/* TSO implies checksum offload on this hardware */
|
||||
cksum_offset = ip_off + (ip->ip_hl << 2);
|
||||
flags = MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST;
|
||||
|
||||
|
||||
/* for TSO, pseudo_hdr_offset holds mss.
|
||||
* The firmware figures out where to put
|
||||
* the checksum by parsing the header. */
|
||||
pseudo_hdr_offset = htobe16(mss);
|
||||
|
||||
tx = &sc->tx;
|
||||
req = tx->req_list;
|
||||
seg = tx->seg_list;
|
||||
cnt = 0;
|
||||
rdma_count = 0;
|
||||
/* "rdma_count" is the number of RDMAs belonging to the
|
||||
* current packet BEFORE the current send request. For
|
||||
* non-TSO packets, this is equal to "count".
|
||||
* For TSO packets, rdma_count needs to be reset
|
||||
* to 0 after a segment cut.
|
||||
*
|
||||
* The rdma_count field of the send request is
|
||||
* the number of RDMAs of the packet starting at
|
||||
* that request. For TSO send requests with one ore more cuts
|
||||
* in the middle, this is the number of RDMAs starting
|
||||
* after the last cut in the request. All previous
|
||||
* segments before the last cut implicitly have 1 RDMA.
|
||||
*
|
||||
* Since the number of RDMAs is not known beforehand,
|
||||
* it must be filled-in retroactively - after each
|
||||
* segmentation cut or at the end of the entire packet.
|
||||
*/
|
||||
|
||||
while (busdma_seg_cnt) {
|
||||
/* Break the busdma segment up into pieces*/
|
||||
low = MXGE_LOWPART_TO_U32(seg->ds_addr);
|
||||
high_swapped = htobe32(MXGE_HIGHPART_TO_U32(seg->ds_addr));
|
||||
len = seg->ds_len;
|
||||
|
||||
while (len) {
|
||||
flags_next = flags & ~MXGEFW_FLAGS_FIRST;
|
||||
seglen = len;
|
||||
cum_len_next = cum_len + seglen;
|
||||
(req-rdma_count)->rdma_count = rdma_count + 1;
|
||||
if (__predict_true(cum_len >= 0)) {
|
||||
/* payload */
|
||||
chop = (cum_len_next > mss);
|
||||
cum_len_next = cum_len_next % mss;
|
||||
next_is_first = (cum_len_next == 0);
|
||||
flags |= chop * MXGEFW_FLAGS_TSO_CHOP;
|
||||
flags_next |= next_is_first *
|
||||
MXGEFW_FLAGS_FIRST;
|
||||
rdma_count |= -(chop | next_is_first);
|
||||
rdma_count += chop & !next_is_first;
|
||||
} else if (cum_len_next >= 0) {
|
||||
/* header ends */
|
||||
rdma_count = -1;
|
||||
cum_len_next = 0;
|
||||
seglen = -cum_len;
|
||||
small = (mss <= MXGEFW_SEND_SMALL_SIZE);
|
||||
flags_next = MXGEFW_FLAGS_TSO_PLD |
|
||||
MXGEFW_FLAGS_FIRST |
|
||||
(small * MXGEFW_FLAGS_SMALL);
|
||||
}
|
||||
|
||||
req->addr_high = high_swapped;
|
||||
req->addr_low = htobe32(low);
|
||||
req->pseudo_hdr_offset = pseudo_hdr_offset;
|
||||
req->pad = 0;
|
||||
req->rdma_count = 1;
|
||||
req->length = htobe16(seglen);
|
||||
req->cksum_offset = cksum_offset;
|
||||
req->flags = flags | ((cum_len & 1) *
|
||||
MXGEFW_FLAGS_ALIGN_ODD);
|
||||
low += seglen;
|
||||
len -= seglen;
|
||||
cum_len = cum_len_next;
|
||||
flags = flags_next;
|
||||
req++;
|
||||
cnt++;
|
||||
rdma_count++;
|
||||
if (__predict_false(cksum_offset > seglen))
|
||||
cksum_offset -= seglen;
|
||||
else
|
||||
cksum_offset = 0;
|
||||
if (__predict_false(cnt > tx->max_desc))
|
||||
goto drop;
|
||||
}
|
||||
busdma_seg_cnt--;
|
||||
seg++;
|
||||
}
|
||||
(req-rdma_count)->rdma_count = rdma_count;
|
||||
|
||||
do {
|
||||
req--;
|
||||
req->flags |= MXGEFW_FLAGS_TSO_LAST;
|
||||
} while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST)));
|
||||
|
||||
tx->info[((cnt - 1) + tx->req) & tx->mask].flag = 1;
|
||||
mxge_submit_req(tx, tx->req_list, cnt);
|
||||
return;
|
||||
|
||||
drop:
|
||||
bus_dmamap_unload(tx->dmat, tx->info[tx->req & tx->mask].map);
|
||||
m_freem(m);
|
||||
sc->ifp->if_oerrors++;
|
||||
if (!once) {
|
||||
printf("tx->max_desc exceeded via TSO!\n");
|
||||
printf("mss = %d, %ld, %d!\n", mss,
|
||||
(long)seg - (long)tx->seg_list, tx->max_desc);
|
||||
once = 1;
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* We reproduce the software vlan tag insertion from
|
||||
* net/if_vlan.c:vlan_start() here so that we can advertise "hardware"
|
||||
* vlan tag insertion. We need to advertise this in order to have the
|
||||
* vlan interface respect our csum offload flags.
|
||||
*/
|
||||
static struct mbuf *
|
||||
mxge_vlan_tag_insert(struct mbuf *m)
|
||||
{
|
||||
struct ether_vlan_header *evl;
|
||||
|
||||
M_PREPEND(m, ETHER_VLAN_ENCAP_LEN, M_DONTWAIT);
|
||||
if (__predict_false(m == NULL))
|
||||
return NULL;
|
||||
if (m->m_len < sizeof(*evl)) {
|
||||
m = m_pullup(m, sizeof(*evl));
|
||||
if (__predict_false(m == NULL))
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Transform the Ethernet header into an Ethernet header
|
||||
* with 802.1Q encapsulation.
|
||||
*/
|
||||
evl = mtod(m, struct ether_vlan_header *);
|
||||
bcopy((char *)evl + ETHER_VLAN_ENCAP_LEN,
|
||||
(char *)evl, ETHER_HDR_LEN - ETHER_TYPE_LEN);
|
||||
evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
|
||||
evl->evl_tag = htons(m->m_pkthdr.ether_vtag);
|
||||
m->m_flags &= ~M_VLANTAG;
|
||||
return m;
|
||||
}
|
||||
|
||||
static void
|
||||
mxge_encap(mxge_softc_t *sc, struct mbuf *m)
|
||||
{
|
||||
@ -1717,12 +1526,6 @@ mxge_encap(mxge_softc_t *sc, struct mbuf *m)
|
||||
tx = &sc->tx;
|
||||
|
||||
ip_off = sizeof (struct ether_header);
|
||||
if (m->m_flags & M_VLANTAG) {
|
||||
m = mxge_vlan_tag_insert(m);
|
||||
if (__predict_false(m == NULL))
|
||||
goto drop;
|
||||
ip_off += ETHER_VLAN_ENCAP_LEN;
|
||||
}
|
||||
|
||||
/* (try to) map the frame for DMA */
|
||||
idx = tx->req & tx->mask;
|
||||
@ -1752,13 +1555,6 @@ mxge_encap(mxge_softc_t *sc, struct mbuf *m)
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
tx->info[idx].m = m;
|
||||
|
||||
|
||||
/* TSO is different enough, we handle it in another routine */
|
||||
if (m->m_pkthdr.csum_flags & (CSUM_TSO)) {
|
||||
mxge_encap_tso(sc, m, cnt, ip_off);
|
||||
return;
|
||||
}
|
||||
|
||||
req = tx->req_list;
|
||||
cksum_offset = 0;
|
||||
pseudo_hdr_offset = 0;
|
||||
@ -2034,6 +1830,7 @@ mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum)
|
||||
{
|
||||
struct ether_vlan_header *evl;
|
||||
struct ether_header *eh;
|
||||
struct m_tag *mtag;
|
||||
uint32_t partial;
|
||||
|
||||
evl = mtod(m, struct ether_vlan_header *);
|
||||
@ -2056,10 +1853,14 @@ mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum)
|
||||
/* restore checksum to network byte order;
|
||||
later consumers expect this */
|
||||
*csum = htons(*csum);
|
||||
|
||||
/* save the tag */
|
||||
mtag = m_tag_alloc(MTAG_VLAN, MTAG_VLAN_TAG, sizeof(u_int),
|
||||
M_NOWAIT);
|
||||
if (mtag == NULL)
|
||||
return;
|
||||
m->m_flags |= M_VLANTAG;
|
||||
m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
|
||||
VLAN_TAG_VALUE(mtag) = ntohs(evl->evl_tag);
|
||||
m_tag_prepend(m, mtag);
|
||||
|
||||
/*
|
||||
* Remove the 802.1q header by copying the Ethernet
|
||||
@ -3079,9 +2880,8 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
|
||||
mask = ifr->ifr_reqcap ^ ifp->if_capenable;
|
||||
if (mask & IFCAP_TXCSUM) {
|
||||
if (IFCAP_TXCSUM & ifp->if_capenable) {
|
||||
ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
|
||||
ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP
|
||||
| CSUM_TSO);
|
||||
ifp->if_capenable &= ~(IFCAP_TXCSUM);
|
||||
ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP);
|
||||
} else {
|
||||
ifp->if_capenable |= IFCAP_TXCSUM;
|
||||
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
|
||||
@ -3095,24 +2895,7 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
|
||||
sc->csum_flag = 1;
|
||||
}
|
||||
}
|
||||
if (mask & IFCAP_TSO4) {
|
||||
if (IFCAP_TSO4 & ifp->if_capenable) {
|
||||
ifp->if_capenable &= ~IFCAP_TSO4;
|
||||
ifp->if_hwassist &= ~CSUM_TSO;
|
||||
} else if (IFCAP_TXCSUM & ifp->if_capenable) {
|
||||
ifp->if_capenable |= IFCAP_TSO4;
|
||||
ifp->if_hwassist |= CSUM_TSO;
|
||||
} else {
|
||||
printf("mxge requires tx checksum offload"
|
||||
" be enabled to use TSO\n");
|
||||
err = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & IFCAP_VLAN_HWTAGGING)
|
||||
ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
|
||||
mtx_unlock(&sc->driver_mtx);
|
||||
VLAN_CAPABILITIES(ifp);
|
||||
|
||||
break;
|
||||
|
||||
@ -3294,15 +3077,14 @@ mxge_attach(device_t dev)
|
||||
|
||||
err = bus_setup_intr(sc->dev, sc->irq_res,
|
||||
INTR_TYPE_NET | INTR_MPSAFE,
|
||||
NULL, mxge_intr, sc, &sc->ih);
|
||||
mxge_intr, sc, &sc->ih);
|
||||
if (err != 0) {
|
||||
goto abort_with_rings;
|
||||
}
|
||||
/* hook into the network stack */
|
||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
|
||||
ifp->if_baudrate = 100000000;
|
||||
ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO4 |
|
||||
IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
|
||||
ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_VLAN_MTU;
|
||||
|
||||
sc->max_mtu = mxge_max_mtu(sc);
|
||||
if (sc->max_mtu >= 9000)
|
||||
@ -3311,7 +3093,7 @@ mxge_attach(device_t dev)
|
||||
device_printf(dev, "MTU limited to %d. Install "
|
||||
"latest firmware for 9000 byte jumbo support\n",
|
||||
sc->max_mtu - ETHER_HDR_LEN);
|
||||
ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO;
|
||||
ifp->if_hwassist = CSUM_TCP | CSUM_UDP;
|
||||
ifp->if_capenable = ifp->if_capabilities;
|
||||
sc->csum_flag = 1;
|
||||
ifp->if_init = mxge_init;
|
||||
@ -3366,11 +3148,6 @@ mxge_detach(device_t dev)
|
||||
{
|
||||
mxge_softc_t *sc = device_get_softc(dev);
|
||||
|
||||
if (sc->ifp->if_vlantrunk != NULL) {
|
||||
device_printf(sc->dev,
|
||||
"Detach vlans before removing module\n");
|
||||
return EBUSY;
|
||||
}
|
||||
mtx_lock(&sc->driver_mtx);
|
||||
if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING)
|
||||
mxge_close(sc);
|
||||
|
@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/kernel.h>
|
||||
|
@ -169,6 +169,7 @@ SUBDIR= ${_3dfx} \
|
||||
msdosfs_iconv \
|
||||
${_mse} \
|
||||
msk \
|
||||
${_mxge} \
|
||||
my \
|
||||
${_ncp} \
|
||||
${_ncv} \
|
||||
@ -422,6 +423,7 @@ _ipw= ipw
|
||||
_iwi= iwi
|
||||
_ixgb= ixgb
|
||||
_mly= mly
|
||||
_mxge= mxge
|
||||
_nve= nve
|
||||
.if !defined(NO_CRYPT) || defined(ALL_MODULES)
|
||||
.if exists(${.CURDIR}/../crypto/via)
|
||||
@ -479,6 +481,7 @@ _ipw= ipw
|
||||
_ixgb= ixgb
|
||||
#_lnc= lnc
|
||||
_mly= mly
|
||||
_mxge= mxge
|
||||
_ndis= ndis
|
||||
_nve= nve
|
||||
_ppc= ppc
|
||||
|
Loading…
x
Reference in New Issue
Block a user