svn commit: r223350 - head/sys/dev/e1000

Jack F Vogel jfv at FreeBSD.org
Mon Jun 20 22:59:29 UTC 2011


Author: jfv
Date: Mon Jun 20 22:59:29 2011
New Revision: 223350
URL: http://svn.freebsd.org/changeset/base/223350

Log:
  Eliminate some global tuneables in favor of adapter-specific,
  particular flow control and dma coalesce. Also improve the
  sysctl operation on those too.
  
  Add IPv6 detection in the ioctl code, this was done for
  ixgbe first, carrying that over.
  
  Add resource ability to disable particular adapter.
  
  Add HW TSO capability so vlans can make use of TSO

Modified:
  head/sys/dev/e1000/if_igb.c
  head/sys/dev/e1000/if_igb.h

Modified: head/sys/dev/e1000/if_igb.c
==============================================================================
--- head/sys/dev/e1000/if_igb.c	Mon Jun 20 22:02:01 2011	(r223349)
+++ head/sys/dev/e1000/if_igb.c	Mon Jun 20 22:59:29 2011	(r223350)
@@ -36,6 +36,7 @@
 #ifdef HAVE_KERNEL_OPTION_HEADERS
 #include "opt_device_polling.h"
 #include "opt_inet.h"
+#include "opt_inet6.h"
 #include "opt_altq.h"
 #endif
 
@@ -99,7 +100,7 @@ int	igb_display_debug_stats = 0;
 /*********************************************************************
  *  Driver version:
  *********************************************************************/
-char igb_driver_version[] = "version - 2.2.3";
+char igb_driver_version[] = "version - 2.2.5";
 
 
 /*********************************************************************
@@ -265,6 +266,7 @@ static void	igb_handle_link(void *contex
 static void	igb_set_sysctl_value(struct adapter *, const char *,
 		    const char *, int *, int);
 static int	igb_set_flowcntl(SYSCTL_HANDLER_ARGS);
+static int	igb_sysctl_dmac(SYSCTL_HANDLER_ARGS);
 
 #ifdef DEVICE_POLLING
 static poll_handler_t igb_poll;
@@ -344,25 +346,6 @@ TUNABLE_INT("hw.igb.hdr_split", &igb_hea
 static int igb_num_queues = 0;
 TUNABLE_INT("hw.igb.num_queues", &igb_num_queues);
 
-/* How many packets rxeof tries to clean at a time */
-static int igb_rx_process_limit = 100;
-TUNABLE_INT("hw.igb.rx_process_limit", &igb_rx_process_limit);
-
-/* Flow control setting - default to FULL */
-static int igb_fc_setting = e1000_fc_full;
-TUNABLE_INT("hw.igb.fc_setting", &igb_fc_setting);
-
-/* Energy Efficient Ethernet - default to off */
-static int igb_eee_disabled = TRUE;
-TUNABLE_INT("hw.igb.eee_disabled", &igb_eee_disabled);
-
-/*
-** DMA Coalescing, only for i350 - default to off,
-** this feature is for power savings
-*/
-static int igb_dma_coalesce = FALSE;
-TUNABLE_INT("hw.igb.dma_coalesce", &igb_dma_coalesce);
-
 /*********************************************************************
  *  Device identification routine
  *
@@ -433,6 +416,11 @@ igb_attach(device_t dev)
 
 	INIT_DEBUGOUT("igb_attach: begin");
 
+	if (resource_disabled("igb", device_get_unit(dev))) {
+		device_printf(dev, "Disabled by device hint\n");
+		return (ENXIO);
+	}
+
 	adapter = device_get_softc(dev);
 	adapter->dev = adapter->osdep.dev = dev;
 	IGB_CORE_LOCK_INIT(adapter, device_get_nameunit(dev));
@@ -450,7 +438,7 @@ igb_attach(device_t dev)
 
 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "flow_control", CTLTYPE_INT|CTLFLAG_RW,
+	    OID_AUTO, "fc", CTLTYPE_INT|CTLFLAG_RW,
 	    adapter, 0, igb_set_flowcntl, "I", "Flow Control");
 
 	callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0);
@@ -476,8 +464,8 @@ igb_attach(device_t dev)
 
 	/* Sysctl for limiting the amount of work done in the taskqueue */
 	igb_set_sysctl_value(adapter, "rx_processing_limit",
-	    "max number of rx packets to process", &adapter->rx_process_limit,
-	    igb_rx_process_limit);
+	    "max number of rx packets to process",
+	    &adapter->rx_process_limit, 100);
 
 	/*
 	 * Validate number of transmit and receive descriptors. It
@@ -552,13 +540,14 @@ igb_attach(device_t dev)
 
 	/* Some adapter-specific advanced features */
 	if (adapter->hw.mac.type >= e1000_i350) {
-		igb_set_sysctl_value(adapter, "dma_coalesce",
-		    "configure dma coalesce",
-		    &adapter->dma_coalesce, igb_dma_coalesce);
+		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+		    OID_AUTO, "dmac", CTLTYPE_INT|CTLFLAG_RW,
+		    adapter, 0, igb_sysctl_dmac, "I", "DMA Coalesce");
 		igb_set_sysctl_value(adapter, "eee_disabled",
 		    "enable Energy Efficient Ethernet",
 		    &adapter->hw.dev_spec._82575.eee_disable,
-		    igb_eee_disabled);
+		    TRUE);
 		e1000_set_eee_i350(&adapter->hw);
 	}
 
