[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH] m68k: Updated Atari EtherNAT (SMC91C111) driver



Take two ... the driver proper.

On Wed, Jul 16, 2008 at 11:59:53PM +0200, Michael Schmitz wrote:
We should close it with the next kernel upload... with any luck, I'll
have the SMC91C111 driver working by then (it did finally own up to
detecting the proper hardware, instead of stuffing up the ROM-port card
or just hanging the kernel).

Does Geert have this in his queue yet?

No. Where's the patch?

Now for the actual EtherNAT driver ... still experimental at this stage.

This patch _replaces_ Geert's linux-m68k-patches-2.6/atari-ethernat.diff (the lp updates made it a bit too messy so I rather send a fresh one). Please replace the old patch with this one, Geert.

I don't think Christian had already added the old driver to the Debian kernel source yet, so it should just drop in there as well.

The driver does compile (at least when built together with the EtherNEC driver), and is properly loaded by the kernel. The SMC91C111 chip is detected and initialized, MII tweaking by ethtool is possible to some extent. After brute forcing the interrupt to the timer D routine, it actually detects link up now.

Apparently, the EtherNAT has no station addres (MAC) PROM on board, so you will have to set the MAC address manually, using

ifconfig eth%d hw ether 00:00:de:ad:be:ef

Sending and receiving data via EtherNAT works to some degree, that is, I can ping remote hosts (but receive duplicate reply packets from the local net when I have the EtherNEC up at the same time). I cannot use slogin (which may be due to the dups, or because I use the same local net for both interfaces without properly separating the networks).

I'd appreciate someone else with access to this hardware and a more elaborate network setup to test the driver and confirm the problems with duplicate packets are real. Enabling debugging in the timer interrupt effectively freezes the box, and I kind of rely on the EtherNEC being up for remote hacking :-)

Signed-off-by: Michael Schmitz <schmitz@debian.org>
---
 arch/m68k/atari/config.c     |   41 +++++++++
 b/drivers/net/atari_91C111.c |  191 ++++++++++++++++++++++++++++++++++++++++---
 drivers/net/Kconfig          |   10 ++
 drivers/net/Makefile         |    1
 4 files changed, 232 insertions(+), 11 deletions(-)

--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <linux/platform_device.h>
 #include <linux/vt_kern.h>
 #include <linux/module.h>

@@ -670,3 +671,43 @@ static int atari_get_hardware_list(char

 	return len;
 }
+
+/*
+ * MSch: initial platform device support for Atari, required for EtherNAT
+ */
+
+#define ATARI_ETHERNAT_PHYS_ADDR	0x80000000
+#define ATARI_ETHERNAT_IRQ		0xc4
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.name	= "smc91x-regs",
+		.start	= ATARI_ETHERNAT_PHYS_ADDR,
+		.end	= ATARI_ETHERNAT_PHYS_ADDR + 0xff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.name	= "smc91x-irq",
+		.start	= ATARI_ETHERNAT_IRQ,
+		.end	= ATARI_ETHERNAT_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+static struct platform_device *atari_platform_devices[] __initdata = {
+	&smc91x_device
+};
+
+int __init atari_platform_init(void)
+{
+	return platform_add_devices(atari_platform_devices, ARRAY_SIZE(atari_platform_devices));
+}
+
+arch_initcall(atari_platform_init);
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -422,6 +422,16 @@ config ATARI_ETHERNEC
 	  ROM port. The driver works by polling instead of interrupts, so it
 	  is quite slow.

+config ATARI_ETHERNAT
+	tristate "Atari EtherNAT Ethernet support"
+	select CRC32
+	select MII
+	depends on NET_ETHERNET && ATARI
+	help
+	  Say Y to include support for the EtherNAT network adapter for the
+	  CT/60 extension port. The driver works by polling instead of
+	  interrupts, so it is quite slow.
+
 config SUN3LANCE
 	tristate "Sun3/Sun3x on-board LANCE support"
 	depends on SUN3 || SUN3X
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -198,6 +198,7 @@ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
 obj-$(CONFIG_DECLANCE) += declance.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o
 obj-$(CONFIG_ATARI_ETHERNEC) += atari_ethernec.o 8390.o
+obj-$(CONFIG_ATARI_ETHERNAT) += atari_91C111.o
 obj-$(CONFIG_A2065) += a2065.o
 obj-$(CONFIG_HYDRA) += hydra.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
--- a/drivers/net/smc91x.c
+++ b/drivers/net/atari_91C111.c
@@ -60,6 +60,8 @@
 static const char version[] =
 	"smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@cam.org>\n";

+#define SMC_DEBUG 1
+
 /* Debugging level */
 #ifndef SMC_DEBUG
 #define SMC_DEBUG		0
@@ -86,7 +88,10 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>

+#include <asm/hwtest.h>
+#include <asm/atariints.h>
 #include <asm/io.h>
+#include <asm/irq.h>

 #include "smc91x.h"

@@ -101,6 +106,8 @@
 	0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0
 };

+#endif  /* CONFIG_ISA */
+
 #ifndef SMC_IOADDR
 # define SMC_IOADDR		-1
 #endif
