Title: [6032] trunk: Task [#2471], [#4719], add BF518 EZBRD on board KSZ8893M switch driver, first checkin.

Diff

Modified: trunk/arch/blackfin/mach-bf518/boards/ezbrd.c (6031 => 6032)


--- trunk/arch/blackfin/mach-bf518/boards/ezbrd.c	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/arch/blackfin/mach-bf518/boards/ezbrd.c	2009-01-22 08:04:09 UTC (rev 6032)
@@ -46,6 +46,7 @@
 #include <asm/dpmc.h>
 #include <asm/bfin_sdh.h>
 #include <linux/spi/ad7877.h>
+#include <net/dsa.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
@@ -109,6 +110,24 @@
 };
 #endif
 
+#if defined(CONFIG_NET_DSA_KSZ8893M) || defined(CONFIG_NET_DSA_KSZ8893M_MODULE)
+struct dsa_platform_data ksz8893m_switch_data = {
+	.mii_bus = NULL,
+	.netdev = &bfin_mac_device.dev,
+	.port_names[0]	= NULL,
+	.port_names[1]	= "eth%d",
+	.port_names[2]	= "eth%d",
+	.port_names[3]	= "cpu",
+};
+
+static struct platform_device ksz8893m_switch_device = {
+	.name		= "dsa",
+	.id		= 0,
+	.num_resources	= 0,
+	.dev.platform_data = &ksz8893m_switch_data,
+};
+#endif
+
 #if defined(CONFIG_MTD_M25P80) \
 	|| defined(CONFIG_MTD_M25P80_MODULE)
 static struct mtd_partition bfin_spi_flash_partitions[] = {
@@ -147,6 +166,15 @@
 };
 #endif
 
+#if defined(CONFIG_NET_DSA_KSZ8893M) \
+	|| defined(CONFIG_NET_DSA_KSZ8893M_MODULE)
+/* SPI SWITCH CHIP */
+static struct bfin5xx_spi_chip spi_switch_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
 #if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
 static struct bfin5xx_spi_chip spi_mmc_chip_info = {
 	.enable_dma = 1,
@@ -226,6 +254,19 @@
 	},
 #endif
 