@@ -658,6 +647,7 @@ igb_attach(device_t dev)
 	return (0);
 
 err_late:
+	igb_detach(dev);
 	igb_free_transmit_structures(adapter);
 	igb_free_receive_structures(adapter);
 	igb_release_hw_control(adapter);
@@ -736,7 +726,8 @@ igb_detach(device_t dev)
 
 	igb_free_transmit_structures(adapter);
 	igb_free_receive_structures(adapter);
-	free(adapter->mta, M_DEVBUF);
+	if (adapter->mta != NULL)
+		free(adapter->mta, M_DEVBUF);
 
 	IGB_CORE_LOCK_DESTROY(adapter);
 
@@ -1025,11 +1016,12 @@ static int
 igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 {
 	struct adapter	*adapter = ifp->if_softc;
-	struct ifreq *ifr = (struct ifreq *)data;
-#ifdef INET
-	struct ifaddr *ifa = (struct ifaddr *)data;
+	struct ifreq	*ifr = (struct ifreq *)data;
+#if defined(INET) || defined(INET6)
+	struct ifaddr	*ifa = (struct ifaddr *)data;
+	bool		avoid_reset = FALSE;
 #endif
-	int error = 0;
+	int		error = 0;
 
 	if (adapter->in_detach)
 		return (error);
@@ -1037,20 +1029,22 @@ igb_ioctl(struct ifnet *ifp, u_long comm
 	switch (command) {
 	case SIOCSIFADDR:
 #ifdef INET
-		if (ifa->ifa_addr->sa_family == AF_INET) {
-			/*
-			 * XXX
-			 * Since resetting hardware takes a very long time
-			 * and results in link renegotiation we only
-			 * initialize the hardware only when it is absolutely
-			 * required.
-			 */
+		if (ifa->ifa_addr->sa_family == AF_INET)
+			avoid_reset = TRUE;
+#endif
+#ifdef INET6
+		if (ifa->ifa_addr->sa_family == AF_INET6)
+			avoid_reset = TRUE;
+#endif
+#if defined(INET) || defined(INET6)
+		/*
+		** Calling init results in link renegotiation,
+		** so we avoid doing it when possible.
+		*/
+		if (avoid_reset) {
 			ifp->if_flags |= IFF_UP;
-			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
-				IGB_CORE_LOCK(adapter);
-				igb_init_locked(adapter);
-				IGB_CORE_UNLOCK(adapter);
-			}
+			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+				igb_init(adapter);
 			if (!(ifp->if_flags & IFF_NOARP))
 				arp_ifinit(ifp, ifa);
 		} else
@@ -1175,6 +1169,10 @@ igb_ioctl(struct ifnet *ifp, u_long comm
 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
 			reinit = 1;
 		}
+		if (mask & IFCAP_VLAN_HWTSO) {
+			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
+			reinit = 1;
+		}
 		if (mask & IFCAP_LRO) {
 			ifp->if_capenable ^= IFCAP_LRO;
 			reinit = 1;
@@ -2721,6 +2719,12 @@ igb_reset(struct adapter *adapter)
 
 	fc->pause_time = IGB_FC_PAUSE_TIME;
 	fc->send_xon = TRUE;
+	if (fc->requested_mode)
+		fc->current_mode = fc->requested_mode;
+	else
+		fc->current_mode = e1000_fc_full;
+
+	adapter->fc = fc->current_mode;
 
 	/* Issue a global reset */
 	e1000_reset_hw(hw);
@@ -2730,9 +2734,13 @@ igb_reset(struct adapter *adapter)
 		device_printf(dev, "Hardware Initialization Failed\n");
 
 	/* Setup DMA Coalescing */
-	if ((hw->mac.type == e1000_i350) &&
-	    (adapter->dma_coalesce == TRUE)) {
-		u32 reg;
+	if (hw->mac.type == e1000_i350) {
+		u32 reg = ~E1000_DMACR_DMAC_EN;
+
+		if (adapter->dmac == 0) { /* Disabling it */
+			E1000_WRITE_REG(hw, E1000_DMACR, reg);
+			goto reset_out;
+		}
 
 		hwm = (pba - 4) << 10;
 		reg = (((pba-6) << E1000_DMACR_DMACTHR_SHIFT)
@@ -2741,8 +2749,8 @@ igb_reset(struct adapter *adapter)
 		/* transition to L0x or L1 if available..*/
 		reg |= (E1000_DMACR_DMAC_EN | E1000_DMACR_DMAC_LX_MASK);
 
-		/* timer = +-1000 usec in 32usec intervals */
-		reg |= (1000 >> 5);
+		/* timer = value in adapter->dmac in 32usec intervals */
+		reg |= (adapter->dmac >> 5);
 		E1000_WRITE_REG(hw, E1000_DMACR, reg);
 
 		/* No lower threshold */
@@ -2767,6 +2775,7 @@ igb_reset(struct adapter *adapter)
 		device_printf(dev, "DMA Coalescing enabled\n");
 	}
 
+reset_out:
 	E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN);
 	e1000_get_phy_info(hw);
 	e1000_check_for_link(hw);
@@ -2827,15 +2836,19 @@ igb_setup_interface(device_t dev, struct
 	 * support full VLAN capability.
 	 */
 	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
-	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
-	ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
+	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING
+			     |  IFCAP_VLAN_HWTSO
+			     |  IFCAP_VLAN_MTU;
+	ifp->if_capenable |= IFCAP_VLAN_HWTAGGING
+			  |  IFCAP_VLAN_HWTSO
+			  |  IFCAP_VLAN_MTU;
 
 	/*
-	** Dont turn this on by default, if vlans are
+	** Don't turn this on by default, if vlans are
 	** created on another pseudo device (eg. lagg)
 	** then vlan events are not passed thru, breaking
 	** operation, but with HW FILTER off it works. If
-	** using vlans directly on the em driver you can
+	** using vlans directly on the igb driver you can
 	** enable this and get full hardware tag filtering.
 	*/
 	ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
@@ -5595,19 +5608,18 @@ static int
 igb_set_flowcntl(SYSCTL_HANDLER_ARGS)
 {
 	int error;
-	struct adapter *adapter;
+	struct adapter *adapter = (struct adapter *) arg1;
 
-	error = sysctl_handle_int(oidp, &igb_fc_setting, 0, req);
+	error = sysctl_handle_int(oidp, &adapter->fc, 0, req);
 
-	if (error)
+	if ((error) || (req->newptr == NULL))
 		return (error);
 
-	adapter = (struct adapter *) arg1;
-	switch (igb_fc_setting) {
+	switch (adapter->fc) {
 		case e1000_fc_rx_pause:
 		case e1000_fc_tx_pause:
 		case e1000_fc_full:
-			adapter->hw.fc.requested_mode = igb_fc_setting;
+			adapter->hw.fc.requested_mode = adapter->fc;
 			break;
 		case e1000_fc_none:
 		default:
@@ -5616,5 +5628,54 @@ igb_set_flowcntl(SYSCTL_HANDLER_ARGS)
 
 	adapter->hw.fc.current_mode = adapter->hw.fc.requested_mode;
 	e1000_force_mac_fc(&adapter->hw);
-	return error;
+	return (error);
+}
+
+/*
+** Manage DMA Coalesce:
+** Control values:
+** 	0/1 - off/on
+**	Legal timer values are:
+**	250,500,1000-10000 in thousands
+*/
+static int
+igb_sysctl_dmac(SYSCTL_HANDLER_ARGS)
+{
+	struct adapter *adapter = (struct adapter *) arg1;
+	int		error;
+
+	error = sysctl_handle_int(oidp, &adapter->dmac, 0, req);
+
+	if ((error) || (req->newptr == NULL))
+		return (error);
+
+	switch (adapter->dmac) {
+		case 0:
+			/*Disabling */
+			break;
+		case 1: /* Just enable and use default */
+			adapter->dmac = 1000;
+			break;
+		case 250:
+		case 500:
+		case 1000:
+		case 2000:
+		case 3000:
+		case 4000:
+		case 5000:
+		case 6000:
+		case 7000:
+		case 8000:
+		case 9000:
+		case 10000:
+			/* Legal values - allow */
+			break;
+		default:
+			/* Do nothing, illegal value */
+			adapter->dmac = 0;
+			return (error);
+	}
+	/* Reinit the interface */
+	igb_init(adapter);
+	return (error);
 }

Modified: head/sys/dev/e1000/if_igb.h
==============================================================================
--- head/sys/dev/e1000/if_igb.h	Mon Jun 20 22:02:01 2011	(r223349)
+++ head/sys/dev/e1000/if_igb.h	Mon Jun 20 22:59:29 2011	(r223350)
@@ -396,11 +396,12 @@ struct adapter {
 	u32		shadow_vfta[IGB_VFTA_SIZE];
 
 	/* Info about the interface */
-	u8		link_active;
+	u16		link_active;
+	u16		fc;
 	u16		link_speed;
 	u16		link_duplex;
 	u32		smartspeed;
-	u32		dma_coalesce;
+	u32		dmac;
 
 	/* Interface queues */
 	struct igb_queue	*queues;


More information about the svn-src-all mailing list