@@ -115,7 +122,6 @@
 module_param(irq, int, 0400);
 MODULE_PARM_DESC(irq, "IRQ number");

-#endif  /* CONFIG_ISA */

 #ifndef SMC_NOWAIT
 # define SMC_NOWAIT		0
@@ -259,6 +265,70 @@
 	}								\
 } while (0)

+/*
+ * Timer based operation on Atari
+ */
+static irqreturn_t smc_interrupt(int irq, void *dev_id);
+
+static int use_poll = 0;
+module_param(use_poll, int, 0);
+MODULE_PARM_DESC(use_poll, "Use scheduling timer to poll driver");
+
+/* This is used by cleanup, to prevent the module from being unloaded while
+ * intrpt_routine is still in the task queue
+ */
+static wait_queue_head_t WaitQ;
+
+static struct delayed_work tqueue;
+
+static struct net_device *poll_dev = NULL;
+
+static void atari_ethernat_int(struct work_struct *work)
+{
+	struct net_device *dev  = poll_dev;
+
+        if(!dev) {
+	        /* If cleanup wants us to die */
+                if (waitqueue_active(&WaitQ))
+                  wake_up(&WaitQ);               /* Now cleanup_module can return */
+                else
+                  /* Put ourselves back in the task queue */
+                  schedule_delayed_work(&tqueue, 1);
+		return;
+        }
+
+        /* This actually does not appear to work during probe */
+	if (netif_running(dev)) {
+		smc_interrupt(dev->irq, dev);
+        }
+
+	/* If cleanup wants us to die */
+	if (waitqueue_active(&WaitQ))
+		wake_up(&WaitQ);               /* Now cleanup_module can return */
+	else
+		/* Put ourselves back in the task queue */
+		schedule_delayed_work(&tqueue, 0); /* reduced delay from 1 */
+}
+
+static void atari_ethernat_start_poll(struct net_device *dev)
+{
+	poll_dev = dev;
+
+	init_waitqueue_head(&WaitQ);
+
+	/* MSch: need to insert dev into work struct?? */
+
+	INIT_DELAYED_WORK(&tqueue, atari_ethernat_int);
+	schedule_delayed_work(&tqueue, 1);
+}
+
+static void atari_ethernat_stop_poll(struct net_device *dev)
+{
+	if (dev && (dev == poll_dev)) {
+	        sleep_on(&WaitQ);
+	}
+	poll_dev = NULL;
+}

 /*
  * this does a soft reset on the device
@@ -1780,6 +1850,11 @@

 	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);

+        if (!hwreg_present( ioaddr + BANK_SELECT )) {
+		retval = -ENODEV;
+		goto err_out;
+	}
+
 	/* First, see if the high byte is 0x33 */
 	val = SMC_CURRENT_BANK(lp);
 	DBG(2, "%s: bank signature probe returned 0x%04x\n", CARDNAME, val);
@@ -1936,8 +2011,10 @@

 	/* Grab the IRQ */
 	retval = request_irq(dev->irq, &smc_interrupt, irq_flags, dev->name, dev);
-      	if (retval)
-      		goto err_out;
+      	if (retval) {
+      		use_poll = 1;
+      		//goto err_out;
+	}

 #ifdef SMC_USE_PXA_DMA
 	{
@@ -1997,15 +2074,22 @@
 	struct resource * res;

 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
-	if (!res)
+	if (!res) {
+		printk("smc_enable_device: smc91x-attrib resource not found !\n");
 		return 0;
+	}
+
+        printk("smc_enable_device: smc91x-attrib resource found, start=%x !\n", res->start);

 	/*
 	 * Map the attribute space.  This is overkill, but clean.
 	 */
 	addr = ioremap(res->start, ATTRIB_SIZE);
-	if (!addr)
+	if (!addr) {
 		return -ENOMEM;
+ } +
+        printk("smc_enable_device :smc91x-attrib resource remapped, start=%p !\n", addr);

 	/*
 	 * Reset the device.  We must disable IRQs around this
@@ -2057,8 +2141,9 @@
 	if (!res)
 		return 0;

-	if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME))
+	if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME)) {
 		return -EBUSY;
+	}

 	return 0;
 }
@@ -2106,6 +2191,25 @@
 }

 /*
+ * Resources defined and added to platform data in arch/m68k/atari/config.c
+ * These are left here for reference only!
+ */
+
+struct resource ethernat_attr = {
+	.start	= 0x80000000,
+	.end	= 0x800000FF,
+	.name	= "smc91x-attrib",
+	.flags	= IORESOURCE_MEM
+};
+
+struct resource ethernat_datacs = {
+	.start	= 0,
+	.end	= 0,
+	.name	= "smc91x-data32",
+	.flags	= IORESOURCE_MEM
+};
+
+/*
  * smc_init(void)
  *   Input parameters:
  *	dev->base_addr == 0, try to find all possible locations
@@ -2116,7 +2220,8 @@
  *	0 --> there is a device
  *	anything else, error
  */
-static int smc_drv_probe(struct platform_device *pdev)
+
+static int __init atari_ethernat_pdev_probe(struct platform_device *pdev)
 {
 	struct smc91x_platdata *pd = pdev->dev.platform_data;
 	struct smc_local *lp;
@@ -2129,12 +2234,15 @@
 	if (!res)
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
+		printk("smc91x-regs resource not found!\n");
 		ret = -ENODEV;
 		goto out;
 	}

+	printk("smc91x-regs resource found, start=%x !\n", res->start);

 	if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) {
+		printk("could not request smc91x-regs resource at %ul!\n", res->start);
 		ret = -EBUSY;
 		goto out;
 	}
