Re: [PATCH netdev-2.6] jme: JMicron Gigabit Ethernet Driver

Previous thread: [PATCH 1/1] usbnet: allow type check of devdbg arguments in non-debug build by Steve Glendinning on Monday, September 15, 2008 - 8:47 am. (10 messages)

Next thread: Bonding and Neighbour Discovery on IPv6-only devices by Alex Sidorenko on Monday, September 15, 2008 - 10:35 am. (18 messages)
From: Guo-Fu Tseng
Date: Monday, September 15, 2008 - 10:00 am

Dear Jeff:

Here is full patch for the JMicron Gigabit Ethernet driver.
Supporting JMC250, and JMC260.

The patch is also available at:
http://cooldavid.org/download/jme.netdev-2.6.20080916.patch

Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>
---
diff -uprN -X ./dontdiff netdev-2.6/drivers/net/jme.c linux/drivers/net/jme.c
--- netdev-2.6/drivers/net/jme.c	1970-01-01 08:00:00.000000000 +0800
+++ linux/drivers/net/jme.c	2008-09-16 00:54:46.000000000 +0800
@@ -0,0 +1,3019 @@
+/*
+ * JMicron JMC2x0 series PCIe Ethernet Linux Device Driver
+ *
+ * Copyright 2008 JMicron Technology Corporation
+ * http://www.jmicron.com/
+ *
+ * Author: Guo-Fu Tseng <cooldavid@cooldavid.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if_vlan.h>
+#include "jme.h"
+
+static int force_pseudohp = -1;
+static int no_pseudohp = -1;
+static int no_extplug = -1;
+module_param(force_pseudohp, int, ...
From: Ethan
Date: Monday, September 15, 2008 - 7:47 pm

Dear Guo-Fu:

It works fine, thanks!

Acked-and-tested-by: Ethan Hsiao <ethanhsiao@jmicron.com>

Regards,
> +		val = jr
From: Jeff Garzik
Date: Thursday, September 18, 2008 - 9:07 am

applied

--

From: Guo-Fu Tseng
Date: Wednesday, October 8, 2008 - 2:56 pm

Dear Jeff, David:

This patch:

    1. Set bit 5 of GPREG1 to 1 to enable hardware workaround for half-duplex
       mode. Which the MAC processor generates CRS/COL by itself instead of
       receive it from PHY processor.

    2. Set bit 6 of GPREG1 to 1 to enable hardware workaround that masks the
       MAC processor working right while calculating IPv6 RSS in 10/100
       mode.

    3. Group the workaround codes all together.

    The patch is also available at:
    http://cooldavid.org/download/jme.net-next-2.6.20081009.1.patch

    Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index f292df5..635f616 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -190,7 +190,7 @@ jme_reset_mac_processor(struct jme_adapter *jme)
 	else
 		gpreg0 = GPREG0_DEFAULT;
 	jwrite32(jme, JME_GPREG0, gpreg0);
-	jwrite32(jme, JME_GPREG1, 0);
+	jwrite32(jme, JME_GPREG1, GPREG1_DEFAULT);
 }
 
 static inline void
@@ -365,7 +365,7 @@ static int
 jme_check_link(struct net_device *netdev, int testonly)
 {
 	struct jme_adapter *jme = netdev_priv(netdev);
-	u32 phylink, ghc, cnt = JME_SPDRSV_TIMEOUT, bmcr;
+	u32 phylink, ghc, cnt = JME_SPDRSV_TIMEOUT, bmcr, gpreg1;
 	char linkmsg[64];
 	int rc = 0;
 
@@ -437,37 +437,22 @@ jme_check_link(struct net_device *netdev, int testonly)
 		case PHY_LINK_SPEED_10M:
 			ghc |= GHC_SPEED_10M;
 			strcat(linkmsg, "10 Mbps, ");
-			if (is_buggy250(jme->pdev->device, jme->chiprev))
-				jme_set_phyfifoa(jme);
 			break;
 		case PHY_LINK_SPEED_100M:
 			ghc |= GHC_SPEED_100M;
 			strcat(linkmsg, "100 Mbps, ");
-			if (is_buggy250(jme->pdev->device, jme->chiprev))
-				jme_set_phyfifob(jme);
 			break;
 		case PHY_LINK_SPEED_1000M:
 			ghc |= GHC_SPEED_1000M;
 			strcat(linkmsg, "1000 Mbps, ");
-			if (is_buggy250(jme->pdev->device, jme->chiprev))
-				jme_set_phyfifoa(jme);
 			break;
 		default:
 			break;
 		}
-		ghc |= (phylink & PHY_LINK_DUPLEX) ? GHC_DPX : ...
From: David Miller
Date: Wednesday, October 8, 2008 - 7:51 pm

From: "Guo-Fu Tseng" <cooldavid@cooldavid.org>

Applied.
--

From: Guo-Fu Tseng
Date: Wednesday, October 8, 2008 - 2:57 pm

Dear Jeff, David:

This patch:

    Fix IRQ handle bug when interrupt mode.

    The driver was incorrectly handled and returned IRQ_HANDLED
    while the device is not generating the interrupt.
    It happened due to faulty determination of interrupt status register.

    The patch is also available at:
    http://cooldavid.org/download/jme.net-next-2.6.20081009.2.patch

    Found by: "Ethan" <ethanhsiao@jmicron.com>
    Fixed by: "akeemting" <akeem@jmicron.com>
    Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 635f616..3ab2442 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -1463,7 +1463,7 @@ jme_intr(int irq, void *dev_id)
 	/*
 	 * Check if it's really an interrupt for us
 	 */
