Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 3 Jan 2012 20:24:57 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r229417 - stable/9/sys/dev/ti
Message-ID:  <201201032024.q03KOvHx040993@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Tue Jan  3 20:24:56 2012
New Revision: 229417
URL: http://svn.freebsd.org/changeset/base/229417

Log:
  MFC r227091-227095,227098-227099:
  r227091:
    Make sure to unload loaded DMA area(descriptor, command, event ring).
  
  r227092:
    Announce IFCAP_LINKSTATE capability and let network stack know link
    state changes.  Hide superfluous link up/down message under
    bootverbose since if_link_state_change(9) shows that information.
    While I'm here, change baudrate with the resolved speed of the
    established link instead of blindly setting it 1G. Unfortunately,
    it seems there is no way to differentiate 10/100Mbps from
    non-gigabit link so just assume we established a 100Mbps link if
    current link is not a gigabit link.
  
  r227093:
    Introduce ti_ifmedia_upd_locked() to use in driver initialization
    and add missing driver lock for both ti_ifmedia_upd() and
    ti_ifmedia_sts().
  
  r227094:
    Don't clear upper 4bits from VLAN tag information.  It's
    responsibility of vlan(4) to extract VLAN id from the tag
    information and vlan(4) correctly handles it.
  
  r227095:
    Don't abuse if_hwassist and make sure enabling corresponding TX/RX
    checksum offloading and VLAN hardware tag insertion/stripping from
    the currently enabled hardware offloading capabilities.
    Previously if_hwassist, which was initialized to TX/RX checksum
    offloading, was blindly used to enable both TX and RX checksum
    offloading such that disabling either TX or RX checksum offloading
    was not possible.
  
    ti(4) controllers support TX/RX checksum offloading with VLAN
    tagging so announce TX/RX checksum offloading capability over VLAN
    to vlan(4).
  
    Make VLAN hardware tag insertion/stripping honors currently enabled
    interface capability instead of blindly enabling VLAN hardware
    tagging. This change allows disabling hardware support of VLAN tag.
  
    Because ti(4) supports VLAN oversized frames, make network stack
    know the capability by setting if_hdrlen.
  
    While I'm here, rewrite SIOCSIFCAP handler and make sure to
    reinitialize controller whenever TX/RX checksum offloading and VLAN
    hardware tagging option is changed.  The requirement of controller
    reinitialization comes from the limitation of Tigon I/II firmware.
    Tigon I/II firmware requires all related RCBs should be
    reinitialized whenever any of its hardware offloading capabilities
    change.
  
    vlan(4) is also notified whenever the parent interface's capability
    changes such that it can correctly handle TX/RX checksum offloading
    based on parent interface's enabled offloading capabilities.
  
    RX checksum offloading handler was changed to make upper stack use
    controller computed partial checksum value.  Previously, ti(4) just
    set the computed value for any frames(IPv4, IPv6) and the value was
    not used in upper stack because driver didn't set CSUM_DATA_VALID
    such that upper network stack had to recompute checksum of TCP/UDP
    packets. I have no idea how this was not noticed for a long time.
    With this change, upper network stack does not have to fully
    recompute the checksum such that calculating pseudo checksum based
    on partial checksum is sufficient to know whether received packet's
    checksum is correct or not. However, I don't know why ti(4) does
    not have controller compute pseudo checksum as controller has
    ability to do it. I'm just guessing enabling that feature could
    trigger a firmware bug or could be slower than computing it on host
    side so just leave it as it was.
  
    In order not to produce false positives, ti(4) now checks whether
    controller actually computed IP or TCP/UDP checksum by checking
    ti_flags field.
  
  r227098:
    Because ti(4) drops a driver lock in RX handler, check whether
    driver is still running before re-enabling interrupts.
  
  r227099:
    Implement altq(4) support.
    While I'm here fix a logic error in r227098 where it didn't
    re-enable interrupts when TX queue is empty.

Modified:
  stable/9/sys/dev/ti/if_ti.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/amd64/include/xen/   (props changed)
  stable/9/sys/boot/   (props changed)
  stable/9/sys/boot/i386/efi/   (props changed)
  stable/9/sys/boot/ia64/efi/   (props changed)
  stable/9/sys/boot/ia64/ski/   (props changed)
  stable/9/sys/boot/powerpc/boot1.chrp/   (props changed)
  stable/9/sys/boot/powerpc/ofw/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/conf/   (props changed)
  stable/9/sys/contrib/dev/acpica/   (props changed)
  stable/9/sys/contrib/octeon-sdk/   (props changed)
  stable/9/sys/contrib/pf/   (props changed)
  stable/9/sys/contrib/x86emu/   (props changed)