@@ -2172,24 +2280,57 @@

 	ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!ires) {
+		printk("atari_91C111: IRQ resource not found!\n");
 		ret = -ENODEV;
 		goto out_free_netdev;
 	}

 	ndev->irq = ires->start;
+	printk("atari_91C111: IRQ resource specified irq=%d\n", ndev->irq);
+
+	/*
+	 * 080720 MSch: testing timer based interrupts - need to set valid
+	 *		interrupt here or request_irq bails out.
+	 *		polling (use_poll == 1) not tested so far
+	 *		Ultimately, this needs to be set in the platform device
+	 *		data, or be overridden by module arguments
+	 *		The actual level6 interrupt is hardwired to vector
+ * 0xc4 according to the MiNT driver source. Interrupts + * are enabled for the device by setting bit 1 at base+0x20
+	 *		or base+0x23!
+	 */
+	ndev->irq = IRQ_MFP_TIMD;
+	ires->start = IRQ_MFP_TIMD;
+	printk("atari_91C111: IRQ forced to irq=%d\n", ndev->irq);
+
 	if (SMC_IRQ_FLAGS == -1)
 		lp->cfg.irq_flags = ires->flags & IRQF_TRIGGER_MASK;

+	if (ndev->irq < 0) {
+		printk("atari_91C111: cannot determine interrupt! Using timer D poll...\n");
+		ndev->irq = IRQ_MFP_TIMD;
+		/* timer actually set up later */
+	}
+
+	if (ndev->irq == IRQ_MFP_TIMD) {
+		printk("atari_91C111: Using timer D interrupt - do share!\n");
+		lp->cfg.irq_flags = IRQF_SHARED;
+	}
+
 	ret = smc_request_attrib(pdev);
-	if (ret)
+	if (ret) {
+		printk("atari_91C111: attrib resource not found!\n");
 		goto out_free_netdev;
+	}
 #if defined(CONFIG_SA1100_ASSABET)
 	NCR_0 |= NCR_ENET_OSC_EN;
 #endif
 	platform_set_drvdata(pdev, ndev);
 	ret = smc_enable_device(pdev);
-	if (ret)
+	if (ret) {
+		printk("atari_91C111: failed to enable card!\n");
 		goto out_release_attrib;
+	}

 	addr = ioremap(res->start, SMC_IO_EXTENT);
 	if (!addr) {
@@ -2205,10 +2346,33 @@
 	}
 #endif

+	printk("smc91x-regs resource remapped, start=%p!\n", addr);
+
+	/*
+	 * about to probe for device; need to enable net IRQ here!
+ * EtherNAT has interrupt enable register at 0x20 or 0x23 + * probe for base address + 0x23 or 0x20
+	 */
+
 	ret = smc_probe(ndev, addr, lp->cfg.irq_flags);
 	if (ret != 0)
 		goto out_iounmap;

+	printk("smc91x probe done, irq %d!\n", ndev->irq);
+	ndev->irq = IRQ_MFP_TIMD;
+
+	if (ndev->irq < 0) {
+		if (use_poll)
+			atari_ethernat_start_poll(ndev);
+	} else if (ndev->irq == IRQ_MFP_TIMD) {
+        	/* maybe instead use MFP timer C ?? */
+		/* init timer if not already running */
+		/* set Timer D data Register */
+		mfp.tim_dt_d = 123;	/* 200 Hz */
+		/* start timer D, div = 1:100 */
+		mfp.tim_ct_cd = (mfp.tim_ct_cd & 0xf0) | 0x6;
+	}
+
 	smc_request_datacs(pdev, ndev);

 	return 0;
@@ -2236,6 +2400,9 @@

 	platform_set_drvdata(pdev, NULL);

+	if (use_poll)
+		atari_ethernat_stop_poll(ndev);
+
 	unregister_netdev(ndev);

 	free_irq(ndev->irq, ndev);
@@ -2292,18 +2459,20 @@
 }

 static struct platform_driver smc_driver = {
-	.probe		= smc_drv_probe,
+	.probe		= atari_ethernat_pdev_probe,
 	.remove		= smc_drv_remove,
 	.suspend	= smc_drv_suspend,
 	.resume		= smc_drv_resume,
 	.driver		= {
 		.name	= CARDNAME,
-		.owner	= THIS_MODULE,
 	},
 };

 static int __init smc_init(void)
 {
+	if (!MACH_IS_ATARI)
+		return -ENODEV;
+
 #ifdef MODULE
 #ifdef CONFIG_ISA
 	if (io == -1)


Reply to: