EtherCAT functionality of igb driver. stable-1.5
authorFlorian Pose <fp@igh.de>
Thu, 12 Oct 2017 13:08:15 +0200
branchstable-1.5
changeset 2686 91cb9cf20f6c
parent 2685 740291442c05
child 2687 ac94c7ec73e6
EtherCAT functionality of igb driver.
devices/igb/igb-3.18-ethercat.h
devices/igb/igb_main-3.18-ethercat.c
--- a/devices/igb/igb-3.18-ethercat.h	Fri Sep 08 14:39:38 2017 +0200
+++ b/devices/igb/igb-3.18-ethercat.h	Thu Oct 12 13:08:15 2017 +0200
@@ -19,6 +19,8 @@
  * Contact Information:
  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * vim: noexpandtab
  */
 
 /* Linux PRO/1000 Ethernet Driver main header file */
@@ -26,6 +28,9 @@
 #ifndef _IGB_H_
 #define _IGB_H_
 
+/* EtherCAT header file */
+#include "../ecdev.h"
+
 #include "e1000_mac-3.18-ethercat.h"
 #include "e1000_82575-3.18-ethercat.h"
 
@@ -454,6 +459,10 @@
 	int copper_tries;
 	struct e1000_info ei;
 	u16 eee_advert;
+
+	/* EtherCAT device variables */
+	ec_device_t *ecdev;
+	unsigned long ec_watchdog_jiffies;
 };
 
 #define IGB_FLAG_HAS_MSI		(1 << 0)
--- a/devices/igb/igb_main-3.18-ethercat.c	Fri Sep 08 14:39:38 2017 +0200
+++ b/devices/igb/igb_main-3.18-ethercat.c	Thu Oct 12 13:08:15 2017 +0200
@@ -19,6 +19,8 @@
  * Contact Information:
  * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * vim: noexpandtab
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -60,11 +62,11 @@
 #define MIN 2
 #define BUILD 15
 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
-__stringify(BUILD) "-k"
-char igb_driver_name[] = "igb";
+__stringify(BUILD) "-k-EtherCAT"
+char igb_driver_name[] = "ec_igb";
 char igb_driver_version[] = DRV_VERSION;
 static const char igb_driver_string[] =
-				"Intel(R) Gigabit Ethernet Network Driver";
+	"Intel(R) Gigabit Ethernet Network Driver (EtherCAT-enabled)";
 static const char igb_copyright[] =
 				"Copyright (c) 2007-2014 Intel Corporation.";
 
@@ -112,7 +114,7 @@
 	{0, }
 };
 
-MODULE_DEVICE_TABLE(pci, igb_pci_tbl);
+// MODULE_DEVICE_TABLE(pci, igb_pci_tbl);
 
 static int igb_setup_all_tx_resources(struct igb_adapter *);
 static int igb_setup_all_rx_resources(struct igb_adapter *);
@@ -949,6 +951,11 @@
 	struct e1000_hw *hw = &adapter->hw;
 	int i, err = 0, vector = 0, free_vector = 0;
 
+	if (adapter->ecdev) {
+		/* avoid requesting MSI-X. */
+		return 0;
+	}
+
 	err = request_irq(adapter->msix_entries[vector].vector,
 			  igb_msix_other, 0, netdev->name, adapter);
 	if (err)
@@ -1040,7 +1047,9 @@
 	if (q_vector->rx.ring)
 		adapter->tx_ring[q_vector->rx.ring->queue_index] = NULL;
 
-	netif_napi_del(&q_vector->napi);
+	if (!adapter->ecdev) {
+		netif_napi_del(&q_vector->napi);
+	}
 
 }
 
@@ -1212,9 +1221,11 @@
 	if (!q_vector)
 		return -ENOMEM;
 
-	/* initialize NAPI */
-	netif_napi_add(adapter->netdev, &q_vector->napi,
-		       igb_poll, 64);
+	if (!adapter->ecdev) {
+		/* initialize NAPI */
+		netif_napi_add(adapter->netdev, &q_vector->napi,
+				igb_poll, 64);
+	}
 
 	/* tie q_vector and adapter together */
 	adapter->q_vector[v_idx] = q_vector;
@@ -1426,7 +1437,7 @@
 
 	igb_assign_vector(adapter->q_vector[0], 0);
 
