lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 11 Jun 2018 16:26:34 +0200
From:   Andrea Greco <andrea.greco.gapmilano@...il.com>
To:     davem@...emloft.net
Cc:     tobin@...orbit.com, Andrea Greco <a.greco@...gma.it>,
        Michael Grzeschik <m.grzeschik@...gutronix.de>,
        linux-kernel@...r.kernel.org, netdev@...r.kernel.org
Subject: [PATCH 3/6] arcnet: com20020: Add com20020 io mapped version

From: Andrea Greco <a.greco@...gma.it>

Add support for com20022I/com20020, io mapped.

Signed-off-by: Andrea Greco <a.greco@...gma.it>
---
 drivers/net/arcnet/Kconfig       |   9 +-
 drivers/net/arcnet/Makefile      |   1 +
 drivers/net/arcnet/com20020-io.c | 315 +++++++++++++++++++++++++++++++++++++++
 drivers/net/arcnet/com20020.c    |   5 +-
 4 files changed, 327 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/arcnet/com20020-io.c

diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig
index afc5898e7a16..f72620dc63ec 100644
--- a/drivers/net/arcnet/Kconfig
+++ b/drivers/net/arcnet/Kconfig
@@ -3,7 +3,7 @@
 #
 
 menuconfig ARCNET
-	depends on NETDEVICES && (ISA || PCI || PCMCIA)
+	depends on NETDEVICES
 	tristate "ARCnet support"
 	---help---
 	  If you have a network card of this type, say Y and check out the
@@ -129,5 +129,12 @@ config ARCNET_COM20020_CS
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called com20020_cs.  If unsure, say N.
+config ARCNET_COM20020_IO
+	tristate "Support for COM20020 (IO mapped)"
+	depends on ARCNET_COM20020
+	help
+	  Say Y here if your custom board mount com20020 chipset or friends.
+	  Supported Chipset: com20020, com20022, com20022I-3v3
+	  If unsure, say N.
 
 endif # ARCNET
diff --git a/drivers/net/arcnet/Makefile b/drivers/net/arcnet/Makefile
index 53525e8ea130..18da4341f404 100644
--- a/drivers/net/arcnet/Makefile
+++ b/drivers/net/arcnet/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_ARCNET_COM20020) += com20020.o
 obj-$(CONFIG_ARCNET_COM20020_ISA) += com20020-isa.o
 obj-$(CONFIG_ARCNET_COM20020_PCI) += com20020-pci.o
 obj-$(CONFIG_ARCNET_COM20020_CS) += com20020_cs.o
