svn commit: r213569 - projects/sv/sys/dev/ixgbe

Attilio Rao attilio at FreeBSD.org
Fri Oct 8 10:42:17 UTC 2010


Author: attilio
Date: Fri Oct  8 10:42:16 2010
New Revision: 213569
URL: http://svn.freebsd.org/changeset/base/213569

Log:
  Add the support for polling on ixgbe. It is mostly modelled on what
  ixgb already does.
  
  Small questions:
  - does the IFF_DRV_RUNNING check might be kept unlocked? I can't find
    an uniform locking pattern for it looking around and it seems
    mostly unlocked.
  - reading IXGBE_EICR and _LSC should be unlocked? It seems functions do
    this way.
  - In case ixgbe_rxeof() returns 'more' should we schedule the taskqueue?
    ixgb polling doesn't do that, so I'd like to hear more opinion in return.

Modified:
  projects/sv/sys/dev/ixgbe/ixgbe.c

Modified: projects/sv/sys/dev/ixgbe/ixgbe.c
==============================================================================
--- projects/sv/sys/dev/ixgbe/ixgbe.c	Fri Oct  8 10:27:52 2010	(r213568)
+++ projects/sv/sys/dev/ixgbe/ixgbe.c	Fri Oct  8 10:42:16 2010	(r213569)
@@ -141,7 +141,7 @@ static void     ixgbe_enable_intr(struct
 static void     ixgbe_disable_intr(struct adapter *);
 static void     ixgbe_update_stats_counters(struct adapter *);
 static bool	ixgbe_txeof(struct tx_ring *);
-static bool	ixgbe_rxeof(struct ix_queue *, int);
+static bool	ixgbe_rxeof(struct ix_queue *, int, int *);
 static void	ixgbe_rx_checksum(u32, struct mbuf *, u32);
 static void     ixgbe_set_promisc(struct adapter *);
 static void     ixgbe_disable_promisc(struct adapter *);
@@ -195,6 +195,10 @@ static void	ixgbe_atr(struct tx_ring *, 
 static void	ixgbe_reinit_fdir(void *, int);
 #endif
 
+#ifdef DEVICE_POLLING
+static poll_handler_t ixgbe_poll;
+#endif
+
 /*********************************************************************
  *  FreeBSD Device Interface Entry Points
  *********************************************************************/
@@ -675,6 +679,11 @@ ixgbe_detach(device_t dev)
 		return (EBUSY);
 	}
 
+#ifdef DEVICE_POLLING
+	if ((adapter->ifp->if_capenable & IFCAP_POLLING) != 0)
+		ether_poll_deregister(adapter->ifp);
+#endif
+
 	IXGBE_CORE_LOCK(adapter);
 	ixgbe_stop(adapter);
 	IXGBE_CORE_UNLOCK(adapter);
@@ -979,6 +988,25 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c
 	{
 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
 		IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)");
+#ifdef DEVICE_POLLING
+		if ((mask & IFCAP_POLLING) != 0) {
+			if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) {
+				error = ether_poll_register(ixgbe_poll, ifp);
+				if (error != 0)
+					return (error);
+				IXGBE_CORE_LOCK(adapter);
+				ixgbe_disable_intr(adapter);
+				ifp->if_capenable |= IFCAP_POLLING;
+				IXGBE_CORE_UNLOCK(adapter);
+			} else {
+				error = ether_poll_deregister(ifp);
+				IXGBE_CORE_LOCK(adapter);
+				ixgbe_enable_intr(adapter);
+				ifp->if_capenable &= ~IFCAP_POLLING;
+				IXGBE_CORE_UNLOCK(adapter);
+			}
+		}
+#endif /* !DEVICE_POLLING */
 		if (mask & IFCAP_HWCSUM)
 			ifp->if_capenable ^= IFCAP_HWCSUM;
 		if (mask & IFCAP_TSO4)
@@ -1199,8 +1227,13 @@ ixgbe_init_locked(struct adapter *adapte
 	/* Config/Enable Link */
 	ixgbe_config_link(adapter);
 
-	/* And now turn on interrupts */
-	ixgbe_enable_intr(adapter);
+#ifdef DEVICE_POLLING
+	/* Disable interrupts if polling is on, enable otherwise. */
+	if ((ifp->if_capenable & IFCAP_POLLING) != 0)
+		ixgbe_disable_intr(adapter);
+	else
+#endif
+		ixgbe_enable_intr(adapter);
 
 	/* Now inform the stack we're ready */
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -1294,7 +1327,7 @@ ixgbe_handle_que(void *context, int pend
 	bool		more;
 
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
-		more = ixgbe_rxeof(que, adapter->rx_process_limit);
+		more = ixgbe_rxeof(que, adapter->rx_process_limit, NULL);
 		IXGBE_TX_LOCK(txr);
 		ixgbe_txeof(txr);
 #if __FreeBSD_version >= 800000
@@ -1333,6 +1366,10 @@ ixgbe_legacy_irq(void *arg)
 	bool		more_tx, more_rx;
 	u32       	reg_eicr, loop = MAX_LOOP;
 
+#ifdef DEVICE_POLLING
+	if ((adapter->ifp->if_capenable & IFCAP_POLLING) != 0)
+		return;
+#endif
 
 	reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
 
@@ -1342,7 +1379,7 @@ ixgbe_legacy_irq(void *arg)
 		return;
 	}
 
-	more_rx = ixgbe_rxeof(que, adapter->rx_process_limit);
+	more_rx = ixgbe_rxeof(que, adapter->rx_process_limit, NULL);
 
 	IXGBE_TX_LOCK(txr);
 	do {
@@ -1387,13 +1424,13 @@ ixgbe_msix_que(void *arg)
 
 	++que->irqs;
 
-	more_rx = ixgbe_rxeof(que, adapter->rx_process_limit);
+	more_rx = ixgbe_rxeof(que, adapter->rx_process_limit, NULL);
 
 	IXGBE_TX_LOCK(txr);
 	more_tx = ixgbe_txeof(txr);
 	IXGBE_TX_UNLOCK(txr);
 
-	more_rx = ixgbe_rxeof(que, adapter->rx_process_limit);
+	more_rx = ixgbe_rxeof(que, adapter->rx_process_limit, NULL);
 
 	/* Do AIM now? */
 
@@ -2417,6 +2454,9 @@ ixgbe_setup_interface(device_t dev, stru
 	ifp->if_capabilities |= IFCAP_JUMBO_MTU | IFCAP_LRO;
 
 	ifp->if_capenable = ifp->if_capabilities;
+#ifdef DEVICE_POLLING
+	ifp->if_capabilities |= IFCAP_POLLING;
+#endif
 
 	/*
 	 * Specify the media types supported by this adapter and register
@@ -3262,6 +3302,52 @@ ixgbe_atr(struct tx_ring *txr, struct mb
 }
 #endif
 
+#ifdef DEVICE_POLLING
+static int
+ixgbe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+	struct adapter *adapter;
+	struct tx_ring *txr;
+	struct ix_queue *que;
+	struct ixgbe_hw *hw;
+	u32 loop, reg_eicr;
+	int rx_npkts;
+	bool more_tx;
+
+	adapter = ifp->if_softc;
+	txr = adapter->tx_rings;
+	que = adapter->queues;
+	hw = &adapter->hw;
+	loop = MAX_LOOP;
+	rx_npkts = 0;
+
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return (rx_npkts);
+
+	if (cmd == POLL_AND_CHECK_STATUS) {
+		reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+
+		/* Link status change */
+		if ((reg_eicr & IXGBE_EICR_LSC) != 0)
+			taskqueue_enqueue(adapter->tq, &adapter->link_task);
+	}
+	ixgbe_rxeof(que, count, &rx_npkts);
+	IXGBE_TX_LOCK(txr);
+	do {
+		more_tx = ixgbe_txeof(txr);
+	} while (loop-- && more_tx);
+#if __FreeBSD_version >= 800000
+	if (!drbr_empty(ifp, txr->br))
+		ixgbe_mq_start_locked(ifp, txr, NULL);
+#else
+	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+		ixgbe_start_locked(txr, ifp);
+#endif
+	IXGBE_TX_UNLOCK(txr);
+	return (rx_npkts);
+}
+#endif
+
 /**********************************************************************
  *
  *  Examine each tx_buffer in the used queue. If the hardware is done
@@ -4062,14 +4148,14 @@ ixgbe_rx_discard(struct rx_ring *rxr, in
  *  Return TRUE for more work, FALSE for all clean.
  *********************************************************************/
 static bool
-ixgbe_rxeof(struct ix_queue *que, int count)
+ixgbe_rxeof(struct ix_queue *que, int count, int *rx_npktsp)
 {
 	struct adapter		*adapter = que->adapter;
 	struct rx_ring		*rxr = que->rxr;
 	struct ifnet		*ifp = adapter->ifp;
 	struct lro_ctrl		*lro = &rxr->lro;
 	struct lro_entry	*queued;
-	int			i, nextp, processed = 0;
+	int			i, nextp, processed = 0, rx_npkts = 0;
 	u32			staterr = 0;
 	union ixgbe_adv_rx_desc	*cur;
 	struct ixgbe_rx_buf	*rbuf, *nbuf;
@@ -4273,8 +4359,10 @@ next_desc:
 			i = 0;
 
 		/* Now send to the stack or do LRO */
-		if (sendmp != NULL)
+		if (sendmp != NULL) {
 			ixgbe_rx_input(rxr, ifp, sendmp, ptype);
+			rx_npkts++;
+		}
 
                /* Every 8 descriptors we go to refresh mbufs */
 		if (processed == 8) {
@@ -4307,9 +4395,13 @@ next_desc:
 	*/
 	if ((staterr & IXGBE_RXD_STAT_DD) != 0) {
 		ixgbe_rearm_queues(adapter, (u64)(1 << que->msix));
+		if (rx_npktsp != NULL)
+			*rx_npktsp = rx_npkts;
 		return (TRUE);
 	}
 
+	if (rx_npktsp != NULL)
+		*rx_npktsp = rx_npkts;
 	return (FALSE);
 }
 


More information about the svn-src-projects mailing list