-	if (adapter->flags & IGB_FLAG_HAS_MSI) {
+	if (!adapter->ecdev && adapter->flags & IGB_FLAG_HAS_MSI) {
 		err = request_irq(pdev->irq, igb_intr_msi, 0,
 				  netdev->name, adapter);
 		if (!err)
@@ -1437,12 +1448,14 @@
 		adapter->flags &= ~IGB_FLAG_HAS_MSI;
 	}
 
-	err = request_irq(pdev->irq, igb_intr, IRQF_SHARED,
-			  netdev->name, adapter);
-
-	if (err)
-		dev_err(&pdev->dev, "Error %d getting interrupt\n",
-			err);
+	if (!adapter->ecdev) {
+		err = request_irq(pdev->irq, igb_intr, IRQF_SHARED,
+				netdev->name, adapter);
+
+		if (err)
+			dev_err(&pdev->dev, "Error %d getting interrupt\n",
+					err);
+	}
 
 request_done:
 	return err;
@@ -1450,6 +1463,11 @@
 
 static void igb_free_irq(struct igb_adapter *adapter)
 {
+	if (adapter->ecdev) {
+		/* no IRQ to free in EtherCAT operation */
+		return;
+	}
+
 	if (adapter->flags & IGB_FLAG_HAS_MSIX) {
 		int vector = 0, i;
 
@@ -1487,6 +1505,12 @@
 	wr32(E1000_IAM, 0);
 	wr32(E1000_IMC, ~0);
 	wrfl();
+
+	if (adapter->ecdev) {
+		/* skip synchonizing IRQs */
+		return;
+	}
+
 	if (adapter->flags & IGB_FLAG_HAS_MSIX) {
 		int i;
 
@@ -1505,6 +1529,11 @@
 {
 	struct e1000_hw *hw = &adapter->hw;
 
+	if (adapter->ecdev) {
+		/* skip enabling interrupts */
+		return;
+	}
+
 	if (adapter->flags & IGB_FLAG_HAS_MSIX) {
 		u32 ims = E1000_IMS_LSC | E1000_IMS_DOUTSYNC | E1000_IMS_DRSTA;
 		u32 regval = rd32(E1000_EIAC);
@@ -1728,8 +1757,10 @@
 
 	clear_bit(__IGB_DOWN, &adapter->state);
 
-	for (i = 0; i < adapter->num_q_vectors; i++)
-		napi_enable(&(adapter->q_vector[i]->napi));
+	if (!adapter->ecdev) {
+		for (i = 0; i < adapter->num_q_vectors; i++)
+			napi_enable(&(adapter->q_vector[i]->napi));
+	}
 
 	if (adapter->flags & IGB_FLAG_HAS_MSIX)
 		igb_configure_msix(adapter);
@@ -1748,11 +1779,13 @@
 		wr32(E1000_CTRL_EXT, reg_data);
 	}
 
-	netif_tx_start_all_queues(adapter->netdev);
-
-	/* start the watchdog. */
-	hw->mac.get_link_status = 1;
-	schedule_work(&adapter->watchdog_task);
+	if (!adapter->ecdev) {
+		netif_tx_start_all_queues(adapter->netdev);
+
+		/* start the watchdog. */
+		hw->mac.get_link_status = 1;
+		schedule_work(&adapter->watchdog_task);
+	}
 
 	if ((adapter->flags & IGB_FLAG_EEE) &&
 	    (!hw->dev_spec._82575.eee_disable))
@@ -1778,7 +1811,9 @@
 	wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
 	/* flush and sleep below */
 
-	netif_tx_stop_all_queues(netdev);
+	if (!adapter->ecdev) {
+		netif_tx_stop_all_queues(netdev);
+	}
 
 	/* disable transmits in the hardware */
 	tctl = rd32(E1000_TCTL);
@@ -1793,7 +1828,7 @@
 	adapter->flags &= ~IGB_FLAG_NEED_LINK_UPDATE;
 
 	for (i = 0; i < adapter->num_q_vectors; i++) {
-		if (adapter->q_vector[i]) {
+		if (!adapter->ecdev && adapter->q_vector[i]) {
 			napi_synchronize(&adapter->q_vector[i]->napi);
 			napi_disable(&adapter->q_vector[i]->napi);
 		}
@@ -1803,7 +1838,9 @@
 	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_info_timer);
 
-	netif_carrier_off(netdev);
+	if (!adapter->ecdev) {
+		netif_carrier_off(netdev);
+	}
 
 	/* record the stats before reset*/
 	spin_lock(&adapter->stats64_lock);
@@ -2024,7 +2061,7 @@
 			break;
 		}
 	}
-	if (!netif_running(adapter->netdev))
+	if (!adapter->ecdev && !netif_running(adapter->netdev))
 		igb_power_down_link(adapter);
 
 	igb_update_mng_vlan(adapter);
@@ -2100,6 +2137,40 @@
 };
 
 /**
+ * ec_poll - EtherCAT poll routine
+ * @netdev: net device structure
+ *
+ * This function can never fail.
+ *
+ **/
+void ec_poll(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	int i;
+	int budget = 64;
+
+	if (jiffies - adapter->ec_watchdog_jiffies >= 2 * HZ) {
+		struct e1000_hw *hw = &adapter->hw;
+		bool link;
+		hw->mac.get_link_status = true;
+		link = igb_has_link(adapter);
+		ecdev_set_link(adapter->ecdev, link);
+		adapter->ec_watchdog_jiffies = jiffies;
+	}
+
+	for (i = 0; i < adapter->num_q_vectors; i++) {
+		struct igb_q_vector *q_vector = adapter->q_vector[i];
+		if (q_vector->tx.ring) {
+			igb_clean_tx_irq(q_vector);
+		}
+
+		if (q_vector->rx.ring) {
+			igb_clean_rx_irq(q_vector, budget);
+		}
+	}
+}
+
+/**
  * igb_set_fw_version - Configure version string for ethtool
  * @adapter: adapter struct
  **/
@@ -2540,13 +2611,23 @@
 	 */
 	igb_get_hw_control(adapter);
 
-	strcpy(netdev->name, "eth%d");
-	err = register_netdev(netdev);
-	if (err)
-		goto err_register;
-
-	/* carrier off reporting is important to ethtool even BEFORE open */
-	netif_carrier_off(netdev);
+	adapter->ecdev = ecdev_offer(netdev, ec_poll, THIS_MODULE);
+	if (adapter->ecdev) {
+		err = ecdev_open(adapter->ecdev);
+		if (err) {
+			ecdev_withdraw(adapter->ecdev);
+			goto err_register;
+		}
+		adapter->ec_watchdog_jiffies = jiffies;
+	} else {
+		strcpy(netdev->name, "eth%d");
+		err = register_netdev(netdev);
+		if (err)
+			goto err_register;
+
+		/* carrier off reporting is important to ethtool even BEFORE open */
+		netif_carrier_off(netdev);
+	}
 
 #ifdef CONFIG_IGB_DCA
 	if (dca_add_requester(&pdev->dev) == 0) {
@@ -2789,6 +2870,11 @@
 	struct igb_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
+	if (adapter->ecdev) {
+		ecdev_close(adapter->ecdev);
+		ecdev_withdraw(adapter->ecdev);
+	}
+
 	pm_runtime_get_noresume(&pdev->dev);
 #ifdef CONFIG_IGB_HWMON
 	igb_sysfs_exit(adapter);
@@ -2819,7 +2905,9 @@
 	 */
 	igb_release_hw_control(adapter);
 
-	unregister_netdev(netdev);
+	if (!adapter->ecdev) {
+		unregister_netdev(netdev);
+	}
 
 	igb_clear_interrupt_scheme(adapter);
 
@@ -3035,7 +3123,12 @@
 	if (!resuming)
 		pm_runtime_get_sync(&pdev->dev);
 
-	netif_carrier_off(netdev);
+	if (adapter->ecdev) {
+		ecdev_set_link(adapter->ecdev, 0);
+	}
+	else {
+		netif_carrier_off(netdev);
+	}
 
 	/* allocate transmit descriptors */
 	err = igb_setup_all_tx_resources(adapter);
@@ -3060,22 +3153,26 @@
 	if (err)
 		goto err_req_irq;
 
-	/* Notify the stack of the actual queue counts. */
-	err = netif_set_real_num_tx_queues(adapter->netdev,
-					   adapter->num_tx_queues);
-	if (err)
-		goto err_set_queues;
-
-	err = netif_set_real_num_rx_queues(adapter->netdev,
-					   adapter->num_rx_queues);
-	if (err)
-		goto err_set_queues;
+	if (!adapter->ecdev) {
+		/* Notify the stack of the actual queue counts. */
+		err = netif_set_real_num_tx_queues(adapter->netdev,
+						   adapter->num_tx_queues);
+		if (err)
+			goto err_set_queues;
+
+		err = netif_set_real_num_rx_queues(adapter->netdev,
+						   adapter->num_rx_queues);
+		if (err)
+			goto err_set_queues;
+	}
 
 	/* From here on the code is the same as igb_up() */
 	clear_bit(__IGB_DOWN, &adapter->state);
 
-	for (i = 0; i < adapter->num_q_vectors; i++)
-		napi_enable(&(adapter->q_vector[i]->napi));
+	if (!adapter->ecdev) {
+		for (i = 0; i < adapter->num_q_vectors; i++)
+			napi_enable(&(adapter->q_vector[i]->napi));
+	}
 
 	/* Clear any pending interrupts. */
 	rd32(E1000_ICR);
@@ -3090,14 +3187,18 @@
 		wr32(E1000_CTRL_EXT, reg_data);
 	}
 
-	netif_tx_start_all_queues(netdev);
+	if (!adapter->ecdev) {
+		netif_tx_start_all_queues(netdev);
+	}
 
 	if (!resuming)
 		pm_runtime_put(&pdev->dev);
 
-	/* start the watchdog. */
-	hw->mac.get_link_status = 1;
-	schedule_work(&adapter->watchdog_task);
+	if (!adapter->ecdev) {
+		/* start the watchdog. */
+		hw->mac.get_link_status = 1;
+		schedule_work(&adapter->watchdog_task);
+	}
 
 	return 0;
 
@@ -3728,7 +3829,11 @@
 				    struct igb_tx_buffer *tx_buffer)
 {
 	if (tx_buffer->skb) {
-		dev_kfree_skb_any(tx_buffer->skb);
+		struct igb_adapter *adapter = netdev_priv(ring->netdev);
+		if (!adapter->ecdev) {
+			/* skb is reused in EtherCAT TX operation */
+			dev_kfree_skb_any(tx_buffer->skb);
+		}
 		if (dma_unmap_len(tx_buffer, len))
 			dma_unmap_single(ring->dev,
 					 dma_unmap_addr(tx_buffer, dma),
@@ -4823,8 +4928,11 @@
 static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
 {
 	struct net_device *netdev = tx_ring->netdev;
-
-	netif_stop_subqueue(netdev, tx_ring->queue_index);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	if (!adapter->ecdev) {
+		netif_stop_subqueue(netdev, tx_ring->queue_index);
+	}
 
 	/* Herbert's original patch had:
 	 *  smp_mb__after_netif_stop_queue();
@@ -4839,7 +4947,9 @@
 		return -EBUSY;
 
 	/* A reprieve! */
-	netif_wake_subqueue(netdev, tx_ring->queue_index);
+	if (!adapter->ecdev) {
+		netif_wake_subqueue(netdev, tx_ring->queue_index);
+	}
 
 	u64_stats_update_begin(&tx_ring->tx_syncp2);
 	tx_ring->tx_stats.restart_queue2++;
@@ -4996,6 +5106,7 @@
 	u16 count = TXD_USE_COUNT(skb_headlen(skb));
 	__be16 protocol = vlan_get_protocol(skb);
 	u8 hdr_len = 0;
+	struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
 
 	/* need: 1 descriptor per page * PAGE_SIZE/IGB_MAX_DATA_PER_TXD,
 	 *       + 1 desc for skb_headlen/IGB_MAX_DATA_PER_TXD,
@@ -5023,8 +5134,8 @@
 	first->bytecount = skb->len;
 	first->gso_segs = 1;
 
-	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
-		struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
+	if (unlikely(!adapter->ecdev &&
+				(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) {
 
 		if (!test_and_set_bit_lock(__IGB_PTP_TX_IN_PROGRESS,
 					   &adapter->state)) {
@@ -5082,12 +5193,16 @@
 	struct igb_adapter *adapter = netdev_priv(netdev);
 
 	if (test_bit(__IGB_DOWN, &adapter->state)) {
-		dev_kfree_skb_any(skb);
+		if (!adapter->ecdev) {
+			dev_kfree_skb_any(skb);
+		}
 		return NETDEV_TX_OK;
 	}
 
 	if (skb->len <= 0) {
-		dev_kfree_skb_any(skb);
+		if (!adapter->ecdev) {
+			dev_kfree_skb_any(skb);
+		}
 		return NETDEV_TX_OK;
 	}
 
@@ -6380,8 +6495,10 @@
 		total_bytes += tx_buffer->bytecount;
 		total_packets += tx_buffer->gso_segs;
 
-		/* free the skb */
-		dev_consume_skb_any(tx_buffer->skb);
+		if (!adapter->ecdev) {
+			/* free the skb */
+			dev_consume_skb_any(tx_buffer->skb);
+		}
 
 		/* unmap skb header data */
 		dma_unmap_single(tx_ring->dev,
@@ -6431,8 +6548,10 @@
 		budget--;
 	} while (likely(budget));
 
-	netdev_tx_completed_queue(txring_txq(tx_ring),
-				  total_packets, total_bytes);
+	if (!adapter->ecdev) {
+		netdev_tx_completed_queue(txring_txq(tx_ring),
+					  total_packets, total_bytes);
+	}
 	i += tx_ring->count;
 	tx_ring->next_to_clean = i;
 	u64_stats_update_begin(&tx_ring->tx_syncp);
@@ -6442,7 +6561,8 @@
 	q_vector->tx.total_bytes += total_bytes;
 	q_vector->tx.total_packets += total_packets;
 
-	if (test_bit(IGB_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags)) {
+	if (!adapter->ecdev &&
+			test_bit(IGB_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags)) {
 		struct e1000_hw *hw = &adapter->hw;
 
 		/* Detect a transmit hang in hardware, this serializes the
@@ -6485,7 +6605,7 @@
 	}
 
 #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
-	if (unlikely(total_packets &&
+	if (unlikely(!adapter->ecdev && total_packets &&
 	    netif_carrier_ok(tx_ring->netdev) &&
 	    igb_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD)) {
 		/* Make sure that anybody stopping the queue after this
@@ -6634,13 +6754,14 @@
 {
 	struct igb_rx_buffer *rx_buffer;
 	struct page *page;
+	struct igb_adapter *adapter = netdev_priv(rx_ring->netdev);
 
 	rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
 
 	page = rx_buffer->page;
 	prefetchw(page);
 
-	if (likely(!skb)) {
+	if (!adapter->ecdev && likely(!skb)) {
 		void *page_addr = page_address(page) +
 				  rx_buffer->page_offset;
 
@@ -6672,18 +6793,27 @@
 				      IGB_RX_BUFSZ,
 				      DMA_FROM_DEVICE);
 
-	/* pull page into skb */
-	if (igb_add_rx_frag(rx_ring, rx_buffer, rx_desc, skb)) {
-		/* hand second half of page back to the ring */
+	if (adapter->ecdev) {
+		unsigned char *va =
+			page_address(rx_buffer->page) + rx_buffer->page_offset;
+		unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
+		ecdev_receive(adapter->ecdev, va, size);
 		igb_reuse_rx_page(rx_ring, rx_buffer);
-	} else {
-		/* we are not reusing the buffer so unmap it */
-		dma_unmap_page(rx_ring->dev, rx_buffer->dma,
-			       PAGE_SIZE, DMA_FROM_DEVICE);
-	}
-
-	/* clear contents of rx_buffer */
-	rx_buffer->page = NULL;
+	}
+	else {
+		/* pull page into skb */
+		if (igb_add_rx_frag(rx_ring, rx_buffer, rx_desc, skb)) {
+			/* hand second half of page back to the ring */
+			igb_reuse_rx_page(rx_ring, rx_buffer);
+		} else {
+			/* we are not reusing the buffer so unmap it */
+			dma_unmap_page(rx_ring->dev, rx_buffer->dma,
+					   PAGE_SIZE, DMA_FROM_DEVICE);
+		}
+
+		/* clear contents of rx_buffer */
+		rx_buffer->page = NULL;
+	}
 
 	return skb;
 }
@@ -6910,6 +7040,7 @@
 static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
 {
 	struct igb_ring *rx_ring = q_vector->rx.ring;
+	struct igb_adapter *adapter = netdev_priv(rx_ring->netdev);
 	struct sk_buff *skb = rx_ring->skb;
 	unsigned int total_bytes = 0, total_packets = 0;
 	u16 cleaned_count = igb_desc_unused(rx_ring);
@@ -6938,8 +7069,9 @@
 		skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
 
 		/* exit if we failed to retrieve a buffer */
-		if (!skb)
+		if (!adapter->ecdev && !skb) {
 			break;
+		}
 
 		cleaned_count++;
 
@@ -6947,6 +7079,11 @@
 		if (igb_is_non_eop(rx_ring, rx_desc))
 			continue;
 
+		if (adapter->ecdev) {
+			total_packets++;
+			continue;
+		}
+
 		/* verify the packet layout is correct */
 		if (igb_cleanup_headers(rx_ring, rx_desc, skb)) {
 			skb = NULL;