+obj-$(CONFIG_ARCNET_COM20020_IO) += com20020-io.o
diff --git a/drivers/net/arcnet/com20020-io.c b/drivers/net/arcnet/com20020-io.c
new file mode 100644
index 000000000000..23c24d4de5a9
--- /dev/null
+++ b/drivers/net/arcnet/com20020-io.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Linux ARCnet driver for com 20020.
+ *
+ * datasheet:
+ * http://ww1.microchip.com/downloads/en/DeviceDoc/200223vrevc.pdf
+ * http://ww1.microchip.com/downloads/en/DeviceDoc/20020.pdf
+ *
+ * Supported chip version:
+ * - com20020
+ * - com20022
+ * - com20022I-3v3
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/sizes.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include "arcdevice.h"
+#include "com20020.h"
+
+/* Reset (5 * xTalFreq), minimal com20020 xTal is 10Mhz */
+#define RESET_DELAY 500
+
+static unsigned int io_arc_inb(int addr, int offset)
+{
+	return ioread8((void *__iomem) addr + offset);
+}
+
+static void io_arc_outb(int value, int addr, int offset)
+{
+	iowrite8(value, (void *__iomem)addr + offset);
+}
+
+static void io_arc_insb(int  addr, int offset, void *buffer, int count)
+{
+	ioread8_rep((void *__iomem) (addr + offset), buffer, count);
+}
+
+static void io_arc_outsb(int addr, int offset, void *buffer, int count)
+{
+	iowrite8_rep((void *__iomem) (addr + offset), buffer, count);
+}
+
+enum com20020_xtal_freq {
+	freq_10Mhz = 10,
+	freq_20Mhz = 20,
+};
+
+enum com20020_arcnet_speed {
+	arc_speed_10M_bps = 10000000,
+	arc_speed_5M_bps = 5000000,
+	arc_speed_2M50_bps = 2500000,
+	arc_speed_1M25_bps = 1250000,
+	arc_speed_625K_bps = 625000,
+	arc_speed_312K5_bps = 312500,
+	arc_speed_156K25_bps = 156250,
+};
+
+enum com20020_timeout {
+	arc_timeout_328us =   328000,
+	arc_timeout_164us = 164000,
+	arc_timeout_82us =  82000,
+	arc_timeout_20u5s =  20500,
+};
+
+static int setup_clock(int *clockp, int *clockm, int xtal, int arcnet_speed)
+{
+	int pll_factor, req_clock_frq = 20;
+
+	switch (arcnet_speed) {
+	case arc_speed_10M_bps:
+		req_clock_frq = 80;
+		*clockp = 0;
+		break;
+	case arc_speed_5M_bps:
+		req_clock_frq = 40;
+		*clockp = 0;
+		break;
+	case arc_speed_2M50_bps:
+		*clockp = 0;
+		break;
+	case arc_speed_1M25_bps:
+		*clockp = 1;
+		break;
+	case arc_speed_625K_bps:
+		*clockp = 2;
+		break;
+	case arc_speed_312K5_bps:
+		*clockp = 3;
+		break;
+	case arc_speed_156K25_bps:
+		*clockp = 4;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (xtal != freq_10Mhz && xtal != freq_20Mhz)
+		return -EINVAL;
+
+	pll_factor = (unsigned int)req_clock_frq / xtal;
+
+	switch (pll_factor) {
+	case 1:
+		*clockm = 0;
+		break;
+	case 2:
+		*clockm = 1;
+		break;
+	case 4:
+		*clockm = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int setup_timeout(int *timeout)
+{
+	switch (*timeout) {
+	case arc_timeout_328us:
+		*timeout = 0;
+		break;
+	case arc_timeout_164us:
+		*timeout = 1;
+		break;
+	case arc_timeout_82us:
+		*timeout = 2;
+		break;
+	case arc_timeout_20u5s:
+		*timeout = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int com20020_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	struct net_device *dev;
+	struct arcnet_local *lp;
+	struct resource res, *iores;
+	int ret, phy_reset;
+	u32 timeout, xtal, arc_speed;
+	int clockp, clockm;
+	bool backplane = false;
+	int ioaddr;
+
+	np = pdev->dev.of_node;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	ret = of_address_to_resource(np, 0, &res);
+	if (ret)
+		return ret;
+
+	ret = of_property_read_u32(np, "timeout-ns", &timeout);
+	if (ret) {
+		dev_err(&pdev->dev, "timeout is required param");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "smsc,xtal-mhz", &xtal);
+	if (ret) {
+		dev_err(&pdev->dev, "xtal-mhz is required param");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "bus-speed-bps", &arc_speed);
+	if (ret) {
+		dev_err(&pdev->dev, "Bus speed is required param");
+		return ret;
+	}
+
+	if (of_property_read_bool(np, "smsc,backplane-enabled"))
+		backplane = true;
+
+	phy_reset = of_get_named_gpio(np, "reset-gpios", 0);
+	if (!gpio_is_valid(phy_reset)) {
+		dev_err(&pdev->dev, "reset gpio not valid");
+		return phy_reset;
+	}
+
+	ret = devm_gpio_request_one(&pdev->dev, phy_reset, GPIOF_OUT_INIT_LOW,
+				    "arcnet-reset");
+	if (ret) {
+		dev_err(&pdev->dev, "failed to get phy reset gpio: %d\n", ret);
+		return ret;
+	}
+
+	dev = alloc_arcdev(NULL);
+	dev->netdev_ops = &com20020_netdev_ops;
+	lp = netdev_priv(dev);
+
+	lp->card_flags = ARC_CAN_10MBIT;
+
+	/* Peak random address,
+	 * if required user could set a new-one in userspace
+	 */
+	get_random_bytes(dev->dev_addr, dev->addr_len);
+
+	if (!devm_request_mem_region(&pdev->dev, res.start, resource_size(&res),
+				     lp->card_name))
+		return -EBUSY;
+
+	ioaddr = (int)devm_ioremap(&pdev->dev, iores->start,
+				 resource_size(iores));
+	if (!ioaddr) {
+		dev_err(&pdev->dev, "ioremap fallied\n");
+		return -ENOMEM;
+	}
+
+	gpio_set_value_cansleep(phy_reset, 0);
+	ndelay(RESET_DELAY);
+	gpio_set_value_cansleep(phy_reset, 1);
+
+	lp->hw.arc_inb = io_arc_inb;
+	lp->hw.arc_outb = io_arc_outb;
+	lp->hw.arc_insb = io_arc_insb;
+	lp->hw.arc_outsb = io_arc_outsb;
+
+	/* ARCNET controller needs this access to detect bustype */
+	lp->hw.arc_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
+	lp->hw.arc_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
+
+	dev->base_addr = (unsigned long)ioaddr;
+
+	dev->irq = of_get_named_gpio(np, "interrupts", 0);
+	if (dev->irq == -EPROBE_DEFER) {
+		return dev->irq;
+	} else if (!gpio_is_valid(dev->irq)) {
+		dev_err(&pdev->dev, "irq-gpios not valid !");
+		return -EIO;
+	}
+	dev->irq = gpio_to_irq(dev->irq);
+
+	ret = setup_clock(&clockp, &clockm, xtal, arc_speed);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Impossible use oscillator:%dMhz and arcnet bus speed:%dKbps",
+			xtal, arc_speed / 1000);
+		return ret;
+	}
+
+	ret = setup_timeout(&timeout);
+	if (ret) {
+		dev_err(&pdev->dev, "Timeout:%d is not valid value", timeout);
+		return ret;
+	}
+
+	lp->backplane = (int)backplane;
+	lp->timeout = timeout;
+	lp->clockm = clockm;
+	lp->clockp = clockp;
+	lp->hw.owner = THIS_MODULE;
+
+	if (lp->hw.arc_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
+		ret = -EIO;
+		goto err_release_mem;
+	}
+
+	if (com20020_check(dev)) {
+		ret = -EIO;
+		goto err_release_mem;
+	}
+
+	ret = com20020_found(dev, IRQF_TRIGGER_FALLING);
+	if (ret)
+		goto err_release_mem;
+
+	dev_dbg(&pdev->dev, "probe Done\n");
+	return 0;
+
+err_release_mem:
+	devm_iounmap(&pdev->dev, (void __iomem *)ioaddr);
+	devm_release_mem_region(&pdev->dev, res.start, resource_size(&res));
+	dev_err(&pdev->dev, "probe failed!\n");
+	return ret;
+}
+
+static const struct of_device_id of_com20020_match[] = {
+	{ .compatible = "smsc,com20020",	},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, of_com20020_match);
+
+static struct platform_driver of_com20020_driver = {
+	.driver			= {
+		.name		= "com20020-memory-bus",
+		.of_match_table = of_com20020_match,
+	},
+	.probe			= com20020_probe,
+};
+
+static int com20020_init(void)
+{
+	return platform_driver_register(&of_com20020_driver);
+}
+late_initcall(com20020_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c
index cbcea7834378..8d979a66d8e9 100644
--- a/drivers/net/arcnet/com20020.c
+++ b/drivers/net/arcnet/com20020.c
@@ -43,7 +43,7 @@
 #include "com20020.h"
 
 static const char * const clockrates[] = {
-	"XXXXXXX", "XXXXXXXX", "XXXXXX", "2.5 Mb/s",
+	"10 Mb/s", "XXXXXXXX", "XXXXXX", "2.5 Mb/s",
 	"1.25Mb/s", "625 Kb/s", "312.5 Kb/s", "156.25 Kb/s",
 	"Reserved", "Reserved", "Reserved"
 };
@@ -429,7 +429,8 @@ static void com20020_set_mc_list(struct net_device *dev)
 
 #if defined(CONFIG_ARCNET_COM20020_PCI_MODULE) || \
     defined(CONFIG_ARCNET_COM20020_ISA_MODULE) || \
-    defined(CONFIG_ARCNET_COM20020_CS_MODULE)
+    defined(CONFIG_ARCNET_COM20020_CS_MODULE)  || \
+    defined(CONFIG_ARCNET_COM20020_IO)
 EXPORT_SYMBOL(com20020_check);
 EXPORT_SYMBOL(com20020_found);
 EXPORT_SYMBOL(com20020_netdev_ops);
-- 
2.14.4

Powered by blists - more mailing lists