Modified: stable/9/sys/dev/ti/if_ti.c
==============================================================================
--- stable/9/sys/dev/ti/if_ti.c	Tue Jan  3 20:17:35 2012	(r229416)
+++ stable/9/sys/dev/ti/if_ti.c	Tue Jan  3 20:24:56 2012	(r229417)
@@ -196,6 +196,7 @@ static void ti_stop(struct ti_softc *);
 static void ti_watchdog(void *);
 static int ti_shutdown(device_t);
 static int ti_ifmedia_upd(struct ifnet *);
+static int ti_ifmedia_upd_locked(struct ti_softc *);
 static void ti_ifmedia_sts(struct ifnet *, struct ifmediareq *);
 
 static uint32_t ti_eeprom_putbyte(struct ti_softc *, int);
@@ -924,12 +925,26 @@ ti_handle_events(struct ti_softc *sc)
 		switch (TI_EVENT_EVENT(e)) {
 		case TI_EV_LINKSTAT_CHANGED:
 			sc->ti_linkstat = TI_EVENT_CODE(e);
-			if (sc->ti_linkstat == TI_EV_CODE_LINK_UP)
-				device_printf(sc->ti_dev, "10/100 link up\n");
-			else if (sc->ti_linkstat == TI_EV_CODE_GIG_LINK_UP)
-				device_printf(sc->ti_dev, "gigabit link up\n");
-			else if (sc->ti_linkstat == TI_EV_CODE_LINK_DOWN)
-				device_printf(sc->ti_dev, "link down\n");
+			if (sc->ti_linkstat == TI_EV_CODE_LINK_UP) {
+				if_link_state_change(sc->ti_ifp, LINK_STATE_UP);
+				sc->ti_ifp->if_baudrate = IF_Mbps(100);
+				if (bootverbose)
+					device_printf(sc->ti_dev,
+					    "10/100 link up\n");
+			} else if (sc->ti_linkstat == TI_EV_CODE_GIG_LINK_UP) {
+				if_link_state_change(sc->ti_ifp, LINK_STATE_UP);
+				sc->ti_ifp->if_baudrate = IF_Gbps(1UL);
+				if (bootverbose)
+					device_printf(sc->ti_dev,
+					    "gigabit link up\n");
+			} else if (sc->ti_linkstat == TI_EV_CODE_LINK_DOWN) {
+				if_link_state_change(sc->ti_ifp,
+				    LINK_STATE_DOWN);
+				sc->ti_ifp->if_baudrate = 0;
+				if (bootverbose)
+					device_printf(sc->ti_dev,
+					    "link down\n");
+			}
 			break;
 		case TI_EV_ERROR:
 			if (TI_EVENT_CODE(e) == TI_EV_CODE_ERR_INVAL_CMD)
@@ -1237,7 +1252,7 @@ ti_newbuf_std(struct ti_softc *sc, int i
 	r->ti_len = segs.ds_len;
 	r->ti_type = TI_BDTYPE_RECV_BD;
 	r->ti_flags = 0;
-	if (sc->ti_ifp->if_hwassist)
+	if (sc->ti_ifp->if_capenable & IFCAP_RXCSUM)
 		r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM;
 	r->ti_idx = i;
 
@@ -1284,7 +1299,7 @@ ti_newbuf_mini(struct ti_softc *sc, int 
 	r->ti_len = segs.ds_len;
 	r->ti_type = TI_BDTYPE_RECV_BD;
 	r->ti_flags = TI_BDFLAG_MINI_RING;
-	if (sc->ti_ifp->if_hwassist)
+	if (sc->ti_ifp->if_capenable & IFCAP_RXCSUM)
 		r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM;
 	r->ti_idx = i;
 
@@ -1350,7 +1365,7 @@ ti_newbuf_jumbo(struct ti_softc *sc, int
 	r->ti_len = segs.ds_len;
 	r->ti_type = TI_BDTYPE_RECV_JUMBO_BD;
 	r->ti_flags = TI_BDFLAG_JUMBO_RING;
-	if (sc->ti_ifp->if_hwassist)
+	if (sc->ti_ifp->if_capenable & IFCAP_RXCSUM)
 		r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM;
 	r->ti_idx = i;
 
@@ -1492,7 +1507,7 @@ ti_newbuf_jumbo(struct ti_softc *sc, int
 
 	r->ti_flags = TI_BDFLAG_JUMBO_RING|TI_RCB_FLAG_USE_EXT_RX_BD;
 
-	if (sc->ti_ifp->if_hwassist)
+	if (sc->ti_ifp->if_capenable & IFCAP_RXCSUM)
 		r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM|TI_BDFLAG_IP_CKSUM;
 
 	r->ti_idx = idx;
@@ -1845,11 +1860,6 @@ ti_chipinit(struct ti_softc *sc)
 	/* Initialize link to down state. */
 	sc->ti_linkstat = TI_EV_CODE_LINK_DOWN;
 
-	if (sc->ti_ifp->if_capenable & IFCAP_HWCSUM)
-		sc->ti_ifp->if_hwassist = TI_CSUM_FEATURES;
-	else
-		sc->ti_ifp->if_hwassist = 0;
-
 	/* Set endianness before we access any non-PCI registers. */
 #if 0 && BYTE_ORDER == BIG_ENDIAN
 	CSR_WRITE_4(sc, TI_MISC_HOST_CTL,
@@ -1968,7 +1978,7 @@ ti_chipinit(struct ti_softc *sc)
 	 * the firmware racks up lots of nicDmaReadRingFull
 	 * errors.  This is not compatible with hardware checksums.
 	 */
-	if (sc->ti_ifp->if_hwassist == 0)
+	if ((sc->ti_ifp->if_capenable & (IFCAP_TXCSUM | IFCAP_RXCSUM)) == 0)
 		TI_SETBIT(sc, TI_GCR_OPMODE, TI_OPMODE_1_DMA_ACTIVE);
 
 	/* Recommended settings from Tigon manual. */
@@ -2055,10 +2065,11 @@ ti_gibinit(struct ti_softc *sc)
 	TI_HOSTADDR(rcb->ti_hostaddr) = rdphys + TI_RD_OFF(ti_rx_std_ring);
 	rcb->ti_max_len = TI_FRAMELEN;
 	rcb->ti_flags = 0;
-	if (sc->ti_ifp->if_hwassist)
+	if (sc->ti_ifp->if_capenable & IFCAP_RXCSUM)
 		rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM |
 		     TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM;
-	rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
+	if (sc->ti_ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+		rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
 
 	/* Set up the jumbo receive ring. */
 	rcb = &sc->ti_rdata->ti_info.ti_jumbo_rx_rcb;
@@ -2071,10 +2082,11 @@ ti_gibinit(struct ti_softc *sc)
 	rcb->ti_max_len = PAGE_SIZE;
 	rcb->ti_flags = TI_RCB_FLAG_USE_EXT_RX_BD;
 #endif
-	if (sc->ti_ifp->if_hwassist)
+	if (sc->ti_ifp->if_capenable & IFCAP_RXCSUM)
 		rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM |
 		     TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM;
-	rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
+	if (sc->ti_ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+		rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
 
 	/*
 	 * Set up the mini ring. Only activated on the
@@ -2088,10 +2100,11 @@ ti_gibinit(struct ti_softc *sc)
 		rcb->ti_flags = TI_RCB_FLAG_RING_DISABLED;
 	else
 		rcb->ti_flags = 0;
-	if (sc->ti_ifp->if_hwassist)
+	if (sc->ti_ifp->if_capenable & IFCAP_RXCSUM)
 		rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM |
 		     TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM;
-	rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
+	if (sc->ti_ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+		rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
 
 	/*
 	 * Set up the receive return ring.
@@ -2120,8 +2133,9 @@ ti_gibinit(struct ti_softc *sc)
 		rcb->ti_flags = 0;
 	else
 		rcb->ti_flags = TI_RCB_FLAG_HOST_RING;
-	rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
-	if (sc->ti_ifp->if_hwassist)
+	if (sc->ti_ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
+		rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST;
+	if (sc->ti_ifp->if_capenable & IFCAP_TXCSUM)
 		rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM |
 		     TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM;
 	rcb->ti_max_len = TI_TX_RING_CNT;
@@ -2221,8 +2235,8 @@ ti_attach(device_t dev)
 		error = ENOSPC;
 		goto fail;
 	}
-	sc->ti_ifp->if_capabilities = IFCAP_HWCSUM |
-	    IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
+	sc->ti_ifp->if_hwassist = TI_CSUM_FEATURES;
+	sc->ti_ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_RXCSUM;
 	sc->ti_ifp->if_capenable = sc->ti_ifp->if_capabilities;
 
 	/*
@@ -2417,8 +2431,10 @@ ti_attach(device_t dev)
 	ifp->if_ioctl = ti_ioctl;
 	ifp->if_start = ti_start;
 	ifp->if_init = ti_init;
-	ifp->if_baudrate = 1000000000;
-	ifp->if_snd.ifq_maxlen = TI_TX_RING_CNT - 1;
+	ifp->if_baudrate = IF_Gbps(1UL);
+	ifp->if_snd.ifq_drv_maxlen = TI_TX_RING_CNT - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
+	IFQ_SET_READY(&ifp->if_snd);
 
 	/* Set up ifmedia support. */
 	if (sc->ti_copper) {
@@ -2464,6 +2480,17 @@ ti_attach(device_t dev)
 	 */
 	ether_ifattach(ifp, eaddr);
 
+	/* VLAN capability setup. */
+	ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM |
+	    IFCAP_VLAN_HWTAGGING;
+	ifp->if_capenable = ifp->if_capabilities;
+	/* Tell the upper layer we support VLAN over-sized frames. */
+	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
+
+	/* Driver supports link state tracking. */
+	ifp->if_capabilities |= IFCAP_LINKSTATE;
+	ifp->if_capenable |= IFCAP_LINKSTATE;
+
 	/* Hook interrupt last to avoid having to lock softc */
 	error = bus_setup_intr(dev, sc->ti_irq, INTR_TYPE_NET|INTR_MPSAFE,
 	   NULL, ti_intr, sc, &sc->ti_intrhand);
@@ -2522,6 +2549,8 @@ ti_detach(device_t dev)
 		bus_dma_tag_destroy(sc->ti_mbuftx_dmat);
 	if (sc->ti_mbufrx_dmat)
 		bus_dma_tag_destroy(sc->ti_mbufrx_dmat);
+	if (sc->ti_rdata && sc->ti_rdata_dmamap)
+		bus_dmamap_unload(sc->ti_rdata_dmat, sc->ti_rdata_dmamap);
 	if (sc->ti_rdata)
 		bus_dmamem_free(sc->ti_rdata_dmat, sc->ti_rdata,
 				sc->ti_rdata_dmamap);
@@ -2638,7 +2667,7 @@ ti_rxeof(struct ti_softc *sc)
 
 		if (cur_rx->ti_flags & TI_BDFLAG_VLAN_TAG) {
 			have_tag = 1;
-			vlan_tag = cur_rx->ti_vlan_tag & 0xfff;
+			vlan_tag = cur_rx->ti_vlan_tag;
 		}
 
 		if (cur_rx->ti_flags & TI_BDFLAG_JUMBO_RING) {
@@ -2715,12 +2744,17 @@ ti_rxeof(struct ti_softc *sc)
 		ifp->if_ipackets++;
 		m->m_pkthdr.rcvif = ifp;
 
-		if (ifp->if_hwassist) {
-			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED |
-			    CSUM_DATA_VALID;
-			if ((cur_rx->ti_ip_cksum ^ 0xffff) == 0)
-				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
-			m->m_pkthdr.csum_data = cur_rx->ti_tcp_udp_cksum;
+		if (ifp->if_capenable & IFCAP_RXCSUM) {
+			if (cur_rx->ti_flags & TI_BDFLAG_IP_CKSUM) {
+				m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
+				if ((cur_rx->ti_ip_cksum ^ 0xffff) == 0)
+					m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+			}
+			if (cur_rx->ti_flags & TI_BDFLAG_TCP_UDP_CKSUM) {
+				m->m_pkthdr.csum_data =
+				    cur_rx->ti_tcp_udp_cksum;
+				m->m_pkthdr.csum_flags |= CSUM_DATA_VALID;
+			}
 		}
 
 		/*
@@ -2824,12 +2858,12 @@ ti_intr(void *xsc)
 
 	ti_handle_events(sc);
 
-	/* Re-enable interrupts. */
-	CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0);
-
-	if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
-	    ifp->if_snd.ifq_head != NULL)
-		ti_start_locked(ifp);
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+		/* Re-enable interrupts. */
+		CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0);
+		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+			ti_start_locked(ifp);
+	}
 
 	TI_UNLOCK(sc);
 }
@@ -2933,7 +2967,7 @@ ti_encap(struct ti_softc *sc, struct mbu
 		f->ti_flags = csum_flags;
 		if (m->m_flags & M_VLANTAG) {
 			f->ti_flags |= TI_BDFLAG_VLAN_TAG;
-			f->ti_vlan_tag = m->m_pkthdr.ether_vtag & 0xfff;
+			f->ti_vlan_tag = m->m_pkthdr.ether_vtag;
 		} else {
 			f->ti_vlan_tag = 0;
 		}
@@ -2986,9 +3020,9 @@ ti_start_locked(struct ifnet *ifp)
 
 	sc = ifp->if_softc;
 
-	for (; ifp->if_snd.ifq_head != NULL &&
+	for (; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
 	    sc->ti_txcnt < (TI_TX_RING_CNT - 16);) {
-		IF_DEQUEUE(&ifp->if_snd, m_head);
+		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
 		if (m_head == NULL)
 			break;
 
@@ -3004,7 +3038,7 @@ ti_start_locked(struct ifnet *ifp)
 		    m_head->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) {
 			if ((TI_TX_RING_CNT - sc->ti_txcnt) <
 			    m_head->m_pkthdr.csum_data + 16) {
-				IF_PREPEND(&ifp->if_snd, m_head);
+				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
 				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 				break;
 			}
@@ -3018,7 +3052,7 @@ ti_start_locked(struct ifnet *ifp)
 		if (ti_encap(sc, &m_head)) {
 			if (m_head == NULL)
 				break;
-			IF_PREPEND(&ifp->if_snd, m_head);
+			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 			break;
 		}
@@ -3150,7 +3184,7 @@ static void ti_init2(struct ti_softc *sc
 	ifm = &sc->ifmedia;
 	tmp = ifm->ifm_media;
 	ifm->ifm_media = ifm->ifm_cur->ifm_media;
-	ti_ifmedia_upd(ifp);
+	ti_ifmedia_upd_locked(sc);
 	ifm->ifm_media = tmp;
 }
 
@@ -3161,11 +3195,23 @@ static int
 ti_ifmedia_upd(struct ifnet *ifp)
 {
 	struct ti_softc *sc;
+	int error;
+
+	sc = ifp->if_softc;
+	TI_LOCK(sc);
+	error = ti_ifmedia_upd(ifp);
+	TI_UNLOCK(sc);
+
+	return (error);
+}
+
+static int
+ti_ifmedia_upd_locked(struct ti_softc *sc)
+{
 	struct ifmedia *ifm;
 	struct ti_cmd_desc cmd;
 	uint32_t flowctl;
 
-	sc = ifp->if_softc;
 	ifm = &sc->ifmedia;
 
 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
@@ -3266,11 +3312,15 @@ ti_ifmedia_sts(struct ifnet *ifp, struct
 
 	sc = ifp->if_softc;
 
+	TI_LOCK(sc);
+
 	ifmr->ifm_status = IFM_AVALID;
 	ifmr->ifm_active = IFM_ETHER;
 
-	if (sc->ti_linkstat == TI_EV_CODE_LINK_DOWN)
+	if (sc->ti_linkstat == TI_EV_CODE_LINK_DOWN) {
+		TI_UNLOCK(sc);
 		return;
+	}
 
 	ifmr->ifm_status |= IFM_ACTIVE;
 
@@ -3302,6 +3352,7 @@ ti_ifmedia_sts(struct ifnet *ifp, struct
 		if (media & TI_LNK_HALF_DUPLEX)
 			ifmr->ifm_active |= IFM_HDX;
 	}
+	TI_UNLOCK(sc);
 }
 
 static int
@@ -3368,15 +3419,32 @@ ti_ioctl(struct ifnet *ifp, u_long comma
 	case SIOCSIFCAP:
 		TI_LOCK(sc);
 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
-		if (mask & IFCAP_HWCSUM) {
-			if (IFCAP_HWCSUM & ifp->if_capenable)
-				ifp->if_capenable &= ~IFCAP_HWCSUM;
-			else
-				ifp->if_capenable |= IFCAP_HWCSUM;
-			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+		if ((mask & IFCAP_TXCSUM) != 0 &&
+		    (ifp->if_capabilities & IFCAP_TXCSUM) != 0) {
+			ifp->if_capenable ^= IFCAP_TXCSUM;
+			if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
+				ifp->if_hwassist |= TI_CSUM_FEATURES;
+                        else
+				ifp->if_hwassist &= ~TI_CSUM_FEATURES;
+                }
+		if ((mask & IFCAP_RXCSUM) != 0 &&
+		    (ifp->if_capabilities & IFCAP_RXCSUM) != 0)
+			ifp->if_capenable ^= IFCAP_RXCSUM;
+		if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
+		    (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0)
+                        ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+		if ((mask & IFCAP_VLAN_HWCSUM) != 0 &&
+		    (ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0)
+			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
+		if ((mask & (IFCAP_TXCSUM | IFCAP_RXCSUM |
+		    IFCAP_VLAN_HWTAGGING)) != 0) {
+			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 				ti_init_locked(sc);
+			}
 		}
 		TI_UNLOCK(sc);
+		VLAN_CAPABILITIES(ifp);
 		break;
 	default:
 		error = ether_ioctl(ifp, command, data);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201032024.q03KOvHx040993>