+#if defined(CONFIG_NET_DSA_KSZ8893M) \
+	|| defined(CONFIG_NET_DSA_KSZ8893M_MODULE)
+	{
+		.modalias = "spi_switch",
+		.max_speed_hz = 5000000,
+		.bus_num = 0,
+		.chip_select = 1,
+		.platform_data = NULL,
+		.controller_data = &spi_switch_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
 #if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
 	{
 		.modalias = "spi_mmc_dummy",
@@ -585,6 +626,10 @@
 	&bfin_mac_device,
 #endif
 
+#if defined(CONFIG_NET_DSA_KSZ8893M) || defined(CONFIG_NET_DSA_KSZ8893M_MODULE)
+	&ksz8893m_switch_device,
+#endif
+
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 	&bfin_spi0_device,
 	&bfin_spi1_device,

Modified: trunk/drivers/net/bfin_mac.c (6031 => 6032)


--- trunk/drivers/net/bfin_mac.c	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/drivers/net/bfin_mac.c	2009-01-22 08:04:09 UTC (rev 6032)
@@ -59,6 +59,10 @@
 	dma_free_coherent(NULL, sizeof(*ptr), ptr, dma_handle)
 #endif
 
+#if defined(CONFIG_NET_DSA_KSZ8893M)
+	extern struct dsa_platform_data ksz8893m_switch_data;
+#endif
+
 #define PKT_BUF_SZ 1580
 
 #define MAX_TIMEOUT_CNT	500
@@ -397,7 +401,7 @@
 	bfin_write_EMAC_SYSCTL(sysctl);
 
 	/* search for connect PHY device */
-	for (i = 0; i < PHY_MAX_ADDR; i++) {
+	for (i = PHY_MAX_ADDR - 1; i >= 0; i--) {
 		struct phy_device *const tmp_phydev = lp->mii_bus->phy_map[i];
 
 		if (!tmp_phydev)
@@ -522,6 +526,13 @@
 	/* Frame length is increased to 1538 bytes, for future use? */
 	/* bfin_write_EMAC_VLAN2( ?? ); */
 
+#if defined(CONFIG_NET_DSA)
+#if defined(CONFIG_NET_DSA_KSZ8893M)
+	bfin_write_EMAC_VLAN1(0x8101);
+	bfin_write_EMAC_VLAN2(0x8102);
+#endif
+#endif
+
 	/* Initialize the TX DMA channel registers */
 	bfin_write_DMA2_X_COUNT(0);
 	bfin_write_DMA2_X_MODIFY(4);
@@ -1083,6 +1094,9 @@
 		goto out_err_mdiobus_register;
 	}
 
+#if defined(CONFIG_NET_DSA_KSZ8893M)
+	ksz8893m_switch_data.mii_bus = &(lp->mii_bus->dev);
+#endif
 	rc = mii_probe(ndev);
 	if (rc) {
 		dev_err(&pdev->dev, "MII Probe failed!\n");

Modified: trunk/include/linux/if_ether.h (6031 => 6032)


--- trunk/include/linux/if_ether.h	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/include/linux/if_ether.h	2009-01-22 08:04:09 UTC (rev 6032)
@@ -104,6 +104,7 @@
 #define ETH_P_ARCNET	0x001A		/* 1A for ArcNet :-)            */
 #define ETH_P_DSA	0x001B		/* Distributed Switch Arch.	*/
 #define ETH_P_TRAILER	0x001C		/* Trailer switch tagging	*/
+#define ETH_P_STPID	0x001D		/* STPID switch tagging		*/
 #define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
 
 /*

Modified: trunk/include/linux/netdevice.h (6031 => 6032)


--- trunk/include/linux/netdevice.h	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/include/linux/netdevice.h	2009-01-22 08:04:09 UTC (rev 6032)
@@ -831,6 +831,15 @@
 	return 0;
 }
 
+static inline bool netdev_uses_stpid_tags(struct net_device *dev)
+{
+#ifdef CONFIG_NET_DSA_TAG_STPID
+	if (dev->dsa_ptr != NULL)
+		return dsa_uses_stpid_tags(dev->dsa_ptr);
+#endif
+
+	return 0;
+}
 /**
  *	netdev_priv - access network device private data
  *	@dev: network device

Modified: trunk/net/dsa/Kconfig (6031 => 6032)


--- trunk/net/dsa/Kconfig	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/net/dsa/Kconfig	2009-01-22 08:04:09 UTC (rev 6032)
@@ -23,6 +23,9 @@
 	bool
 	default n
 
+config NET_DSA_TAG_STPID
+	bool
+	default n
 
 # switch drivers
 config NET_DSA_MV88E6XXX
@@ -57,4 +60,11 @@
 	  This enables support for the Marvell 88E6123/6161/6165
 	  ethernet switch chips.
 
+config NET_DSA_KSZ8893M
+	bool "MICREL KSZ8893MQL/BL ethernet switch chip support"
+	select NET_DSA_TAG_STPID
+	---help---
+	  This enables support for the Micrel KSZ8893MQL/BL
+	  ethernet switch chips.
+
 endif

Modified: trunk/net/dsa/Makefile (6031 => 6032)


--- trunk/net/dsa/Makefile	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/net/dsa/Makefile	2009-01-22 08:04:09 UTC (rev 6032)
@@ -2,12 +2,14 @@
 obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
 obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
 obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
+obj-$(CONFIG_NET_DSA_TAG_STPID) += tag_stpid.o
 
 # switch drivers
 obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
 obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
 obj-$(CONFIG_NET_DSA_MV88E6123_61_65) += mv88e6123_61_65.o
 obj-$(CONFIG_NET_DSA_MV88E6131) += mv88e6131.o
+obj-$(CONFIG_NET_DSA_KSZ8893M) += ksz8893m.o
 
 # the core
 obj-$(CONFIG_NET_DSA) += dsa.o slave.o

Modified: trunk/net/dsa/dsa.c (6031 => 6032)


--- trunk/net/dsa/dsa.c	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/net/dsa/dsa.c	2009-01-22 08:04:09 UTC (rev 6032)
@@ -224,7 +224,13 @@
 	return !!(ds->tag_protocol == htons(ETH_P_TRAILER));
 }
 
+bool dsa_uses_stpid_tags(void *dsa_ptr)
+{
+	struct dsa_switch *ds = dsa_ptr;
 
+	return !!(ds->tag_protocol == htons(ETH_P_STPID));
+}
+
 /* link polling *************************************************************/
 static void dsa_link_poll_work(struct work_struct *ugly)
 {

Modified: trunk/net/dsa/dsa_priv.h (6031 => 6032)


--- trunk/net/dsa/dsa_priv.h	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/net/dsa/dsa_priv.h	2009-01-22 08:04:09 UTC (rev 6032)
@@ -112,5 +112,7 @@
 /* tag_trailer.c */
 int trailer_xmit(struct sk_buff *skb, struct net_device *dev);
 
+/* tag_stpid.c */
+int stpid_xmit(struct sk_buff *skb, struct net_device *dev);
 
 #endif

Added: trunk/net/dsa/ksz8893m.c (0 => 6032)


--- trunk/net/dsa/ksz8893m.c	                        (rev 0)
+++ trunk/net/dsa/ksz8893m.c	2009-01-22 08:04:09 UTC (rev 6032)
@@ -0,0 +1,325 @@
+/*
+ * Integrated 3-Port 10/100 Managed Switch with PHYs
+ *
+ * - KSZ8893M support
+ *
+ * Copyright 2008-2009 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ */
+
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/spi/spi.h>
+#include "dsa_priv.h"
+#include "ksz8893m.h"
+
+#define  BUF_LEN 6
+
+static struct _spi_switch {
+	struct spi_transfer xfer;
+	struct spi_device *dev;
+} sw;
+
+static int switch_read_spi(unsigned char *din, unsigned char reg, int len)
+{
+	struct spi_message message;
+	unsigned char dout[BUF_LEN];
+	struct spi_transfer *t = &sw.xfer;
+	int i;
+
+	t->len = len;
+	t->tx_buf = dout;
+	t->rx_buf = din;
+	((unsigned char *)(t->tx_buf))[0] = SPI_READ;
+	((unsigned char *)(t->tx_buf))[1] = reg;
+	for (i = 2; i < len; i++)
+		((unsigned char *)(t->tx_buf))[i] = 0;
+
+	spi_message_init(&message);
+	spi_message_add_tail(t, &message);
+	return spi_sync(sw.dev, &message);
+}
+
+static int switch_write_spi(unsigned char *dout, unsigned char reg, int len)
+{
+	struct spi_message message;
+	unsigned char din[BUF_LEN];
+	struct spi_transfer *t = &sw.xfer;
+
+	t->len = len;
+	t->tx_buf = dout;
+	t->rx_buf = din;
+	((unsigned char *)(t->tx_buf))[0] = SPI_WRITE;
+	((unsigned char *)(t->tx_buf))[1] = reg;
+
+	spi_message_init(&message);
+	spi_message_add_tail(t, &message);
+	return spi_sync(sw.dev, &message);
+}
+
+static char *ksz8893m_probe(struct mii_bus *bus, int sw_addr)
+{
+	int phyid_low, phyid_high;
+	unsigned char din[BUF_LEN];
+
+	phyid_high = mdiobus_read(bus, KSZ8893M_CPU_PORT, MII_PHYSID1);
+	phyid_low = mdiobus_read(bus, KSZ8893M_CPU_PORT, MII_PHYSID2);
+	if (phyid_high != PHYID_HIGH || phyid_low != PHYID_LOW) {
+		return NULL;
+	}
+
+	switch_read_spi(din, ChipID0, 3);
+
+	if (FamilyID == din[2])
+		return "KSZ8893M";
+
+	return NULL;
+}
+
+static int ksz8893m_switch_reset(struct dsa_switch *ds)
+{
+	return 0;
+}
+
+static int ksz8893m_setup_global(struct dsa_switch *ds)
+{
+	unsigned char dout[BUF_LEN];
+	unsigned char din[BUF_LEN];
+
+	/* Set VLAN VID of port1 */
+	switch_read_spi(din, Port1Control3, 3);
+	din[2] &= 0xf0;
+	dout[2] = (DEFAULT_PORT_VID & 0xfff) >>8 | din[2];
+	dout[3] = DEFAULT_PORT_VID & 0xff;
+	switch_write_spi(dout, Port1Control3, 4);
+			
+	/* Set VLAN VID of port2 */
+	switch_read_spi(din, Port2Control3, 3);
+	din[2] &= 0xf0;
+	dout[2] = (DEFAULT_PORT_VID & 0xfff) >>8 | din[2];
+	dout[3] = DEFAULT_PORT_VID & 0xff;
+	switch_write_spi(dout, Port2Control3, 4);
+			
+	/* Set VLAN VID of port3 */
+	switch_read_spi(din, Port3Control3, 3);
+	din[2] &= 0xf0;
+	dout[2] = (DEFAULT_PORT_VID & 0xfff) >>8 | din[2];
+	dout[3] = DEFAULT_PORT_VID & 0xff;
+	switch_write_spi(dout, Port3Control3, 4);
+
+	/* Insert VLAN tag that egress Port3 */
+	switch_read_spi(din, Port3Control0, 3);
+	dout[2] = 0x4 | din[2];
+	switch_write_spi(dout, Port3Control0, 3);
+
+	/* Enable STPID Mode */
+	switch_read_spi(din, GlobalControl9, 3);
+	dout[2] = 0x01 | din[2];
+	switch_write_spi(dout, GlobalControl9, 3);
+
+	/* Start switch */
+	dout[2] = StartSwitch;
+	switch_write_spi(dout, ChipID1_StartSwitch, 3);
+
+	return 0;
+}
+
+static int ksz8893m_setup_port(struct dsa_switch *ds, int p)
+{
+	int val;
+	val = mdiobus_read(ds->master_mii_bus, p, MII_BMCR);
+	/* bit 12 auto-negotiation enabled */
+	val |= 0x1000;
+	/* bit 13 force 100, bit 8 force full duplex */
+	val |= 0x2100;
+	/* bit 11 power on, bit 3 enable auto MDI-X, bit 2 enble far-end fault detection */
+	val &= ~0x80c;
+	mdiobus_write(ds->master_mii_bus, p, MII_BMCR, val);
+
+	val = mdiobus_read(ds->master_mii_bus, p, MII_ADVERTISE);
+	/* bit 8/7/6/5 advertise 100full/100half/10full/10half ability */
+	val |= 0x1e0;
+	mdiobus_write(ds->master_mii_bus, p, MII_ADVERTISE, val);
+	return 0;
+}
+
+static int ksz8893m_setup(struct dsa_switch *ds)
+{
+	int i;
+	int ret;
+
+	ret = ksz8893m_switch_reset(ds);
+	if (ret < 0)
+		return ret;
+
+	ret = ksz8893m_setup_global(ds);
+	if (ret < 0)
+		return ret;
+
+	for (i = 1; i < KSZ8893M_PORT_NUM; i++) {
+		ret = ksz8893m_setup_port(ds, i);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ksz8893m_set_addr(struct dsa_switch *ds, u8 *addr)
+{
+	return 0;
+}
+
+static int ksz8893m_port_to_phy_addr(int port)
+{
+	if (port >= 1 && port <= KSZ8893M_PORT_NUM)
+		return port;
+
+	printk(KERN_INFO "ksz8893m: use default phy addr 3\n");
+	return 3;
+}
+
+static int
+ksz8893m_phy_read(struct dsa_switch *ds, int port, int regnum)
+{
+	int phy_addr = ksz8893m_port_to_phy_addr(port);
+	return mdiobus_read(ds->master_mii_bus, phy_addr, regnum);
+}
+
+static int
+ksz8893m_phy_write(struct dsa_switch *ds,
+			      int port, int regnum, u16 val)
+{
+	int phy_addr = ksz8893m_port_to_phy_addr(port);
+	return mdiobus_write(ds->master_mii_bus, phy_addr, regnum, val);
+}
+
+void ksz8893m_poll_link(struct dsa_switch *ds)
+{
+	int i;
+
+	for (i = 1; i < KSZ8893M_PORT_NUM; i++) {
+		struct net_device *dev;
+		int val;
+		int link;
+		int speed;
+		int duplex;
+		int anc;
+		int fefd;
+
+		dev = ds->ports[i];
+		if (dev == NULL)
+			continue;
+
+		link = 0;
+		if (dev->flags & IFF_UP) {
+			val = mdiobus_read(ds->master_mii_bus, i, MII_BMSR);
+			if (val < 0)
+				continue;
+
+			/* bit 2 link is up */
+			link = !!(val & 0x04);
+			/* bit 4 far-end fault detected */
+			fefd = !!(val & 0x10);
+			/* bit 5 auto-negotiation complete */
+			anc = !!(val & 0x20);
+		}
+
+		if (!link) {
+			if (netif_carrier_ok(dev)) {
+				printk(KERN_INFO "%s: link down\n", dev->name);
+				netif_carrier_off(dev);
+			}
+			continue;
+		}
+
+		speed = 10;
+		duplex = 0;
+		val = mdiobus_read(ds->master_mii_bus, i, MII_BMSR);
+		/* bit 14/13/12/11 capable of 100full/100half/10full/10half */
+		val &= 0x7800;
+		if (val & 0x4000) {
+			speed = 100;
+			duplex = 1;
+		}
+		else if (val & 0x2000) {
+			speed = 100;
+			duplex = 0;
+		}
+		else if (val & 0x1000 ) {
+			speed = 10;
+			duplex = 1;
+		}
+
+		if (!netif_carrier_ok(dev)) {
+			printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex\n",
+					dev->name, speed, duplex ? "full" : "half");
+			netif_carrier_on(dev);
+		}
+	}
+}
+
+static int __devinit spi_switch_probe(struct spi_device *spi)
+{
+	memset(&(sw.xfer), 0, sizeof(sw.xfer));
+	sw.dev = spi;
+	return 0;
+}
+
+static int __devexit spi_switch_remove(struct spi_device *spi)
+{
+	sw.dev = NULL;
+	printk(KERN_INFO "spi switch exit\n");
+	return 0;
+}
+
+static struct spi_driver spi_switch_driver = {
+	.driver = {
+		.name	= "spi_switch",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe	= spi_switch_probe,
+	.remove	= __devexit_p(spi_switch_remove),
+};
+
+static struct dsa_switch_driver ksz8893m_switch_driver = {
+	.tag_protocol		= __constant_htons(ETH_P_STPID),
+	.probe			= ksz8893m_probe,
+	.setup			= ksz8893m_setup,
+	.set_addr		= ksz8893m_set_addr,
+	.phy_read		= ksz8893m_phy_read,
+	.phy_write		= ksz8893m_phy_write,
+	.poll_link		= ksz8893m_poll_link,
+};
+
+int __init ksz8893m_init(void)
+{
+	int ret;
+	ret = spi_register_driver(&spi_switch_driver);
+	if (ret) {
+		printk(KERN_ERR "Can't register spi_switch_driver!\n");
+		return ret;
+	}
+
+	register_switch_driver(&ksz8893m_switch_driver);
+	return 0;
+}
+module_init(ksz8893m_init);
+
+void __exit ksz8893m_cleanup(void)
+{
+	spi_unregister_driver(&spi_switch_driver);
+	unregister_switch_driver(&ksz8893m_switch_driver);
+}
+module_exit(ksz8893m_cleanup);
+
+MODULE_AUTHOR("Graf.Yang <[email protected]>");
+MODULE_DESCRIPTION("KSZ8893M driver for DSA");
+MODULE_LICENSE("GPL");
+

Added: trunk/net/dsa/ksz8893m.h (0 => 6032)


--- trunk/net/dsa/ksz8893m.h	                        (rev 0)
+++ trunk/net/dsa/ksz8893m.h	2009-01-22 08:04:09 UTC (rev 6032)
@@ -0,0 +1,136 @@
+#ifndef __KSZ8893M_H
+#define __KSZ8893M_H
+#include <linux/netdevice.h>
+
+#define KSZ8893M_PORT_NUM 3
+
+#define KSZ8893M_CPU_PORT 3
+
+#define STPID_HLEN        4
+
+#define ETH_P_8021QH      (ETH_P_8021Q >> 8)
+#define ETH_P_8021QL      (ETH_P_8021Q & 0xFF)
+
+#define DEFAULT_PORT_VID  0
+
+#define SPI_READ          3
+#define SPI_WRITE         2
+
+#define PHYID_HIGH        0x22
+#define PHYID_LOW         0x1430
+#define FamilyID          0x88
+
+#define StartSwitch       0x1
+
+enum switch_phy_reg {
+	/* Global Registers: 0-15 */
+	ChipID0 = 0,
+	ChipID1_StartSwitch,
+	GlobalControl0,
+	GlobalControl1,
+	GlobalControl2, /* 4 */
+	GlobalControl3,
+	GlobalControl4,
+	GlobalControl5,
+	GlobalControl6, /* 8 */
+	GlobalControl7,
+	GlobalControl8,
+	GlobalControl9,
+	GlobalControl10, /* 12 */
+	GlobalControl11,
+	GlobalControl12,
+	GlobalControl13,
+	/* Port Registers: 16-95 */
+	Port1Control0 = 16,
+	Port1Control1,
+	Port1Control2,
+	Port1Control3,
+	Port1Control4, /* 20 */
+	Port1Control5,
+	Port1Control6,
+	Port1Control7,
+	Port1Control8, /* 24 */
+	Port1Control9,
+	Port1PHYSpecialControl_Status,
+	Port1LinkMDResult,
+	Port1Control12, /* 28 */
+	Port1Control13,
+	Port1Status0,
+	Port1Status1,
+	Port2Control0, /* 32 */
+	Port2Control1,
+	Port2Control2,
+	Port2Control3,
+	Port2Control4, /* 36 */
+	Port2Control5,
+	Port2Control6,
+	Port2Control7,
+	Port2Control8, /* 40 */
+	Port2Control9,
+	Port2PHYSpecialControl_Status,
+	Port2LinkMDResult,
+	Port2Control12, /* 44 */
+	Port2Control13,
+	Port2Status0,
+	Port2Status1,
+	Port3Control0, /* 48 */
+	Port3Control1,
+	Port3Control2,
+	Port3Control3,
+	Port3Control4, /* 52 */
+	Port3Control5,
+	Port3Control6,
+	Port3Control7,
+	Port3Control8, /* 56 */
+	Port3Control9,
+	Reservednotappliedtoport3, /* 58-62 */
+	Port3Status1 = 63,
+	/* Advanced Control Registers: 96-141 */
+	TOSPriorityControlRegister0 = 96,
+	TOSPriorityControlRegister1,
+	TOSPriorityControlRegister2,
+	TOSPriorityControlRegister3,
+	TOSPriorityControlRegister4, /* 100 */
+	TOSPriorityControlRegister5,
+	TOSPriorityControlRegister6,
+	TOSPriorityControlRegister7,
+	TOSPriorityControlRegister8, /* 104 */
+	TOSPriorityControlRegister9,
+	TOSPriorityControlRegister10,
+	TOSPriorityControlRegister11,
+	TOSPriorityControlRegister12, /* 108 */
+	TOSPriorityControlRegister13,
+	TOSPriorityControlRegister14,
+	TOSPriorityControlRegister15,
+	MACAddressRegister0 = 112,
+	MACAddressRegister1,
+	MACAddressRegister2,
+	MACAddressRegister3,
+	MACAddressRegister4,
+	MACAddressRegister5,
+	UserDefinedRegister1 = 118,
+	UserDefinedRegister2,
+	UserDefinedRegister3,
+	IndirectAccessControl0 = 121,
+	IndirectAccessControl1,
+	IndirectDataRegister8 = 123,
+	IndirectDataRegister7,
+	IndirectDataRegister6,
+	IndirectDataRegister5,
+	IndirectDataRegister4,
+	IndirectDataRegister3,
+	IndirectDataRegister2,
+	IndirectDataRegister1,
+	IndirectDataRegister0,
+	DigitalTestingStatus0 = 132,
+	DigitalTestingControl0,
+	AnalogTestingControl0,
+	AnalogTestingControl1,
+	AnalogTestingControl2,
+	AnalogTestingControl3,
+	AnalogTestingStatus,
+	AnalogTestingControl4,
+	QMDebug1,
+	QMDebug2,
+};
+#endif

Modified: trunk/net/dsa/slave.c (6031 => 6032)


--- trunk/net/dsa/slave.c	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/net/dsa/slave.c	2009-01-22 08:04:09 UTC (rev 6032)
@@ -322,6 +322,11 @@
 		slave_dev->hard_start_xmit = trailer_xmit;
 		break;
 #endif
+#ifdef CONFIG_NET_DSA_TAG_STPID
+	case htons(ETH_P_STPID):
+		slave_dev->hard_start_xmit = stpid_xmit;
+		break;
+#endif
 	default:
 		BUG();
 	}

Added: trunk/net/dsa/tag_stpid.c (0 => 6032)


--- trunk/net/dsa/tag_stpid.c	                        (rev 0)
+++ trunk/net/dsa/tag_stpid.c	2009-01-22 08:04:09 UTC (rev 6032)
@@ -0,0 +1,139 @@
+/*
+ * net/dsa/tag_stpid.c - special tag identifier,
+ * 0x810 + 4 bit "port mask" + 3 bit 8021p + 1 bit CFI + 12 bit VLAN ID
+ *
+ * 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, or
+ * (at your option) any later version.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include "dsa_priv.h"
+#include "ksz8893m.h"
+
+int stpid_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dsa_slave_priv *p = netdev_priv(dev);
+	u8 *dsa_header;
+
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	/*
+	 * For 802.1Q frames, convert to STPID tagged frames,
+	 * do nothing for common frames.
+	 */
+	if (skb->protocol == htons(ETH_P_8021Q)) {
+		if (skb_cow_head(skb, 0) < 0)
+			goto out_free;
+
+		dsa_header = skb->data + 2 * ETH_ALEN;
+		dsa_header[1] = p->port & 0x03;
+	}
+
+	skb->protocol = htons(ETH_P_STPID);
+
+	skb->dev = p->parent->master_netdev;
+	dev_queue_xmit(skb);
+
+	return NETDEV_TX_OK;
+
+out_free:
+	kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static int stpid_rcv(struct sk_buff *skb, struct net_device *dev,
+		   struct packet_type *pt, struct net_device *orig_dev)
+{
+	struct dsa_switch *ds = dev->dsa_ptr;
+	u8 *dsa_header;
+	int source_port;
+	int vid;
+
+	if (unlikely(ds == NULL))
+		goto out_drop;
+
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if (skb == NULL)
+		goto out;
+
+	/* The ether_head has been pulled by master driver */
+	dsa_header = skb->data - 2;
+
+	vid = ((dsa_header[2] & 0x0f)<<8 | dsa_header[3]);
+
+	source_port = dsa_header[1] & 0x03;
+	if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
+		goto out_drop;
+
+	if (((dsa_header[0] & ETH_P_8021QH) == ETH_P_8021QH) &&
+			(vid != DEFAULT_PORT_VID)) {
+		u8 new_header[STPID_HLEN];
+
+	 	/* Convert STPID tag to 802.1q tag */
+		new_header[0] = ETH_P_8021QH;
+		new_header[1] = ETH_P_8021QL;
+
+		if (skb->ip_summed == CHECKSUM_COMPLETE) {
+			__wsum c = skb->csum;
+			c = csum_add(c, csum_partial(new_header, 2, 0));
+			c = csum_sub(c, csum_partial(dsa_header, 2, 0));
+			skb->csum = c;
+		}
+		memcpy(dsa_header, new_header, STPID_HLEN / 2);
+
+	} else if ((dsa_header[0] & ETH_P_8021QH) &&
+			(vid == DEFAULT_PORT_VID)) {
+
+		if (unlikely(!pskb_may_pull(skb, STPID_HLEN)))
+			goto out_drop;
+
+		/* Remove STPID tag and update checksum. */
+		if (skb->ip_summed == CHECKSUM_COMPLETE) {
+			__wsum c = skb->csum;
+			c = csum_sub(c, csum_partial(dsa_header, STPID_HLEN, 0));
+			skb->csum = c;
+		}
+		memmove(skb->data - ETH_HLEN + STPID_HLEN,
+				skb->data - ETH_HLEN, 2 * ETH_ALEN);
+		skb_pull(skb, STPID_HLEN);
+	}
+
+	skb->dev = ds->ports[source_port];
+	skb_push(skb, ETH_HLEN);
+	skb->pkt_type = PACKET_HOST;
+	skb->protocol = eth_type_trans(skb, skb->dev);
+	skb->dev->last_rx = jiffies;
+	skb->dev->stats.rx_packets++;
+	skb->dev->stats.rx_bytes += skb->len;
+	netif_receive_skb(skb);
+
+	return 0;
+
+out_drop:
+	kfree_skb(skb);
+out:
+	return 0;
+}
+
+static struct packet_type stpid_packet_type = {
+	.type	= __constant_htons(ETH_P_STPID),
+	.func	= stpid_rcv,
+};
+
+static int __init stpid_init_module(void)
+{
+	dev_add_pack(&stpid_packet_type);
+	return 0;
+}
+module_init(stpid_init_module);
+
+static void __exit stpid_cleanup_module(void)
+{
+	dev_remove_pack(&stpid_packet_type);
+}
+module_exit(stpid_cleanup_module);

Modified: trunk/net/ethernet/eth.c (6031 => 6032)


--- trunk/net/ethernet/eth.c	2009-01-22 04:05:16 UTC (rev 6031)
+++ trunk/net/ethernet/eth.c	2009-01-22 08:04:09 UTC (rev 6032)
@@ -195,6 +195,8 @@
 		return htons(ETH_P_DSA);
 	if (netdev_uses_trailer_tags(dev))
 		return htons(ETH_P_TRAILER);
+	if (netdev_uses_stpid_tags(dev))
+		return htons(ETH_P_STPID);
 
 	if (ntohs(eth->h_proto) >= 1536)
 		return eth->h_proto;
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
http://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to