-	if (unlikely(intrstat == 0))
+	if (unlikely((intrstat & INTR_ENABLE) == 0))
 		return IRQ_NONE;
 
 	/*

--

From: David Miller
Date: Wednesday, October 8, 2008 - 7:51 pm

From: "Guo-Fu Tseng" <cooldavid@cooldavid.org>

Applied.
--

From: Guo-Fu Tseng
Date: Wednesday, October 8, 2008 - 2:58 pm

Dear Jeff, David:

This patch:

    Advances the driver version after modification.

    The patch is also available at:
    http://cooldavid.org/download/jme.net-next-2.6.20081009.3.patch

    Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>

diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 9fdf20a..f863aee 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -25,7 +25,7 @@
 #define __JME_H_INCLUDEE__
 
 #define DRV_NAME	"jme"
-#define DRV_VERSION	"1.0.2"
+#define DRV_VERSION	"1.0.3"
 #define PFX		DRV_NAME ": "
 
 #define PCI_DEVICE_ID_JMICRON_JMC250	0x0250

--

From: David Miller
Date: Wednesday, October 8, 2008 - 7:51 pm

From: "Guo-Fu Tseng" <cooldavid@cooldavid.org>

Applied.
--

From: Guo-Fu Tseng
Date: Wednesday, December 3, 2008 - 3:41 am

Dear Jeff, David:

Due to the hardware design, except the first chip on the market,
other chips needs to setup the clock source for MAC processor
implicitly through Global Host Control Register(GHC).
(Strange design huh?)

10/100M uses the PCI-E as clock source, and 1G uses GPHY.

And I reordered the code a little, to make it easier to read.

Found-by: "Ethan" <ethanhsiao@jmicron.com>
Fixed-by: "akeemting" <akeem@jmicron.com>
Signed-off-by: "Guo-Fu Tseng" <cooldavid@cooldavid.org>

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 665e70d..49090ba 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -435,15 +435,18 @@ jme_check_link(struct net_device *netdev, int testonly)
 					GHC_DPX);
 		switch (phylink & PHY_LINK_SPEED_MASK) {
 		case PHY_LINK_SPEED_10M:
-			ghc |= GHC_SPEED_10M;
+			ghc |= GHC_SPEED_10M |
+				GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE;
 			strcat(linkmsg, "10 Mbps, ");
 			break;
 		case PHY_LINK_SPEED_100M:
-			ghc |= GHC_SPEED_100M;
+			ghc |= GHC_SPEED_100M |
+				GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE;
 			strcat(linkmsg, "100 Mbps, ");
 			break;
 		case PHY_LINK_SPEED_1000M:
-			ghc |= GHC_SPEED_1000M;
+			ghc |= GHC_SPEED_1000M |
+				GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY;
 			strcat(linkmsg, "1000 Mbps, ");
 			break;
 		default:
@@ -463,14 +466,6 @@ jme_check_link(struct net_device *netdev, int testonly)
 				TXTRHD_TXREN |
 				((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL));
 		}
-		strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ?
-					"Full-Duplex, " :
-					"Half-Duplex, ");
-
-		if (phylink & PHY_LINK_MDI_STAT)
-			strcat(linkmsg, "MDI-X");
-		else
-			strcat(linkmsg, "MDI");
 
 		gpreg1 = GPREG1_DEFAULT;
 		if (is_buggy250(jme->pdev->device, jme->chiprev)) {
@@ -492,11 +487,17 @@ jme_check_link(struct net_device *netdev, int testonly)
 				break;
 			}
 		}
-		jwrite32(jme, JME_GPREG1, gpreg1);
 
-		jme->reg_ghc = ghc;
+		jwrite32(jme, JME_GPREG1, gpreg1);
 		jwrite32(jme, JME_GHC, ghc);
+		jme->reg_ghc = ghc;
 ...
From: Jeff Garzik
Date: Wednesday, December 3, 2008 - 8:00 am

patches 1-2 Acked-by: Jeff Garzik <jgarzik@redhat.com>


--

From: David Miller
Date: Wednesday, December 3, 2008 - 10:20 pm

From: Jeff Garzik <jgarzik@pobox.com>

Both patches applied to net-next-2.6, thanks everyone.
--

From: Guo-Fu Tseng
Date: Wednesday, December 3, 2008 - 3:44 am

Dear Jeff, David:

Although the hardware supports the 64bit DMA address in design,
but later found that it actually not working.
This patch reduced the rang to 32bit.

Found-by: "Ethan" <ethanhsiao@jmicron.com>
Signed-off-by: "Guo-Fu Tseng" <cooldavid@cooldavid.org>

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 49090ba..660bb89 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -2592,14 +2592,6 @@ static const struct ethtool_ops jme_ethtool_ops = {
 static int
 jme_pci_dma64(struct pci_dev *pdev)
 {
-	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK))
-		if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
-			return 1;
-
-	if (!pci_set_dma_mask(pdev, DMA_40BIT_MASK))
-		if (!pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK))
-			return 1;
-
 	if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
 		if (!pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
 			return 0;

--

From: Guo-Fu Tseng
Date: Friday, February 27, 2009 - 8:54 pm

This patch modifies messages to display correct hardware version.
Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 08b3405..60cb997 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -2856,7 +2856,11 @@ jme_init_one(struct pci_dev *pdev,
 		goto err_out_free_shadow;
 	}
 
-	msg_probe(jme, "JMC250 gigabit%s ver:%x rev:%x macaddr:%pM\n",
+	msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n",
+		(jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ?
+			"JMC250 Gigabit Ethernet" :
+			(jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260) ?
+				"JMC260 Fast Ethernet" : "Unknown",
 		(jme->fpgaver != 0) ? " (FPGA)" : "",
 		(jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev,
 		jme->rev, netdev->dev_addr);
@@ -3002,7 +3006,7 @@ static struct pci_driver jme_driver = {
 static int __init
 jme_init_module(void)
 {
-	printk(KERN_INFO PFX "JMicron JMC250 gigabit ethernet "
+	printk(KERN_INFO PFX "JMicron JMC2XX ethernet "
 	       "driver version %s\n", DRV_VERSION);
 	return pci_register_driver(&jme_driver);
 }


--

From: Guo-Fu Tseng
Date: Friday, February 27, 2009 - 8:57 pm

We should sync ring descriptor to pci device after modifying it.
Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 60cb997..f65a09c 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -1833,7 +1833,7 @@ jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags)
 }
 
 static int
-jme_fill_first_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
+jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
 {
 	struct jme_ring *txring = jme->txring;
 	struct txdesc *txdesc;
@@ -1863,6 +1863,7 @@ jme_fill_first_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
 	if (jme_tx_tso(skb, &txdesc->desc1.mss, &flags))
 		jme_tx_csum(jme, skb, &flags);
 	jme_tx_vlan(skb, &txdesc->desc1.vlan, &flags);
+	jme_map_tx_skb(jme, skb, idx);
 	txdesc->desc1.flags = flags;
 	/*
 	 * Set tx buffer info after telling NIC to send
@@ -1932,8 +1933,7 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 		return NETDEV_TX_BUSY;
 	}
 
-	jme_map_tx_skb(jme, skb, idx);
-	jme_fill_first_tx_desc(jme, skb, idx);
+	jme_fill_tx_desc(jme, skb, idx);
 
 	jwrite32(jme, JME_TXCS, jme->reg_txcs |
 				TXCS_SELECT_QUEUE0 |

--

From: Guo-Fu Tseng
Date: Friday, February 27, 2009 - 8:58 pm

Clear all modified GHC register flags.

Fixed-by: Ethan Hsiao <ethanhsiao@jmicron.com>
Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index f65a09c..47dd47f 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -429,10 +429,9 @@ jme_check_link(struct net_device *netdev, int testonly)
 
 		jme->phylink = phylink;
 
-		ghc = jme->reg_ghc & ~(GHC_SPEED_10M |
-					GHC_SPEED_100M |
-					GHC_SPEED_1000M |
-					GHC_DPX);
+		ghc = jme->reg_ghc & ~(GHC_SPEED | GHC_DPX |
+				GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE |
+				GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY);
 		switch (phylink & PHY_LINK_SPEED_MASK) {
 		case PHY_LINK_SPEED_10M:
 			ghc |= GHC_SPEED_10M |

--

From: Guo-Fu Tseng
Date: Friday, February 27, 2009 - 8:59 pm

All JMC250 chips have no problem with higher bits support.
Adding it back.

Found-by: Ethan Hsiao <ethanhsiao@jmicron.com>
Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>

diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 47dd47f..4da81a3 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -2589,6 +2589,16 @@ static const struct ethtool_ops jme_ethtool_ops = {
 static int
 jme_pci_dma64(struct pci_dev *pdev)
 {
+	if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250 &&
+	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+		if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
+			return 1;
+
+	if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250 &&
+	    !pci_set_dma_mask(pdev, DMA_40BIT_MASK))
+		if (!pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK))
+			return 1;
+
 	if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
 		if (!pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
 			return 0;

--

From: Guo-Fu Tseng
Date: Monday, March 2, 2009 - 1:39 am

Advance version number after previous changes.
Sorry for not come along with previous patch series.

diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index e321c67..0996a06 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -25,7 +25,7 @@
 #define __JME_H_INCLUDED__
 
 #define DRV_NAME	"jme"
-#define DRV_VERSION	"1.0.3"
+#define DRV_VERSION	"1.0.4"
 #define PFX		DRV_NAME ": "
 
 #define PCI_DEVICE_ID_JMICRON_JMC250	0x0250

--

From: David Miller
Date: Monday, March 2, 2009 - 2:55 am

From: "Guo-Fu Tseng" <cooldavid@cooldavid.org>

Applied, but missing a signoff, please don't forget it
next time.
--

From: Stephen Hemminger
Date: Thursday, November 20, 2008 - 10:20 pm

Going through this driver for net_device_ops makes me wonder
why some other things wer not caught during the review process.

1. Obfuscation by macro which looks like some "vendor support older kernels"
   stuff.  See the wrapping of NAPI and NET_STAT

2. 5 tasklets for thing that could be done by NAPI and one tasklet

3. 4 atomic variables for things that should be already covered by locks

4. 3 locks, seems like more than needed.

5. PCI setup of max read request size should be done via pci_set_readrq
   not by direct manipulation of PCI registers.

6. Not using pci dma allocation which is more standard convention

7. NAPI weight is very large 256 (vs normal 64)


--

From: David Miller
Date: Thursday, November 20, 2008 - 10:36 pm

From: Stephen Hemminger <shemminger@vyatta.com>

Using the generic DMA interfaces is actually preferred.  There is
no effective difference other than using a more generic interface.
--

From: Stephen Hemminger
Date: Thursday, November 20, 2008 - 11:45 pm

On Thu, 20 Nov 2008 21:36:27 -0800 (PST)

Ok, but this???


#define NET_STAT(priv) (priv->dev->stats)
#define NETDEV_GET_STATS(netdev, fun_ptr)
#define DECLARE_NET_DEVICE_STATS

#define DECLARE_NAPI_STRUCT struct napi_struct napi;
#define NETIF_NAPI_SET(dev, napis, pollfn, q) \
	netif_napi_add(dev, napis, pollfn, q);
#define JME_NAPI_HOLDER(holder) struct napi_struct *holder
#define JME_NAPI_WEIGHT(w) int w
#define JME_NAPI_WEIGHT_VAL(w) w
#define JME_NAPI_WEIGHT_SET(w, r)
#define JME_RX_COMPLETE(dev, napis) netif_rx_complete(dev, napis)
#define JME_NAPI_ENABLE(priv) napi_enable(&priv->napi);
#define JME_NAPI_DISABLE(priv) \
	if (!napi_disable_pending(&priv->napi)) \
		napi_disable(&priv->napi);
#define JME_RX_SCHEDULE_PREP(priv) \
	netif_rx_schedule_prep(priv->dev, &priv->napi)
#define JME_RX_SCHEDULE(priv) \
	__netif_rx_schedule(priv->dev, &priv->napi);
--

From: David Miller
Date: Friday, November 21, 2008 - 1:46 am

From: Stephen Hemminger <shemminger@vyatta.com>

Yes, of course, all of those NAPI et al. abstraction macros have
to go.

I was only commenting about the DMA bits, the rest of your
criticism was on target.
--

From: Guo-Fu Tseng
Date: Friday, November 21, 2008 - 9:22 am

Thank you for point those out.
This is my first driver, so I still have many things to learn.
I'll work on it. Any suggestion or help is very welcome!

Guo-Fu Tseng

--

From: Guo-Fu Tseng
Date: Friday, November 21, 2008 - 9:18 am

You are right about it.
I have another jme.h which can compile for older kernel.
It can be removed if it should be.

Guo-Fu Tseng

--

Previous thread: [PATCH 1/1] usbnet: allow type check of devdbg arguments in non-debug build by Steve Glendinning on Monday, September 15, 2008 - 8:47 am. (10 messages)

Next thread: Bonding and Neighbour Discovery on IPv6-only devices by Alex Sidorenko on Monday, September 15, 2008 - 10:35 am. (18 messages)