All of lore.kernel.org
 help / color / mirror / Atom feed
* DSA support for Micrel KSZ8895
@ 2017-08-16  7:55 Pavel Machek
  2017-08-16 14:04 ` Andrew Lunn
  0 siblings, 1 reply; 35+ messages in thread
From: Pavel Machek @ 2017-08-16  7:55 UTC (permalink / raw)
  To: andrew, vivien.didelot, f.fainelli, netdev, linux-kernel,
	Tristram.Ha, Woojung.Huh

[-- Attachment #1: Type: text/plain, Size: 653 bytes --]

Hi!

I've got hardware with KSZ8895, and I'd like to use switch ports as
separate ethernet cards. I believe that means DSA support.

And there are even patches available from microchip... unfortunately
they are in strange form and for v3.18.

http://www.microchip.com/SWLibraryWeb/product.aspx?product=KSZ8895%20Software%20Linux%203.18

Is there newer version of the driver available somewhere? Is the
driver good starting point, or should I start with something else?

Best regards,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: DSA support for Micrel KSZ8895
  2017-08-16  7:55 DSA support for Micrel KSZ8895 Pavel Machek
@ 2017-08-16 14:04 ` Andrew Lunn
  2017-08-16 14:25   ` Woojung.Huh
  2017-08-16 18:32   ` Pavel Machek
  0 siblings, 2 replies; 35+ messages in thread
From: Andrew Lunn @ 2017-08-16 14:04 UTC (permalink / raw)
  To: Pavel Machek
  Cc: vivien.didelot, f.fainelli, netdev, linux-kernel, Tristram.Ha,
	Woojung.Huh

On Wed, Aug 16, 2017 at 09:55:24AM +0200, Pavel Machek wrote:
> Hi!
> 
> I've got hardware with KSZ8895, and I'd like to use switch ports as
> separate ethernet cards. I believe that means DSA support.
> 
> And there are even patches available from microchip... unfortunately
> they are in strange form and for v3.18.
> 
> http://www.microchip.com/SWLibraryWeb/product.aspx?product=KSZ8895%20Software%20Linux%203.18
> 
> Is there newer version of the driver available somewhere? Is the
> driver good starting point, or should I start with something else?

Hi Pavel

Woojung is the expert here. His DSA driver for the 9477 is a nice
clean driver.

Have you compared the 8895 to the 9477. Are they similar? Could the
existing 9477 be extended to support the 8895?

	 Andrew

^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: DSA support for Micrel KSZ8895
  2017-08-16 14:04 ` Andrew Lunn
@ 2017-08-16 14:25   ` Woojung.Huh
  2017-08-23  9:09     ` Pavel Machek
  2017-08-27 12:36     ` [PATCH] " Pavel Machek
  2017-08-16 18:32   ` Pavel Machek
  1 sibling, 2 replies; 35+ messages in thread
From: Woojung.Huh @ 2017-08-16 14:25 UTC (permalink / raw)
  To: pavel
  Cc: vivien.didelot, f.fainelli, netdev, linux-kernel, Tristram.Ha, andrew

> > Hi!
> >
> > I've got hardware with KSZ8895, and I'd like to use switch ports as
> > separate ethernet cards. I believe that means DSA support.
> >
> > And there are even patches available from microchip... unfortunately
> > they are in strange form and for v3.18.
> >
> >
> http://www.microchip.com/SWLibraryWeb/product.aspx?product=KSZ8895
> %20Software%20Linux%203.18
> >
> > Is there newer version of the driver available somewhere? Is the
> > driver good starting point, or should I start with something else?
> 
> Hi Pavel
> 
> Woojung is the expert here. His DSA driver for the 9477 is a nice
> clean driver.
> 
> Have you compared the 8895 to the 9477. Are they similar? Could the
> existing 9477 be extended to support the 8895?
> 
> 	 Andrew

Hi Pavel,

I'll forward your email to our support.
AFAIK, KSZ8895 has different register mapping from KSZ9477,
it will be more than ID changes in current driver.

Thanks.
Woojung

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: DSA support for Micrel KSZ8895
  2017-08-16 14:04 ` Andrew Lunn
  2017-08-16 14:25   ` Woojung.Huh
@ 2017-08-16 18:32   ` Pavel Machek
  1 sibling, 0 replies; 35+ messages in thread
From: Pavel Machek @ 2017-08-16 18:32 UTC (permalink / raw)
  To: Andrew Lunn, nathan.leigh.conrad
  Cc: vivien.didelot, f.fainelli, netdev, linux-kernel, Tristram.Ha,
	Woojung.Huh

[-- Attachment #1: Type: text/plain, Size: 1212 bytes --]

Hi!

> > I've got hardware with KSZ8895, and I'd like to use switch ports as
> > separate ethernet cards. I believe that means DSA support.
> > 
> > And there are even patches available from microchip... unfortunately
> > they are in strange form and for v3.18.
> > 
> > http://www.microchip.com/SWLibraryWeb/product.aspx?product=KSZ8895%20Software%20Linux%203.18
> > 
> > Is there newer version of the driver available somewhere? Is the
> > driver good starting point, or should I start with something else?
> 
> Hi Pavel
> 
> Woojung is the expert here. His DSA driver for the 9477 is a nice
> clean driver.

Good.

> Have you compared the 8895 to the 9477. Are they similar? Could the
> existing 9477 be extended to support the 8895?

Register layouts are completely different, at the very least. I'm not
sure if functionality maps 1:1, that was not exactly easy to check.

I've ported the v3.18 driver to v4.4; it looks like v4.5 port will not
be easy. Plus question is if it works at all... time will tell.

Best regards,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: DSA support for Micrel KSZ8895
  2017-08-16 14:25   ` Woojung.Huh
@ 2017-08-23  9:09     ` Pavel Machek
  2017-08-23 12:42       ` Andrew Lunn
  2017-08-23 21:48       ` Woojung.Huh
  2017-08-27 12:36     ` [PATCH] " Pavel Machek
  1 sibling, 2 replies; 35+ messages in thread
From: Pavel Machek @ 2017-08-23  9:09 UTC (permalink / raw)
  To: Woojung.Huh, nathan.leigh.conrad
  Cc: vivien.didelot, f.fainelli, netdev, linux-kernel, Tristram.Ha, andrew

[-- Attachment #1: Type: text/plain, Size: 58740 bytes --]

Hi!

> > Woojung is the expert here. His DSA driver for the 9477 is a nice
> > clean driver.
> > 
> > Have you compared the 8895 to the 9477. Are they similar? Could the
> > existing 9477 be extended to support the 8895?
> > 
> > 	 Andrew
> 
> Hi Pavel,
> 
> I'll forward your email to our support.
> AFAIK, KSZ8895 has different register mapping from KSZ9477,
> it will be more than ID changes in current driver.

More than ID changes, indeed. As layout is completely different, it
looks like different source file will be needed for support.

I'm not nearly there; but I can ifconfig lanX up, already, and perform
some pings.

Any ideas how to do the work in a way to minimize code duplication are
welcome...

Best regards,
								Pavel

diff --git a/drivers/net/dsa/microchip/ksz_8895_reg.h b/drivers/net/dsa/microchip/ksz_8895_reg.h
new file mode 100644
index 000000000000..dd3e0e738c68
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz_8895_reg.h
@@ -0,0 +1,41 @@
+/*
+ * Microchip KSZ9477 register definitions
+ *
+ * Copyright (C) 2017
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __KSZ9477_REGS_H
+#define __KSZ9477_REGS_H
+
+#define KS_PRIO_M			0x3
+#define KS_PRIO_S			2
+
+/* 0 - Operation */
+#define REG_CHIP_ID0__1			0x0000
+
+#define REG_CHIP_ID1__1			0x0001
+
+#define FAMILY_ID			0x95
+#define FAMILY_ID_94			0x94
+#define FAMILY_ID_95			0x95
+#define FAMILY_ID_85			0x85
+#define FAMILY_ID_98			0x98
+#define FAMILY_ID_88			0x88
+
+#define TOTAL_SWITCH_COUNTER_NUM	0x24 /* FIXME */
+#define PORT_CTRL_ADDR(port, addr)	((addr) | (((port) + 1) << 4))
+
+
+#endif /* KSZ9477_REGS_H */
diff --git a/drivers/net/dsa/microchip/ksz_9477_reg.h b/drivers/net/dsa/microchip/ksz_9477_reg.h
index 6aa6752035a1..af4d29c2ba4f 100644
--- a/drivers/net/dsa/microchip/ksz_9477_reg.h
+++ b/drivers/net/dsa/microchip/ksz_9477_reg.h
@@ -16,6 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#error This is not switch we have
 #ifndef __KSZ9477_REGS_H
 #define __KSZ9477_REGS_H
 
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index b313ecdf2919..6117dbea92d5 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -2,6 +2,7 @@
  * Microchip switch driver main logic
  *
  * Copyright (C) 2017
+ * Copyright (C) 2017 Pavel Machek <pavel@denx.de>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -29,6 +30,7 @@
 #include <net/switchdev.h>
 
 #include "ksz_priv.h"
+#include "ksz_sw_phy.h"
 
 static const struct {
 	int index;
@@ -130,10 +132,14 @@ static void ksz_port_cfg32(struct ksz_device *dev, int port, int offset,
 	ksz_write32(dev, addr, data);
 }
 
+#define NOTIMPL() do { NOTIMPLV(); return -EJUKEBOX; } while (0)
+#define NOTIMPLV() do { printk("Not implemented -- %s\n",  __func__); } while (0)
+
 static int wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton, int timeout)
 {
+#ifdef KSOLD
 	u8 data;
-
+	
 	do {
 		ksz_read8(dev, REG_SW_VLAN_CTRL, &data);
 		if (!(data & waiton))
@@ -145,10 +151,14 @@ static int wait_vlan_ctrl_ready(struct ksz_device *dev, u32 waiton, int timeout)
 		return -ETIMEDOUT;
 
 	return 0;
+#else
+	NOTIMPL();
+#endif	
 }
 
 static int get_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table)
 {
+#ifdef KSOLD       
 	struct ksz_device *dev = ds->priv;
 	int ret;
 
@@ -172,12 +182,15 @@ static int get_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table)
 
 exit:
 	mutex_unlock(&dev->vlan_mutex);
-
 	return ret;
+#else
+	NOTIMPL();
+#endif	
 }
 
 static int set_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table)
 {
+#ifdef KSOLD
 	struct ksz_device *dev = ds->priv;
 	int ret;
 
@@ -208,30 +221,42 @@ static int set_vlan_table(struct dsa_switch *ds, u16 vid, u32 *vlan_table)
 	mutex_unlock(&dev->vlan_mutex);
 
 	return ret;
+#else
+	NOTIMPL();
+#endif	
 }
 
 static void read_table(struct dsa_switch *ds, u32 *table)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 
 	ksz_read32(dev, REG_SW_ALU_VAL_A, &table[0]);
 	ksz_read32(dev, REG_SW_ALU_VAL_B, &table[1]);
 	ksz_read32(dev, REG_SW_ALU_VAL_C, &table[2]);
 	ksz_read32(dev, REG_SW_ALU_VAL_D, &table[3]);
+#else
+	NOTIMPLV();
+#endif	
 }
 
 static void write_table(struct dsa_switch *ds, u32 *table)
 {
+#ifdef KSOLD		
 	struct ksz_device *dev = ds->priv;
 
 	ksz_write32(dev, REG_SW_ALU_VAL_A, table[0]);
 	ksz_write32(dev, REG_SW_ALU_VAL_B, table[1]);
 	ksz_write32(dev, REG_SW_ALU_VAL_C, table[2]);
 	ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]);
+#else
+	NOTIMPLV();
+#endif	
 }
 
 static int wait_alu_ready(struct ksz_device *dev, u32 waiton, int timeout)
 {
+#ifdef KSOLD	
 	u32 data;
 
 	do {
@@ -245,12 +270,15 @@ static int wait_alu_ready(struct ksz_device *dev, u32 waiton, int timeout)
 		return -ETIMEDOUT;
 
 	return 0;
+#else
+	NOTIMPL();
+#endif	
 }
 
 static int wait_alu_sta_ready(struct ksz_device *dev, u32 waiton, int timeout)
 {
+#ifdef KSOLD	
 	u32 data;
-
 	do {
 		ksz_read32(dev, REG_SW_ALU_STAT_CTRL__4, &data);
 		if (!(data & waiton))
@@ -262,10 +290,14 @@ static int wait_alu_sta_ready(struct ksz_device *dev, u32 waiton, int timeout)
 		return -ETIMEDOUT;
 
 	return 0;
+#else
+	NOTIMPL();
+#endif	
 }
 
 static int ksz_reset_switch(struct dsa_switch *ds)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	u8 data8;
 	u16 data16;
@@ -295,22 +327,69 @@ static int ksz_reset_switch(struct dsa_switch *ds)
 	data16 &= ~BROADCAST_STORM_RATE;
 	data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100;
 	ksz_write16(dev, REG_SW_MAC_CTRL_2, data16);
+#else
+	/* reset switch */
+	//ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true);
+
+	/* turn off SPI DO Edge select */
+	//ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8);
+	//data8 &= ~SPI_AUTO_EDGE_DETECTION;
+	//ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8);
+
+	/* default configuration */
+	//ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8);
+	//data8 = SW_AGING_ENABLE | SW_LINK_AUTO_AGING |
+//	      SW_SRC_ADDR_FILTER | SW_FLUSH_STP_TABLE | SW_FLUSH_MSTP_TABLE;
+	//ksz_write8(dev, REG_SW_LUE_CTRL_1, data8);
+
+	/* disable interrupts */
+	//ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK);
+	//ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F);
+	//ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
+
+	/* set broadcast storm protection 10% rate */
+	//ksz_read16(dev, REG_SW_MAC_CTRL_2, &data16);
+	//data16 &= ~BROADCAST_STORM_RATE;
+	//data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100;
+	//ksz_write16(dev, REG_SW_MAC_CTRL_2, data16);
+#endif	
 
 	return 0;
 }
 
+#define PORT_MAC_LOOPBACK_my 0x80
+#ifdef KSZOLD
+#define REG_PORT_CTRL_LOOPBACK REG_PORT_CTRL_0
+#else
+#define REG_PORT_CTRL_LOOPBACK 0x0f
+#endif
+
 static void port_setup(struct ksz_device *dev, int port, bool cpu_port)
 {
+#ifdef KSZOLD
 	u8 data8;
 	u16 data16;
+#endif
 
+	printk("Port setup %d, %d\n", port, cpu_port);
+
+#ifndef KSZOLD	
+	if (cpu_port && port != 4)
+		printk("!!! tail tagging only works on port 5\n");
+	if (cpu_port) {
+		printk("enable tail tagging\n");
+		ksz_cfg(dev, S_TAIL_TAG_CTRL, SW_TAIL_TAG_ENABLE, true);
+	}
+#endif
+#ifdef KSZOLD
 	/* enable tag tail for host port */
 	if (cpu_port)
 		ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_TAIL_TAG_ENABLE,
 			     true);
+#endif
 
-	ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false);
-
+	ksz_port_cfg(dev, port, REG_PORT_CTRL_LOOPBACK, PORT_MAC_LOOPBACK_my, false);
+#ifdef KSZOLD
 	/* set back pressure */
 	ksz_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, true);
 
@@ -343,6 +422,7 @@ static void port_setup(struct ksz_device *dev, int port, bool cpu_port)
 
 	/* clear pending interrupts */
 	ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16);
+#endif
 }
 
 static void ksz_config_cpu_port(struct dsa_switch *ds)
@@ -379,18 +459,27 @@ static int ksz_setup(struct dsa_switch *ds)
 	}
 
 	/* accept packet up to 2000bytes */
-	ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_LEGAL_PACKET_DISABLE, true);
+	//ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_LEGAL_PACKET_DISABLE, true);
 
 	ksz_config_cpu_port(ds);
 
+#ifdef KSOLD
 	ksz_cfg(dev, REG_SW_MAC_CTRL_1, MULTICAST_STORM_DISABLE, true);
+#else
+	ksz_cfg(dev, REG_SW_CTRL_2, MULTICAST_STORM_DISABLE, true);
+#endif
 
 	/* queue based egress rate limit */
-	ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
+	//ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
 
 	/* start switch */
+#ifndef KSZOLD
+#define REG_SW_OPERATION 1
+#define SW_START 1
+#endif	
 	ksz_cfg(dev, REG_SW_OPERATION, SW_START, true);
 
+
 	return 0;
 }
 
@@ -399,13 +488,17 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds)
 	return DSA_TAG_PROTO_KSZ;
 }
 
+#ifdef KSZOLD
 static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
 {
 	struct ksz_device *dev = ds->priv;
 	u16 val = 0;
 
-	ksz_pread16(dev, addr, 0x100 + (reg << 1), &val);
+	/* "MIIM" registers. */
 
+	printk("Phy: read16 @ %lx, %lx\n", addr, reg);
+	ksz_pread16(dev, addr, 0x100 + (reg << 1), &val);
+	printk("Phy: read16 @ %lx, %lx -> %lx\n", addr, reg, val);
 	return val;
 }
 
@@ -413,10 +506,14 @@ static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
 {
 	struct ksz_device *dev = ds->priv;
 
+	printk("Phy: write16 @ %lx, %lx, %lx\n", addr, reg, val);	
 	ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val);
 
 	return 0;
 }
+#else
+#include "ksz_mdio_emulation.c"
+#endif
 
 static int ksz_enable_port(struct dsa_switch *ds, int port,
 			   struct phy_device *phy)
@@ -429,13 +526,14 @@ static int ksz_enable_port(struct dsa_switch *ds, int port,
 	return 0;
 }
 
+
 static void ksz_disable_port(struct dsa_switch *ds, int port,
 			     struct phy_device *phy)
 {
 	struct ksz_device *dev = ds->priv;
 
 	/* there is no port disable */
-	ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, true);
+	ksz_port_cfg(dev, port, REG_PORT_CTRL_LOOPBACK, PORT_MAC_LOOPBACK_my, true);
 }
 
 static int ksz_sset_count(struct dsa_switch *ds)
@@ -456,6 +554,7 @@ static void ksz_get_strings(struct dsa_switch *ds, int port, uint8_t *buf)
 static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
 				  uint64_t *buf)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	int i;
 	u32 data;
@@ -491,13 +590,35 @@ static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
 	}
 
 	mutex_unlock(&dev->stats_mutex);
+#else
+	NOTIMPLV();
+#endif	
+}
+
+static void ksz_dump(struct ksz_device *dev)
+{
+	int i;
+	u8 v;
+
+	printk("ksz: dumping:\n");
+	for (i = 0; i < 0x100; i++) {
+		if (!(i % 0x10))
+			printk("\n %lx: ", i);
+		ksz_read8(dev, i, &v);
+		printk("%02x ", v);
+	}
+	printk("\nksz: dump done\n");
 }
 
 static void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 {
 	struct ksz_device *dev = ds->priv;
 	u8 data;
+#ifndef KSOLD
+#define P_STP_CTRL 2	
+#endif
 
+	printk("port %d state %d\n", port, state);
 	ksz_pread8(dev, port, P_STP_CTRL, &data);
 	data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
 
@@ -512,6 +633,7 @@ static void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 		data |= PORT_RX_ENABLE;
 		break;
 	case BR_STATE_FORWARDING:
+		printk("port %d state %d forwarding\n", port, state);		
 		data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
 		break;
 	case BR_STATE_BLOCKING:
@@ -523,10 +645,18 @@ static void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 	}
 
 	ksz_pwrite8(dev, port, P_STP_CTRL, data);
+	
+	/* FIXME ! */
+	//ksz_write8(dev, 0x0c, 0x16);
+	
+	ksz_dump(dev);
+
+
 }
 
 static void ksz_port_fast_age(struct dsa_switch *ds, int port)
 {
+#ifdef KSOLD
 	struct ksz_device *dev = ds->priv;
 	u8 data8;
 
@@ -536,10 +666,15 @@ static void ksz_port_fast_age(struct dsa_switch *ds, int port)
 
 	data8 &= ~SW_FAST_AGING;
 	ksz_write8(dev, REG_SW_LUE_CTRL_1, data8);
+#else
+	NOTIMPLV();
+#endif	
+	
 }
 
 static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 
 	if (flag) {
@@ -553,7 +688,9 @@ static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag)
 		ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL,
 			     PORT_VLAN_LOOKUP_VID_0, false);
 	}
-
+#else
+	NOTIMPL();
+#endif	
 	return 0;
 }
 
@@ -570,6 +707,7 @@ static void ksz_port_vlan_add(struct dsa_switch *ds, int port,
 			      const struct switchdev_obj_port_vlan *vlan,
 			      struct switchdev_trans *trans)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	u32 vlan_table[3];
 	u16 vid;
@@ -599,11 +737,15 @@ static void ksz_port_vlan_add(struct dsa_switch *ds, int port,
 		if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
 			ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vid);
 	}
+#else
+	NOTIMPLV();
+#endif	
 }
 
 static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
 			     const struct switchdev_obj_port_vlan *vlan)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
 	u32 vlan_table[3];
@@ -634,6 +776,9 @@ static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
 	}
 
 	ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid);
+#else
+	NOTIMPL();
+#endif	
 
 	return 0;
 }
@@ -642,6 +787,7 @@ static int ksz_port_vlan_dump(struct dsa_switch *ds, int port,
 			      struct switchdev_obj_port_vlan *vlan,
 			      switchdev_obj_dump_cb_t *cb)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	u16 vid;
 	u16 data;
@@ -676,6 +822,9 @@ static int ksz_port_vlan_dump(struct dsa_switch *ds, int port,
 	mutex_unlock(&dev->vlan_mutex);
 
 	return err;
+#else
+	NOTIMPL();
+#endif	
 }
 
 static int ksz_port_fdb_prepare(struct dsa_switch *ds, int port,
@@ -710,6 +859,7 @@ static void ksz_port_fdb_add(struct dsa_switch *ds, int port,
 			     const struct switchdev_obj_port_fdb *fdb,
 			     struct switchdev_trans *trans)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	u32 alu_table[4];
 	u32 data;
@@ -757,11 +907,15 @@ static void ksz_port_fdb_add(struct dsa_switch *ds, int port,
 
 exit:
 	mutex_unlock(&dev->alu_mutex);
+#else
+	NOTIMPL();
+#endif	
 }
 
 static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
 			    const struct switchdev_obj_port_fdb *fdb)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	u32 alu_table[4];
 	u32 data;
@@ -822,12 +976,15 @@ static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
 
 exit:
 	mutex_unlock(&dev->alu_mutex);
-
 	return ret;
+#else
+	NOTIMPL();
+#endif	
 }
 
 static void convert_alu(struct alu_struct *alu, u32 *alu_table)
 {
+#ifdef KSOLD	
 	alu->is_static = !!(alu_table[0] & ALU_V_STATIC_VALID);
 	alu->is_src_filter = !!(alu_table[0] & ALU_V_SRC_FILTER);
 	alu->is_dst_filter = !!(alu_table[0] & ALU_V_DST_FILTER);
@@ -847,12 +1004,16 @@ static void convert_alu(struct alu_struct *alu, u32 *alu_table)
 	alu->mac[3] = (alu_table[3] >> 16) & 0xFF;
 	alu->mac[4] = (alu_table[3] >> 8) & 0xFF;
 	alu->mac[5] = alu_table[3] & 0xFF;
+#else
+	NOTIMPLV();
+#endif	
 }
 
 static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
 			     struct switchdev_obj_port_fdb *fdb,
 			     switchdev_obj_dump_cb_t *cb)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	int ret = 0;
 	u32 data;
@@ -860,6 +1021,7 @@ static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
 	struct alu_struct alu;
 	int timeout;
 
+
 	mutex_lock(&dev->alu_mutex);
 
 	/* start ALU search */
@@ -907,6 +1069,9 @@ static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
 	mutex_unlock(&dev->alu_mutex);
 
 	return ret;
+#else
+	NOTIMPL();
+#endif	
 }
 
 static int ksz_port_mdb_prepare(struct dsa_switch *ds, int port,
@@ -921,6 +1086,7 @@ static void ksz_port_mdb_add(struct dsa_switch *ds, int port,
 			     const struct switchdev_obj_port_mdb *mdb,
 			     struct switchdev_trans *trans)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	u32 static_table[4];
 	u32 data;
@@ -986,11 +1152,15 @@ static void ksz_port_mdb_add(struct dsa_switch *ds, int port,
 
 exit:
 	mutex_unlock(&dev->alu_mutex);
+#else
+	NOTIMPL();
+#endif	
 }
 
 static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
 			    const struct switchdev_obj_port_mdb *mdb)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	u32 static_table[4];
 	u32 data;
@@ -1063,6 +1233,9 @@ static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
 	mutex_unlock(&dev->alu_mutex);
 
 	return ret;
+#else
+	NOTIMPL();
+#endif	
 }
 
 static int ksz_port_mdb_dump(struct dsa_switch *ds, int port,
@@ -1077,6 +1250,7 @@ static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
 			       struct dsa_mall_mirror_tc_entry *mirror,
 			       bool ingress)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 
 	if (ingress)
@@ -1093,11 +1267,16 @@ static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
 	ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);
 
 	return 0;
+#else
+	NOTIMPL();
+#endif	
+
 }
 
 static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
 				struct dsa_mall_mirror_tc_entry *mirror)
 {
+#ifdef KSOLD	
 	struct ksz_device *dev = ds->priv;
 	u8 data;
 
@@ -1111,6 +1290,10 @@ static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
 	if (!(data & (PORT_MIRROR_RX | PORT_MIRROR_TX)))
 		ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
 			     PORT_MIRROR_SNIFFER, false);
+#else
+	NOTIMPLV();
+#endif	
+	
 }
 
 static const struct dsa_switch_ops ksz_switch_ops = {
@@ -1162,6 +1345,15 @@ static const struct ksz_chip_data ksz_switch_chips[] = {
 		.cpu_ports = 0x7F,	/* can be configured as cpu port */
 		.port_cnt = 7,		/* total physical port count */
 	},
+	{
+		.chip_id = 0x95600c04,
+		.dev_name = "KSZ8895",
+		.num_vlans = 4096, /* FIXME ? */
+		.num_alus = 4096,
+		.num_statics = 16,
+		.cpu_ports = 0x10,	/* can be configured as cpu port */
+		.port_cnt = 5,		/* total physical port count */
+	},
 };
 
 static int ksz_switch_init(struct ksz_device *dev)
@@ -1175,9 +1367,13 @@ static int ksz_switch_init(struct ksz_device *dev)
 
 	dev->ds->ops = &ksz_switch_ops;
 
+	printk("\n\n\nksz_switch_init: detecting\n");
+
 	for (i = 0; i < ARRAY_SIZE(ksz_switch_chips); i++) {
 		const struct ksz_chip_data *chip = &ksz_switch_chips[i];
 
+		printk("ksz_switch_init: have id %lx %lx\n", dev->chip_id, chip->chip_id);
+
 		if (dev->chip_id == chip->chip_id) {
 			dev->name = chip->dev_name;
 			dev->num_vlans = chip->num_vlans;
@@ -1189,6 +1385,8 @@ static int ksz_switch_init(struct ksz_device *dev)
 			break;
 		}
 	}
+	
+	printk("ksz_switch_init: detected %s\n", dev->name);
 
 	/* no switch found */
 	if (!dev->port_cnt)
@@ -1228,7 +1426,7 @@ int ksz_switch_detect(struct ksz_device *dev)
 	u8 data8;
 	u32 id32;
 	int ret;
-
+#ifdef KSOLD
 	/* turn off SPI DO Edge select */
 	ret = ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8);
 	if (ret)
@@ -1238,12 +1436,24 @@ int ksz_switch_detect(struct ksz_device *dev)
 	ret = ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8);
 	if (ret)
 		return ret;
-
+#endif
 	/* read chip id */
 	ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32);
-	if (ret)
+	if (ret) {
+		printk("ksz_switch_detect: error\n");
 		return ret;
-
+	}
+	printk("ksz_switch_detect: id %lx\n", id32);
+	
+	ret = ksz_read8(dev, 0, &data8);
+	printk("ksz_switch_detect: byte %lx, ret %d\n", data8, ret);
+	ret = ksz_read8(dev, 1, &data8);
+	printk("ksz_switch_detect: byte %lx, ret %d\n", data8, ret);
+	ret = ksz_read8(dev, 2, &data8);
+	printk("ksz_switch_detect: byte %lx, ret %d\n", data8, ret);
+	ret = ksz_read8(dev, 3, &data8);
+	printk("ksz_switch_detect: byte %lx, ret %d\n", data8, ret);
+	
 	dev->chip_id = id32;
 
 	return 0;
diff --git a/drivers/net/dsa/microchip/ksz_mdio_emulation.c b/drivers/net/dsa/microchip/ksz_mdio_emulation.c
new file mode 100644
index 000000000000..8ed62dc1615e
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz_mdio_emulation.c
@@ -0,0 +1,373 @@
+/**
+ * Micrel KSZ8895 SPI driver
+ *
+ * Copyright (c) 2015 Micrel, Inc.
+ *
+ * GPLv2
+ */
+
+#include "ksz_sw_phy.h"
+#define PHY_ID_KSZ8895		((KSZ8895_ID_HI << 16) | KSZ8895_ID_LO)
+
+/**
+ * sw_r_phy - read data from PHY register
+ * @sw:		The switch instance.
+ * @phy:	PHY address to read.
+ * @reg:	PHY register to read.
+ * @val:	Buffer to store the read data.
+ *
+ * This routine reads data from the PHY register.
+ */
+static void sw_r_phy(struct ksz_device *sw, u16 phy, u16 reg, u16 *val)
+{
+	u8 ctrl;
+	u8 restart;
+	u8 link;
+	u8 speed;
+	u8 force;
+	u8 p = phy;
+	u16 data = 0;
+
+	switch (reg) {
+	case PHY_REG_CTRL:
+		ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
+		ksz_pread8(sw, p, P_NEG_RESTART_CTRL, &restart);
+		ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
+		ksz_pread8(sw, p, P_FORCE_CTRL, &force);
+		if (restart & PORT_PHY_LOOPBACK)
+			data |= PHY_LOOPBACK;
+		if (force & PORT_FORCE_100_MBIT)
+			data |= PHY_SPEED_100MBIT;
+		if (!(force & PORT_AUTO_NEG_DISABLE))
+			data |= PHY_AUTO_NEG_ENABLE;
+		if (restart & PORT_POWER_DOWN)
+			data |= PHY_POWER_DOWN;
+		if (restart & PORT_AUTO_NEG_RESTART)
+			data |= PHY_AUTO_NEG_RESTART;
+		if (force & PORT_FORCE_FULL_DUPLEX)
+			data |= PHY_FULL_DUPLEX;
+		if (speed & PORT_HP_MDIX)
+			data |= PHY_HP_MDIX;
+		if (restart & PORT_FORCE_MDIX)
+			data |= PHY_FORCE_MDIX;
+		if (restart & PORT_AUTO_MDIX_DISABLE)
+			data |= PHY_AUTO_MDIX_DISABLE;
+		if (restart & PORT_TX_DISABLE)
+			data |= PHY_TRANSMIT_DISABLE;
+		if (restart & PORT_LED_OFF)
+			data |= PHY_LED_DISABLE;
+		break;
+	case PHY_REG_STATUS:
+		ksz_pread8(sw, p, P_LINK_STATUS, &link);
+		ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
+		data = PHY_100BTX_FD_CAPABLE |
+			PHY_100BTX_CAPABLE |
+			PHY_10BT_FD_CAPABLE |
+			PHY_10BT_CAPABLE |
+			PHY_AUTO_NEG_CAPABLE;
+		if (link & PORT_AUTO_NEG_COMPLETE)
+			data |= PHY_AUTO_NEG_ACKNOWLEDGE;
+		if (link & PORT_STAT_LINK_GOOD)
+			data |= PHY_LINK_STATUS;
+		break;
+	case PHY_REG_ID_1:
+		data = KSZ8895_ID_HI;
+		break;
+	case PHY_REG_ID_2:
+		data = KSZ8895_ID_LO;
+		break;
+	case PHY_REG_AUTO_NEGOTIATION:
+		ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
+		data = PHY_AUTO_NEG_802_3;
+		if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
+			data |= PHY_AUTO_NEG_SYM_PAUSE;
+		if (ctrl & PORT_AUTO_NEG_100BTX_FD)
+			data |= PHY_AUTO_NEG_100BTX_FD;
+		if (ctrl & PORT_AUTO_NEG_100BTX)
+			data |= PHY_AUTO_NEG_100BTX;
+		if (ctrl & PORT_AUTO_NEG_10BT_FD)
+			data |= PHY_AUTO_NEG_10BT_FD;
+		if (ctrl & PORT_AUTO_NEG_10BT)
+			data |= PHY_AUTO_NEG_10BT;
+		break;
+	case PHY_REG_REMOTE_CAPABILITY:
+		ksz_pread8(sw, p, P_REMOTE_STATUS, &link);
+		data = PHY_AUTO_NEG_802_3;
+		if (link & PORT_REMOTE_SYM_PAUSE)
+			data |= PHY_AUTO_NEG_SYM_PAUSE;
+		if (link & PORT_REMOTE_100BTX_FD)
+			data |= PHY_AUTO_NEG_100BTX_FD;
+		if (link & PORT_REMOTE_100BTX)
+			data |= PHY_AUTO_NEG_100BTX;
+		if (link & PORT_REMOTE_10BT_FD)
+			data |= PHY_AUTO_NEG_10BT_FD;
+		if (link & PORT_REMOTE_10BT)
+			data |= PHY_AUTO_NEG_10BT;
+		break;
+	default:
+		break;
+	}
+	*val = data;
+}  /* sw_r_phy */
+
+/**
+ * sw_w_phy - write data to PHY register
+ * @hw:		The switch instance.
+ * @phy:	PHY address to write.
+ * @reg:	PHY register to write.
+ * @val:	Word data to write.
+ *
+ * This routine writes data to the PHY register.
+ */
+static void sw_w_phy(struct ksz_device *sw, u16 phy, u16 reg, u16 val)
+{
+	u8 ctrl;
+	u8 restart;
+	u8 speed;
+	u8 data;
+	u8 p = phy;
+
+	switch (reg) {
+	case PHY_REG_CTRL:
+		ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
+		data = speed;
+		if (val & PHY_HP_MDIX)
+			data |= PORT_HP_MDIX;
+		else
+			data &= ~PORT_HP_MDIX;
+		if (data != speed)
+			ksz_pwrite8(sw, p, P_SPEED_STATUS, data);
+		ksz_pread8(sw, p, P_FORCE_CTRL, &ctrl);
+		data = ctrl;
+		if (!(val & PHY_AUTO_NEG_ENABLE))
+			data |= PORT_AUTO_NEG_DISABLE;
+		else
+			data &= ~PORT_AUTO_NEG_DISABLE;
+		if (val & PHY_SPEED_100MBIT)
+			data |= PORT_FORCE_100_MBIT;
+		else
+			data &= ~PORT_FORCE_100_MBIT;
+		if (val & PHY_FULL_DUPLEX)
+			data |= PORT_FORCE_FULL_DUPLEX;
+		else
+			data &= ~PORT_FORCE_FULL_DUPLEX;
+		if (data != ctrl)
+			ksz_pwrite8(sw, p, P_FORCE_CTRL, data);
+		ksz_pread8(sw, p, P_NEG_RESTART_CTRL, &restart);
+		data = restart;
+		if (val & PHY_LED_DISABLE)
+			data |= PORT_LED_OFF;
+		else
+			data &= ~PORT_LED_OFF;
+		if (val & PHY_TRANSMIT_DISABLE)
+			data |= PORT_TX_DISABLE;
+		else
+			data &= ~PORT_TX_DISABLE;
+		if (val & PHY_AUTO_NEG_RESTART)
+			data |= PORT_AUTO_NEG_RESTART;
+		else
+			data &= ~(PORT_AUTO_NEG_RESTART);
+		if (val & PHY_POWER_DOWN)
+			data |= PORT_POWER_DOWN;
+		else
+			data &= ~PORT_POWER_DOWN;
+		if (val & PHY_AUTO_MDIX_DISABLE)
+			data |= PORT_AUTO_MDIX_DISABLE;
+		else
+			data &= ~PORT_AUTO_MDIX_DISABLE;
+		if (val & PHY_FORCE_MDIX)
+			data |= PORT_FORCE_MDIX;
+		else
+			data &= ~PORT_FORCE_MDIX;
+		if (val & PHY_LOOPBACK)
+			data |= PORT_PHY_LOOPBACK;
+		else
+			data &= ~PORT_PHY_LOOPBACK;
+		if (data != restart)
+			ksz_pwrite8(sw, p, P_NEG_RESTART_CTRL, data);
+		break;
+	case PHY_REG_AUTO_NEGOTIATION:
+		ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
+		data = ctrl;
+		data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
+			PORT_AUTO_NEG_100BTX_FD |
+			PORT_AUTO_NEG_100BTX |
+			PORT_AUTO_NEG_10BT_FD |
+			PORT_AUTO_NEG_10BT);
+		if (val & PHY_AUTO_NEG_SYM_PAUSE)
+			data |= PORT_AUTO_NEG_SYM_PAUSE;
+		if (val & PHY_AUTO_NEG_100BTX_FD)
+			data |= PORT_AUTO_NEG_100BTX_FD;
+		if (val & PHY_AUTO_NEG_100BTX)
+			data |= PORT_AUTO_NEG_100BTX;
+		if (val & PHY_AUTO_NEG_10BT_FD)
+			data |= PORT_AUTO_NEG_10BT_FD;
+		if (val & PHY_AUTO_NEG_10BT)
+			data |= PORT_AUTO_NEG_10BT;
+		if (data != ctrl)
+			ksz_pwrite8(sw, p, P_LOCAL_CTRL, data);
+		break;
+	default:
+		break;
+	}
+}  /* sw_w_phy */
+
+static int ksz_mii_addr(int *reg, int *bank)
+{
+	int ret;
+
+	ret = (*reg & 0xC000) >> ADDR_SHIFT;
+	*bank = (*reg & 0x3000) >> BANK_SHIFT;
+	*reg &= 0x0FFF;
+	return ret;
+}
+
+static int ksz_phy_read16(struct dsa_switch *ds, int phy_id, int regnum)
+{
+	struct ksz_device *sw = ds->priv;
+	int addr;
+	int bank;
+	u16 data;
+	int ret = 0xffff;
+
+	if (phy_id > SWITCH_PORT_NUM + 1)
+		return 0xffff;
+#ifdef FIXME      
+	if (sw->port_cnt < sw->mib_port_cnt && 1 == phy_id)
+		return 0xffff;
+#endif
+
+	addr = ksz_mii_addr(&regnum, &bank);
+	BUG_ON(addr >= 6);
+
+	switch (addr) {
+#ifdef FIXME		
+	case ADDR_8:
+		ret = HW_R8(ks, regnum);
+		break;
+	case ADDR_16:
+		ret = HW_R16(ks, regnum);
+		break;
+	case ADDR_32:
+		ret = HW_R32(ks, regnum);
+		break;
+#endif
+	case ADDR_8:
+	case ADDR_16:
+	case ADDR_32:
+		BUG();
+
+	default:
+		if (regnum < 6) {
+			int id = phy_id;
+
+			sw_r_phy(sw, phy_id, regnum, &data);
+			ret = data;
+#ifdef FIXME?			
+			if (0 == id) {
+				switch (regnum) {
+				case 0:
+					ret = 0x3120;
+					break;
+				case 1:
+					ret = 0x782c;
+					break;
+				case 4:
+				case 5:
+					ret = 0x05e1;
+					break;
+				}
+			}
+#endif			
+		} else
+			ret = 0;
+	}
+
+	return ret;
+}  /* ksz_mii_read */
+
+static int ksz_phy_write16(struct dsa_switch *ds, int phy_id, int regnum, u16 val)
+{
+	struct ksz_device *sw = ds->priv;
+	static int last_reg;
+	static int last_val;
+	int addr;
+	int bank;
+	int reg;
+
+	if (phy_id > SWITCH_PORT_NUM + 1)
+		return -EINVAL;
+#ifdef FIXME	
+	if (sw->port_cnt < sw->mib_port_cnt && 1 == phy_id)
+		return -EINVAL;
+#endif	
+
+	BUG_ON(regnum >= 6);
+	reg = regnum;
+	addr = ksz_mii_addr(&regnum, &bank);
+
+	switch (addr) {
+#ifdef FIXME		
+	case ADDR_8:
+		HW_W8(ks, regnum, val);
+		break;
+	case ADDR_16:
+		HW_W16(ks, regnum, val);
+		break;
+	case ADDR_32:
+		/*
+		 * The phy_write interface allows only 16-bit value.  Break
+		 * the 32-bit write into two calls for SPI efficiency.
+		 */
+
+		/* Previous write to high word. */
+		if (last_reg == reg + 2) {
+			last_val <<= 16;
+			last_val |= val;
+			HW_W32(ks, regnum, last_val);
+			last_reg = 0;
+		} else {
+			/* Somebody has written to different address! */
+			if (last_reg) {
+				int last_bank;
+
+				addr = ksz_mii_addr(&last_reg, &last_bank);
+				HW_W16(ks, last_reg, last_val);
+				last_reg = 0;
+			}
+
+			/* Cache the 16-bit write to high word. */
+			if (reg & 3) {
+				last_reg = reg;
+				last_val = val;
+
+			/* Did not find the previous write to high word.*/
+			} else
+				HW_W16(ks, regnum, val);
+		}
+		break;
+#endif
+	case ADDR_8:
+	case ADDR_16:
+	case ADDR_32:
+		BUG();
+	default:
+		if (regnum < 6) {
+			int i;
+			int p = 0;
+
+			/* PHY device driver resets or powers down the PHY. */
+			if (0 == regnum &&
+			    (val & (PHY_RESET | PHY_POWER_DOWN)))
+				break;
+#ifdef FIXME			
+			if (sw->port_cnt < sw->mib_port_cnt)
+				p = 1;
+#endif
+			sw_w_phy(sw, phy_id, regnum, val);
+		}
+		break;
+	}
+
+	return 0;
+}  /* ksz_mii_write */
diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h
index 2a98dbd51456..2344cc1cde75 100644
--- a/drivers/net/dsa/microchip/ksz_priv.h
+++ b/drivers/net/dsa/microchip/ksz_priv.h
@@ -25,7 +25,7 @@
 #include <linux/etherdevice.h>
 #include <net/dsa.h>
 
-#include "ksz_9477_reg.h"
+#include "ksz_8895_reg.h"
 
 struct ksz_io_ops;
 
@@ -174,6 +174,7 @@ static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value)
 static inline void ksz_pread8(struct ksz_device *dev, int port, int offset,
 			      u8 *data)
 {
+	//printk("pread8 %d %d -> %d\n", port, offset, PORT_CTRL_ADDR(port, offset));
 	ksz_read8(dev, PORT_CTRL_ADDR(port, offset), data);
 }
 
diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c
index c51946983bed..37858d9b8f4f 100644
--- a/drivers/net/dsa/microchip/ksz_spi.c
+++ b/drivers/net/dsa/microchip/ksz_spi.c
@@ -29,22 +29,38 @@
 #define KS_SPIOP_RD			3
 #define KS_SPIOP_WR			2
 
+#ifdef KSOLD
 #define SPI_ADDR_SHIFT			24
-#define SPI_ADDR_MASK			(BIT(SPI_ADDR_SHIFT) - 1)
 #define SPI_TURNAROUND_SHIFT		5
+#else
+/* FIXME?! */
+#define SPI_ADDR_SHIFT			12
+#define SPI_TURNAROUND_SHIFT		1
+#endif
+#define SPI_ADDR_MASK			(BIT(SPI_ADDR_SHIFT) - 1)
 
 static int ksz_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val,
 			    unsigned int len)
 {
-	u32 txbuf;
 	int ret;
 
+#ifdef KSOLD
+	u32 txbuf;
 	txbuf = reg & SPI_ADDR_MASK;
 	txbuf |= KS_SPIOP_RD << SPI_ADDR_SHIFT;
 	txbuf <<= SPI_TURNAROUND_SHIFT;
 	txbuf = cpu_to_be32(txbuf);
 
 	ret = spi_write_then_read(spi, &txbuf, 4, val, len);
+#else
+	u8 buf[2];
+
+	buf[0] = KS_SPIOP_RD;
+	buf[1] = reg;
+
+	ret = spi_write_then_read(spi, buf, 2, val, len);
+#endif	
+
 	return ret;
 }
 
@@ -99,8 +115,10 @@ static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val)
 static int ksz_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val,
 			     unsigned int len)
 {
-	u32 txbuf;
 	u8 data[12];
+
+#ifdef KSOLD
+	u32 txbuf;
 	int i;
 
 	txbuf = reg & SPI_ADDR_MASK;
@@ -116,6 +134,16 @@ static int ksz_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val,
 		data[i + 4] = val[i];
 
 	return spi_write(spi, &data, 4 + len);
+#else
+	int i;
+	
+	data[0] = KS_SPIOP_WR;
+	data[1] = reg;
+	for (i = 0; i < len; i++)
+		data[i + 2] = val[i];
+
+	return spi_write(spi, &data, 2 + len);
+#endif
 }
 
 static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value)
@@ -174,6 +202,8 @@ static int ksz_spi_probe(struct spi_device *spi)
 	if (spi->dev.platform_data)
 		dev->pdata = spi->dev.platform_data;
 
+	//printk("Chip variant is %lx\n", spi_get_device_id(spi)->driver_data
+
 	ret = ksz_switch_register(dev);
 	if (ret)
 		return ret;
@@ -195,6 +225,7 @@ static int ksz_spi_remove(struct spi_device *spi)
 
 static const struct of_device_id ksz_dt_ids[] = {
 	{ .compatible = "microchip,ksz9477" },
+	{ .compatible = "microchip,ksz8895" },	
 	{},
 };
 MODULE_DEVICE_TABLE(of, ksz_dt_ids);
diff --git a/drivers/net/dsa/microchip/ksz_sw_phy.h b/drivers/net/dsa/microchip/ksz_sw_phy.h
new file mode 100644
index 000000000000..bb97613a6c84
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz_sw_phy.h
@@ -0,0 +1,754 @@
+/**
+ * Micrel switch PHY common header
+ *
+ * Copyright (c) 2012-2015 Micrel, Inc.
+ *	Tristram Ha <Tristram.Ha@micrel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+
+#ifndef KSZ_PHY_H
+#define KSZ_PHY_H
+
+#define ADDR_SHIFT			14
+#define ADDR_8				1
+#define ADDR_16				2
+#define ADDR_24				3
+#define ADDR_32				4
+
+#define BANK_SHIFT			12
+
+#define PHY_REG(addr, reg)		\
+	(((addr) << ADDR_SHIFT) | (reg))
+
+#define PHY_BANK_REG(addr, bank, reg)	\
+	(((addr) << ADDR_SHIFT) | ((bank) << BANK_SHIFT) | (reg))
+
+/* Use PHY access if no direct access. */
+#ifndef SW_R8
+#define SW_R8(s, r)	phy_read(s->phydev, PHY_REG(ADDR_8, r))
+#define SW_W8(s, r, v)	phy_write(s->phydev, PHY_REG(ADDR_8, r), v)
+#define SW_R16(s, r)	phy_read(s->phydev, PHY_REG(ADDR_16, r))
+#define SW_W16(s, r, v)	phy_write(s->phydev, PHY_REG(ADDR_16, r), v)
+#define SW_R32(s, r)	phy_read(s->phydev, PHY_REG(ADDR_32, r))
+#define SW_W32(s, r, v) \
+	do { \
+		phy_write(s->phydev, PHY_REG(ADDR_32, (r) + 2), (v) >> 16); \
+		phy_write(s->phydev, PHY_REG(ADDR_32, r), v); \
+	} while (0)
+#define SW_LOCK(s)				\
+	do {					\
+		mutex_lock(s->hwlock);		\
+	} while (0)
+#define SW_UNLOCK(s)				\
+	do {					\
+		mutex_unlock(s->hwlock);	\
+	} while (0)
+#endif
+
+
+#define KS_PORT_M			0x1F
+
+#define REG_CHIP_ID0			0x00
+
+#define FAMILY_ID			0x95
+
+#define REG_CHIP_ID1			0x01
+
+#define SW_CHIP_ID_M			0xF0
+#define SW_CHIP_ID_S			4
+#define SW_REVISION_M			0x0E
+#define SW_REVISION_S			1
+
+#define CHIP_ID_95			0x40
+#define CHIP_ID_95R			0x60
+
+#define REG_SW_CTRL_0			0x02
+
+#define SW_NEW_BACKOFF			(1 << 7)
+#define SW_FLUSH_DYN_MAC_TABLE		(1 << 5)
+#define SW_FLUSH_STA_MAC_TABLE		(1 << 4)
+#define SW_UNH_MODE			(1 << 1)
+#define SW_LINK_AUTO_AGING		(1 << 0)
+
+#define REG_SW_CTRL_1			0x03
+
+#define SW_PASS_ALL			(1 << 7)
+#define SW_2K_PACKET			(1 << 6)
+#define SW_TX_FLOW_CTRL_DISABLE		(1 << 5)
+#define SW_RX_FLOW_CTRL_DISABLE		(1 << 4)
+#define SW_CHECK_LENGTH			(1 << 3)
+#define SW_AGING_ENABLE			(1 << 2)
+#define SW_FAST_AGING			(1 << 1)
+#define SW_AGGR_BACKOFF			(1 << 0)
+
+#define REG_SW_CTRL_2			0x04
+
+#define UNICAST_VLAN_BOUNDARY		(1 << 7)
+#define MULTICAST_STORM_DISABLE		(1 << 6)
+#define SW_BACK_PRESSURE		(1 << 5)
+#define FAIR_FLOW_CTRL			(1 << 4)
+#define NO_EXC_COLLISION_DROP		(1 << 3)
+#define SW_HUGE_PACKET			(1 << 2)
+#define SW_LEGAL_PACKET			(1 << 1)
+
+#define REG_SW_CTRL_3			0x05
+#define SW_VLAN_ENABLE			(1 << 7)
+#define SW_IGMP_SNOOP			(1 << 6)
+#define SW_DIRECT			(1 << 5)
+#define SW_PRE_TAG			(1 << 4)
+#define SW_VLAN_TAG			(1 << 1)
+#define SW_MIRROR_RX_TX			(1 << 0)
+
+#define REG_SW_CTRL_4			0x06
+
+#define SW_HALF_DUPLEX_FLOW_CTRL	(1 << 7)
+#define SW_HALF_DUPLEX			(1 << 6)
+#define SW_FLOW_CTRL			(1 << 5)
+#define SW_10_MBIT			(1 << 4)
+#define SW_REPLACE_VID			(1 << 3)
+#define BROADCAST_STORM_RATE_HI		0x07
+
+#define REG_SW_CTRL_5			0x07
+
+#define BROADCAST_STORM_RATE_LO		0xFF
+#define BROADCAST_STORM_RATE		0x07FF
+
+#define REG_SW_CTRL_9			0x0B
+
+#define SW_DATA_SAMPLING_NEG		(1 << 6)
+#define SW_PHY_POWER_SAVE_DISABLE	(1 << 3)
+#define SW_LED_MODE_1			(1 << 1)
+#define SW_SPI_SAMPLING_RISING		(1 << 0)
+
+#define REG_SW_CTRL_10			0x0C
+
+#define SPI_CLK_125_MHZ			0x20
+#define SPI_CLK_83_33_MHZ		0x10
+#define SPI_CLK_41_67_MHZ		0x00
+#define SW_TAIL_TAG_ENABLE		(1 << 1)
+#define SW_PASS_PAUSE			(1 << 0)
+
+#define REG_SW_CTRL_11			0x0D
+
+#define REG_POWER_MANAGEMENT_1		0x0E
+
+#define SW_PLL_POWER_DOWN		(1 << 5)
+#define SW_POWER_MANAGEMENT_MODE_M	0x3
+#define SW_POWER_MANAGEMENT_MODE_S	3
+#define SW_POWER_NORMAL			0
+#define SW_ENERGY_DETECTION		1
+#define SW_SOFTWARE_POWER_DOWN		2
+#define SW_POWER_SAVING			3
+
+#define REG_POWER_MANAGEMENT_2		0x0F
+
+
+#define REG_PORT_1_CTRL_0		0x10
+#define REG_PORT_2_CTRL_0		0x20
+#define REG_PORT_3_CTRL_0		0x30
+#define REG_PORT_4_CTRL_0		0x40
+#define REG_PORT_5_CTRL_0		0x50
+
+#define PORT_BROADCAST_STORM		(1 << 7)
+#define PORT_DIFFSERV_ENABLE		(1 << 6)
+#define PORT_802_1P_ENABLE		(1 << 5)
+#define PORT_BASED_PRIO_S		3
+#define PORT_BASED_PRIO_M		(KS_PRIO_M << PORT_BASED_PRIO_S)
+#define PORT_PORT_PRIO_0		0
+#define PORT_PORT_PRIO_1		1
+#define PORT_PORT_PRIO_2		2
+#define PORT_PORT_PRIO_3		3
+#define PORT_INSERT_TAG			(1 << 2)
+#define PORT_REMOVE_TAG			(1 << 1)
+#define PORT_QUEUE_SPLIT_L		(1 << 0)
+
+#define REG_PORT_1_CTRL_1		0x11
+#define REG_PORT_2_CTRL_1		0x21
+#define REG_PORT_3_CTRL_1		0x31
+#define REG_PORT_4_CTRL_1		0x41
+#define REG_PORT_5_CTRL_1		0x51
+
+#define PORT_MIRROR_SNIFFER		(1 << 7)
+#define PORT_MIRROR_RX			(1 << 6)
+#define PORT_MIRROR_TX			(1 << 5)
+#define PORT_VLAN_MEMBERSHIP		KS_PORT_M
+
+#define REG_PORT_1_CTRL_2		0x12
+#define REG_PORT_2_CTRL_2		0x22
+#define REG_PORT_3_CTRL_2		0x32
+#define REG_PORT_4_CTRL_2		0x42
+#define REG_PORT_5_CTRL_2		0x52
+
+#define PORT_802_1P_REMAPPING		(1 << 7)
+#define PORT_INGRESS_FILTER		(1 << 6)
+#define PORT_DISCARD_NON_VID		(1 << 5)
+#define PORT_FORCE_FLOW_CTRL		(1 << 4)
+#define PORT_BACK_PRESSURE		(1 << 3)
+#define PORT_TX_ENABLE			(1 << 2)
+#define PORT_RX_ENABLE			(1 << 1)
+#define PORT_LEARN_DISABLE		(1 << 0)
+
+#define REG_PORT_1_CTRL_3		0x13
+#define REG_PORT_2_CTRL_3		0x23
+#define REG_PORT_3_CTRL_3		0x33
+#define REG_PORT_4_CTRL_3		0x43
+#define REG_PORT_5_CTRL_3		0x53
+#define REG_PORT_1_CTRL_4		0x14
+#define REG_PORT_2_CTRL_4		0x24
+#define REG_PORT_3_CTRL_4		0x34
+#define REG_PORT_4_CTRL_4		0x44
+#define REG_PORT_5_CTRL_4		0x54
+
+#define PORT_DEFAULT_VID		0x0001
+
+#define REG_PORT_1_STATUS_0		0x19
+#define REG_PORT_2_STATUS_0		0x29
+#define REG_PORT_3_STATUS_0		0x39
+#define REG_PORT_4_STATUS_0		0x49
+#define REG_PORT_5_STATUS_0		0x59
+
+#define PORT_HP_MDIX			(1 << 7)
+#define PORT_REVERSED_POLARITY		(1 << 5)
+#define PORT_TX_FLOW_CTRL		(1 << 4)
+#define PORT_RX_FLOW_CTRL		(1 << 3)
+#define PORT_STAT_SPEED_100MBIT		(1 << 2)
+#define PORT_STAT_FULL_DUPLEX		(1 << 1)
+
+#define REG_PORT_1_LINK_MD_CTRL		0x1A
+#define REG_PORT_2_LINK_MD_CTRL		0x2A
+#define REG_PORT_3_LINK_MD_CTRL		0x3A
+#define REG_PORT_4_LINK_MD_CTRL		0x4A
+#define REG_PORT_5_LINK_MD_CTRL		0x5A
+
+#define PORT_CABLE_10M_SHORT		(1 << 7)
+#define PORT_CABLE_DIAG_RESULT_M	0x3
+#define PORT_CABLE_DIAG_RESULT_S	5
+#define PORT_CABLE_STAT_NORMAL		0
+#define PORT_CABLE_STAT_OPEN		1
+#define PORT_CABLE_STAT_SHORT		2
+#define PORT_CABLE_STAT_FAILED		3
+#define PORT_START_CABLE_DIAG		(1 << 4)
+#define PORT_FORCE_LINK			(1 << 3)
+#define PORT_POWER_SAVING		(1 << 2)
+#define PORT_PHY_REMOTE_LOOPBACK	(1 << 1)
+#define PORT_CABLE_FAULT_COUNTER_H	0x01
+
+#define REG_PORT_1_LINK_MD_RESULT	0x1B
+#define REG_PORT_2_LINK_MD_RESULT	0x2B
+#define REG_PORT_3_LINK_MD_RESULT	0x3B
+#define REG_PORT_4_LINK_MD_RESULT	0x4B
+#define REG_PORT_5_LINK_MD_RESULT	0x5B
+
+#define PORT_CABLE_FAULT_COUNTER_L	0xFF
+#define PORT_CABLE_FAULT_COUNTER	0x1FF
+
+#define REG_PORT_1_CTRL_5		0x1C
+#define REG_PORT_2_CTRL_5		0x2C
+#define REG_PORT_3_CTRL_5		0x3C
+#define REG_PORT_4_CTRL_5		0x4C
+#define REG_PORT_5_CTRL_5		0x5C
+
+#define PORT_AUTO_NEG_DISABLE		(1 << 7)
+#define PORT_FORCE_100_MBIT		(1 << 6)
+#define PORT_FORCE_FULL_DUPLEX		(1 << 5)
+#define PORT_AUTO_NEG_SYM_PAUSE		(1 << 4)
+#define PORT_AUTO_NEG_100BTX_FD		(1 << 3)
+#define PORT_AUTO_NEG_100BTX		(1 << 2)
+#define PORT_AUTO_NEG_10BT_FD		(1 << 1)
+#define PORT_AUTO_NEG_10BT		(1 << 0)
+
+#define REG_PORT_1_CTRL_6		0x1D
+#define REG_PORT_2_CTRL_6		0x2D
+#define REG_PORT_3_CTRL_6		0x3D
+#define REG_PORT_4_CTRL_6		0x4D
+#define REG_PORT_5_CTRL_6		0x5D
+
+#define PORT_LED_OFF			(1 << 7)
+#define PORT_TX_DISABLE			(1 << 6)
+#define PORT_AUTO_NEG_RESTART		(1 << 5)
+#define PORT_POWER_DOWN			(1 << 3)
+#define PORT_AUTO_MDIX_DISABLE		(1 << 2)
+#define PORT_FORCE_MDIX			(1 << 1)
+#define PORT_MAC_LOOPBACK		(1 << 0)
+
+#define REG_PORT_1_STATUS_1		0x1E
+#define REG_PORT_2_STATUS_1		0x2E
+#define REG_PORT_3_STATUS_1		0x3E
+#define REG_PORT_4_STATUS_1		0x4E
+#define REG_PORT_5_STATUS_1		0x5E
+
+#define PORT_MDIX_STATUS		(1 << 7)
+#define PORT_AUTO_NEG_COMPLETE		(1 << 6)
+#define PORT_STAT_LINK_GOOD		(1 << 5)
+#define PORT_REMOTE_SYM_PAUSE		(1 << 4)
+#define PORT_REMOTE_100BTX_FD		(1 << 3)
+#define PORT_REMOTE_100BTX		(1 << 2)
+#define PORT_REMOTE_10BT_FD		(1 << 1)
+#define PORT_REMOTE_10BT		(1 << 0)
+
+#define REG_PORT_1_STATUS_2		0x1F
+#define REG_PORT_2_STATUS_2		0x2F
+#define REG_PORT_3_STATUS_2		0x3F
+#define REG_PORT_4_STATUS_2		0x4F
+#define REG_PORT_5_STATUS_2		0x5F
+
+#define PORT_PHY_LOOPBACK		(1 << 7)
+#define PORT_PHY_ISOLATE		(1 << 5)
+#define PORT_PHY_SOFT_RESET		(1 << 4)
+#define PORT_PHY_FORCE_LINK		(1 << 3)
+#define PORT_PHY_MODE_M			0x7
+#define PHY_MODE_IN_AUTO_NEG		1
+#define PHY_MODE_10BT_HALF		2
+#define PHY_MODE_100BT_HALF		3
+#define PHY_MODE_10BT_FULL		5
+#define PHY_MODE_100BT_FULL		6
+#define PHY_MODE_ISOLDATE		7
+
+#define REG_PORT_CTRL_0			0x00
+#define REG_PORT_CTRL_1			0x01
+#define REG_PORT_CTRL_2			0x02
+#define REG_PORT_CTRL_VID		0x03
+
+#define REG_PORT_STATUS_0		0x09
+#define REG_PORT_LINK_MD_CTRL		0x0A
+#define REG_PORT_LINK_MD_RESULT		0x0B
+#define REG_PORT_CTRL_5			0x0C
+#define REG_PORT_CTRL_6			0x0D
+#define REG_PORT_STATUS_1		0x0E
+#define REG_PORT_STATUS_2		0x0F
+
+#define REG_PORT_CTRL_8			0xA0
+#define REG_PORT_CTRL_9			0xA1
+#define REG_PORT_RATE_CTRL_3		0xA2
+#define REG_PORT_RATE_CTRL_2		0xA3
+#define REG_PORT_RATE_CTRL_1		0xA4
+#define REG_PORT_RATE_CTRL_0		0xA5
+#define REG_PORT_RATE_LIMIT		0xA6
+#define REG_PORT_IN_RATE_0		0xA7
+#define REG_PORT_IN_RATE_1		0xA8
+#define REG_PORT_IN_RATE_2		0xA9
+#define REG_PORT_IN_RATE_3		0xAA
+#define REG_PORT_OUT_RATE_0		0xAB
+#define REG_PORT_OUT_RATE_1		0xAC
+#define REG_PORT_OUT_RATE_2		0xAD
+#define REG_PORT_OUT_RATE_3		0xAE
+
+#define REG_SW_MAC_ADDR_0		0x68
+#define REG_SW_MAC_ADDR_1		0x69
+#define REG_SW_MAC_ADDR_2		0x6A
+#define REG_SW_MAC_ADDR_3		0x6B
+#define REG_SW_MAC_ADDR_4		0x6C
+#define REG_SW_MAC_ADDR_5		0x6D
+
+#define REG_IND_CTRL_0			0x6E
+
+#define TABLE_READ			(1 << 4)
+#define TABLE_SELECT_S			2
+#define TABLE_STATIC_MAC		(0 << TABLE_SELECT_S)
+#define TABLE_VLAN			(1 << TABLE_SELECT_S)
+#define TABLE_DYNAMIC_MAC		(2 << TABLE_SELECT_S)
+#define TABLE_MIB			(3 << TABLE_SELECT_S)
+
+#define REG_IND_CTRL_1			0x6F
+
+#define TABLE_ENTRY_MASK		0x03FF
+
+#define REG_IND_DATA_8			0x70
+#define REG_IND_DATA_7			0x71
+#define REG_IND_DATA_6			0x72
+#define REG_IND_DATA_5			0x73
+#define REG_IND_DATA_4			0x74
+#define REG_IND_DATA_3			0x75
+#define REG_IND_DATA_2			0x76
+#define REG_IND_DATA_1			0x77
+#define REG_IND_DATA_0			0x78
+
+#define REG_IND_DATA_CHECK		REG_IND_DATA_6
+#define REG_IND_MIB_CHECK		REG_IND_DATA_3
+#define REG_IND_DATA_HI			REG_IND_DATA_7
+#define REG_IND_DATA_LO			REG_IND_DATA_3
+
+#define REG_INT_STATUS			0x7C
+#define REG_INT_ENABLE			0x7D
+
+#define INT_PORT_5			(1 << 4)
+#define INT_PORT_4			(1 << 3)
+#define INT_PORT_3			(1 << 2)
+#define INT_PORT_2			(1 << 1)
+#define INT_PORT_1			(1 << 0)
+
+#define REG_SW_CTRL_12			0x80
+#define REG_SW_CTRL_13			0x81
+
+#define SWITCH_802_1P_MASK		3
+#define SWITCH_802_1P_BASE		3
+#define SWITCH_802_1P_SHIFT		2
+
+#define SW_802_1P_MAP_M			KS_PRIO_M
+#define SW_802_1P_MAP_S			KS_PRIO_S
+
+#define REG_SWITCH_CTRL_14		0x82
+
+#define SW_PRIO_MAPPING_M		KS_PRIO_M
+#define SW_PRIO_MAPPING_S		6
+#define SW_PRIO_MAP_3_HI		0
+#define SW_PRIO_MAP_2_HI		2
+#define SW_PRIO_MAP_0_LO		3
+
+#define REG_SW_CTRL_15			0x83
+#define REG_SW_CTRL_16			0x84
+
+#define SW_DRIVE_STRENGTH_M		0x3
+#define SW_DRIVE_STRENGTH_4MA		0
+#define SW_DRIVE_STRENGTH_8MA		1
+#define SW_DRIVE_STRENGTH_10MA		2
+#define SW_DRIVE_STRENGTH_14MA		3
+#define SW_MII_DRIVE_STRENGTH_S		6
+
+#define REG_SW_CTRL_17			0x85
+#define REG_SW_CTRL_18			0x86
+
+#define SW_SELF_ADDR_FILTER_ENABLE	(1 << 6)
+
+#define REG_SW_UNK_UCAST_CTRL		0x83
+#define REG_SW_UNK_MCAST_CTRL		0x84
+#define REG_SW_UNK_VID_CTRL		0x85
+#define REG_SW_UNK_IP_MCAST_CTRL	0x86
+
+#define SW_UNK_FWD_ENABLE		(1 << 5)
+#define SW_UNK_FWD_MAP			KS_PORT_M
+
+#define REG_SW_CTRL_19			0x87
+
+#define SW_IN_RATE_LIMIT_PERIOD_M	0x3
+#define SW_IN_RATE_LIMIT_PERIOD_S	4
+#define SW_IN_RATE_LIMIT_16_MS		0
+#define SW_IN_RATE_LIMIT_64_MS		1
+#define SW_IN_RATE_LIMIT_256_MS		2
+#define SW_QUEUE_BASED_OUT_RATE_LIMIT	(1 << 3)
+#define SW_INS_TAG_ENABLE		(1 << 2)
+
+#define REG_TOS_PRIO_CTRL_0		0x90
+#define REG_TOS_PRIO_CTRL_1		0x91
+#define REG_TOS_PRIO_CTRL_2		0x92
+#define REG_TOS_PRIO_CTRL_3		0x93
+#define REG_TOS_PRIO_CTRL_4		0x94
+#define REG_TOS_PRIO_CTRL_5		0x95
+#define REG_TOS_PRIO_CTRL_6		0x96
+#define REG_TOS_PRIO_CTRL_7		0x97
+#define REG_TOS_PRIO_CTRL_8		0x98
+#define REG_TOS_PRIO_CTRL_9		0x99
+#define REG_TOS_PRIO_CTRL_10		0x9A
+#define REG_TOS_PRIO_CTRL_11		0x9B
+#define REG_TOS_PRIO_CTRL_12		0x9C
+#define REG_TOS_PRIO_CTRL_13		0x9D
+#define REG_TOS_PRIO_CTRL_14		0x9E
+#define REG_TOS_PRIO_CTRL_15		0x9F
+
+#define TOS_PRIO_M			KS_PRIO_M
+#define TOS_PRIO_S			KS_PRIO_S
+
+
+#define REG_PORT_1_CTRL_8		0xB0
+#define REG_PORT_2_CTRL_8		0xC0
+#define REG_PORT_3_CTRL_8		0xD0
+#define REG_PORT_4_CTRL_8		0xE0
+#define REG_PORT_5_CTRL_8		0xF0
+
+#define PORT_INS_TAG_FOR_PORT_5_S	3
+#define PORT_INS_TAG_FOR_PORT_5		(1 << 3)
+#define PORT_INS_TAG_FOR_PORT_4		(1 << 2)
+#define PORT_INS_TAG_FOR_PORT_3		(1 << 1)
+#define PORT_INS_TAG_FOR_PORT_2		(1 << 0)
+
+#define REG_PORT_1_CTRL_9		0xB1
+#define REG_PORT_2_CTRL_9		0xC1
+#define REG_PORT_3_CTRL_9		0xD1
+#define REG_PORT_4_CTRL_9		0xE1
+#define REG_PORT_5_CTRL_9		0xF1
+
+#define PORT_QUEUE_SPLIT_H		(1 << 1)
+#define PORT_QUEUE_SPLIT_1		0
+#define PORT_QUEUE_SPLIT_2		1
+#define PORT_QUEUE_SPLIT_4		2
+#define PORT_DROP_TAG			(1 << 0)
+
+#define REG_PORT_1_CTRL_10		0xB2
+#define REG_PORT_2_CTRL_10		0xC2
+#define REG_PORT_3_CTRL_10		0xD2
+#define REG_PORT_4_CTRL_10		0xE2
+#define REG_PORT_5_CTRL_10		0xF2
+#define REG_PORT_1_CTRL_11		0xB3
+#define REG_PORT_2_CTRL_11		0xC3
+#define REG_PORT_3_CTRL_11		0xD3
+#define REG_PORT_4_CTRL_11		0xE3
+#define REG_PORT_5_CTRL_11		0xF3
+#define REG_PORT_1_CTRL_12		0xB4
+#define REG_PORT_2_CTRL_12		0xC4
+#define REG_PORT_3_CTRL_12		0xD4
+#define REG_PORT_4_CTRL_12		0xE4
+#define REG_PORT_5_CTRL_12		0xF4
+#define REG_PORT_1_CTRL_13		0xB5
+#define REG_PORT_2_CTRL_13		0xC5
+#define REG_PORT_3_CTRL_13		0xD5
+#define REG_PORT_4_CTRL_13		0xE5
+#define REG_PORT_5_CTRL_13		0xF5
+
+#define REG_PORT_1_RATE_CTRL_3		0xB2
+#define REG_PORT_1_RATE_CTRL_2		0xB3
+#define REG_PORT_1_RATE_CTRL_1		0xB4
+#define REG_PORT_1_RATE_CTRL_0		0xB5
+#define REG_PORT_2_RATE_CTRL_3		0xC2
+#define REG_PORT_2_RATE_CTRL_2		0xC3
+#define REG_PORT_2_RATE_CTRL_1		0xC4
+#define REG_PORT_2_RATE_CTRL_0		0xC5
+#define REG_PORT_3_RATE_CTRL_3		0xD2
+#define REG_PORT_3_RATE_CTRL_2		0xD3
+#define REG_PORT_3_RATE_CTRL_1		0xD4
+#define REG_PORT_3_RATE_CTRL_0		0xD5
+#define REG_PORT_4_RATE_CTRL_3		0xE2
+#define REG_PORT_4_RATE_CTRL_2		0xE3
+#define REG_PORT_4_RATE_CTRL_1		0xE4
+#define REG_PORT_4_RATE_CTRL_0		0xE5
+#define REG_PORT_5_RATE_CTRL_3		0xF2
+#define REG_PORT_5_RATE_CTRL_2		0xF3
+#define REG_PORT_5_RATE_CTRL_1		0xF4
+#define REG_PORT_5_RATE_CTRL_0		0xF5
+
+#define RATE_CTRL_ENABLE		(1 << 7)
+#define RATE_RATIO_M			((1 << 7) - 1)
+
+#define REG_PORT_1_RATE_LIMIT		0xB6
+#define REG_PORT_2_RATE_LIMIT		0xC6
+#define REG_PORT_3_RATE_LIMIT		0xD6
+#define REG_PORT_4_RATE_LIMIT		0xE6
+#define REG_PORT_5_RATE_LIMIT		0xF6
+
+#define PORT_IN_FLOW_CTRL_S		4
+#define PORT_IN_LIMIT_MODE_M		0x3
+#define PORT_IN_LIMIT_MODE_S		2
+#define PORT_COUNT_IFG_S		1
+#define PORT_COUNT_PREAMBLE_S		0
+#define PORT_IN_FLOW_CTRL		(1 << PORT_IN_FLOW_CTRL_S)
+#define PORT_IN_ALL			0
+#define PORT_IN_UNICAST			1
+#define PORT_IN_MULTICAST		2
+#define PORT_IN_BROADCAST		3
+#define PORT_COUNT_IFG			(1 << PORT_COUNT_IFG_S)
+#define PORT_COUNT_PREAMBLE		(1 << PORT_COUNT_PREAMBLE_S)
+
+#define REG_PORT_1_IN_RATE_0		0xB7
+#define REG_PORT_2_IN_RATE_0		0xC7
+#define REG_PORT_3_IN_RATE_0		0xD7
+#define REG_PORT_4_IN_RATE_0		0xE7
+#define REG_PORT_5_IN_RATE_0		0xF7
+#define REG_PORT_1_IN_RATE_1		0xB8
+#define REG_PORT_2_IN_RATE_1		0xC8
+#define REG_PORT_3_IN_RATE_1		0xD8
+#define REG_PORT_4_IN_RATE_1		0xE8
+#define REG_PORT_5_IN_RATE_1		0xF8
+#define REG_PORT_1_IN_RATE_2		0xB9
+#define REG_PORT_2_IN_RATE_2		0xC9
+#define REG_PORT_3_IN_RATE_2		0xD9
+#define REG_PORT_4_IN_RATE_2		0xE9
+#define REG_PORT_5_IN_RATE_2		0xF9
+#define REG_PORT_1_IN_RATE_3		0xBA
+#define REG_PORT_2_IN_RATE_3		0xCA
+#define REG_PORT_3_IN_RATE_3		0xDA
+#define REG_PORT_4_IN_RATE_3		0xEA
+#define REG_PORT_5_IN_RATE_3		0xFA
+
+#define PORT_RATE_LIMIT_M		((1 << 7) - 1)
+
+#define REG_PORT_1_OUT_RATE_0		0xBB
+#define REG_PORT_2_OUT_RATE_0		0xCB
+#define REG_PORT_3_OUT_RATE_0		0xDB
+#define REG_PORT_4_OUT_RATE_0		0xEB
+#define REG_PORT_5_OUT_RATE_0		0xFB
+#define REG_PORT_1_OUT_RATE_1		0xBC
+#define REG_PORT_2_OUT_RATE_1		0xCC
+#define REG_PORT_3_OUT_RATE_1		0xDC
+#define REG_PORT_4_OUT_RATE_1		0xEC
+#define REG_PORT_5_OUT_RATE_1		0xFC
+#define REG_PORT_1_OUT_RATE_2		0xBD
+#define REG_PORT_2_OUT_RATE_2		0xCD
+#define REG_PORT_3_OUT_RATE_2		0xDD
+#define REG_PORT_4_OUT_RATE_2		0xED
+#define REG_PORT_5_OUT_RATE_2		0xFD
+#define REG_PORT_1_OUT_RATE_3		0xBE
+#define REG_PORT_2_OUT_RATE_3		0xCE
+#define REG_PORT_3_OUT_RATE_3		0xDE
+#define REG_PORT_4_OUT_RATE_3		0xEE
+#define REG_PORT_5_OUT_RATE_3		0xFE
+
+
+#define REG_SW_CFG			0xEF
+
+#define SW_PORT_3_FIBER			(1 << 7)
+
+/* KSZ8864 */
+
+#define REG_PHY_PORT_CTRL_1		0xCF
+
+#define PORT_HALF_DUPLEX		(1 << 7)
+#define PORT_FLOW_CTRL			(1 << 6)
+#define PORT_10_MBIT			(1 << 5)
+
+#define REG_PHY_PORT_CTRL_2		0xDF
+
+#define PORT_MII_MAC_MODE		(1 << 6)
+
+#define REG_KSZ8864_CHIP_ID		0xFE
+
+#define SW_KSZ8864			(1 << 7)
+
+
+#ifndef PHY_REG_CTRL
+#define PHY_REG_CTRL			0
+
+#define PHY_RESET			(1 << 15)
+#define PHY_LOOPBACK			(1 << 14)
+#define PHY_SPEED_100MBIT		(1 << 13)
+#define PHY_AUTO_NEG_ENABLE		(1 << 12)
+#define PHY_POWER_DOWN			(1 << 11)
+#define PHY_MII_DISABLE			(1 << 10)
+#define PHY_AUTO_NEG_RESTART		(1 << 9)
+#define PHY_FULL_DUPLEX			(1 << 8)
+#define PHY_COLLISION_TEST_NOT		(1 << 7)
+#define PHY_HP_MDIX			(1 << 5)
+#define PHY_FORCE_MDIX			(1 << 4)
+#define PHY_AUTO_MDIX_DISABLE		(1 << 3)
+#define PHY_REMOTE_FAULT_DISABLE	(1 << 2)
+#define PHY_TRANSMIT_DISABLE		(1 << 1)
+#define PHY_LED_DISABLE			(1 << 0)
+
+#define PHY_REG_STATUS			1
+
+#define PHY_100BT4_CAPABLE		(1 << 15)
+#define PHY_100BTX_FD_CAPABLE		(1 << 14)
+#define PHY_100BTX_CAPABLE		(1 << 13)
+#define PHY_10BT_FD_CAPABLE		(1 << 12)
+#define PHY_10BT_CAPABLE		(1 << 11)
+#define PHY_MII_SUPPRESS_CAPABLE_NOT	(1 << 6)
+#define PHY_AUTO_NEG_ACKNOWLEDGE	(1 << 5)
+#define PHY_REMOTE_FAULT		(1 << 4)
+#define PHY_AUTO_NEG_CAPABLE		(1 << 3)
+#define PHY_LINK_STATUS			(1 << 2)
+#define PHY_JABBER_DETECT_NOT		(1 << 1)
+#define PHY_EXTENDED_CAPABILITY		(1 << 0)
+
+#define PHY_REG_ID_1			2
+#define PHY_REG_ID_2			3
+
+#define KSZ8895_ID_HI			0x0022
+#define KSZ8895_ID_LO			0x1450
+
+#define PHY_REG_AUTO_NEGOTIATION	4
+
+#define PHY_AUTO_NEG_NEXT_PAGE_NOT	(1 << 15)
+#define PHY_AUTO_NEG_REMOTE_FAULT_NOT	(1 << 13)
+#define PHY_AUTO_NEG_SYM_PAUSE		(1 << 10)
+#define PHY_AUTO_NEG_100BT4		(1 << 9)
+#define PHY_AUTO_NEG_100BTX_FD		(1 << 8)
+#define PHY_AUTO_NEG_100BTX		(1 << 7)
+#define PHY_AUTO_NEG_10BT_FD		(1 << 6)
+#define PHY_AUTO_NEG_10BT		(1 << 5)
+#define PHY_AUTO_NEG_SELECTOR		0x001F
+#define PHY_AUTO_NEG_802_3		0x0001
+
+#define PHY_REG_REMOTE_CAPABILITY	5
+
+#define PHY_REMOTE_NEXT_PAGE_NOT	(1 << 15)
+#define PHY_REMOTE_ACKNOWLEDGE_NOT	(1 << 14)
+#define PHY_REMOTE_REMOTE_FAULT_NOT	(1 << 13)
+#define PHY_REMOTE_SYM_PAUSE		(1 << 10)
+#define PHY_REMOTE_100BTX_FD		(1 << 8)
+#define PHY_REMOTE_100BTX		(1 << 7)
+#define PHY_REMOTE_10BT_FD		(1 << 6)
+#define PHY_REMOTE_10BT			(1 << 5)
+
+#define PHY_REG_LINK_MD			0x1D
+
+#define PHY_START_CABLE_DIAG		(1 << 15)
+#define PHY_CABLE_DIAG_RESULT		0x6000
+#define PHY_CABLE_STAT_NORMAL		0x0000
+#define PHY_CABLE_STAT_OPEN		0x2000
+#define PHY_CABLE_STAT_SHORT		0x4000
+#define PHY_CABLE_STAT_FAILED		0x6000
+#define PHY_CABLE_10M_SHORT		(1 << 12)
+#define PHY_CABLE_FAULT_COUNTER		0x01FF
+
+#define PHY_REG_PHY_CTRL		0x1F
+
+#define PHY_MODE_M			0x7
+#define PHY_MODE_S			8
+#define PHY_STAT_REVERSED_POLARITY	(1 << 5)
+#define PHY_STAT_MDIX			(1 << 4)
+#define PHY_FORCE_LINK			(1 << 3)
+#define PHY_POWER_SAVING_ENABLE		(1 << 2)
+#define PHY_REMOTE_LOOPBACK		(1 << 1)
+#endif
+
+
+/* Default values are used in ksz_sw.h if these are not defined. */
+#define PRIO_QUEUES			4
+
+#define KS_PRIO_IN_REG			4
+
+#define SWITCH_PORT_NUM			4
+
+#define KSZ8895_COUNTER_NUM		0x20
+#define TOTAL_KSZ8895_COUNTER_NUM	(KSZ8895_COUNTER_NUM + 2)
+
+#define SWITCH_COUNTER_NUM		KSZ8895_COUNTER_NUM
+#define TOTAL_SWITCH_COUNTER_NUM	TOTAL_KSZ8895_COUNTER_NUM
+
+#define SW_D				u8
+#define SW_R(sw, addr)			(sw)->reg->r8(sw, addr)
+#define SW_W(sw, addr, val)		(sw)->reg->w8(sw, addr, val)
+#define SW_SIZE				(1)
+#define SW_SIZE_STR			"%02x"
+
+
+#define P_BCAST_STORM_CTRL		REG_PORT_CTRL_0
+#define P_PRIO_CTRL			REG_PORT_CTRL_0
+#define P_TAG_CTRL			REG_PORT_CTRL_0
+#define P_MIRROR_CTRL			REG_PORT_CTRL_1
+#define P_802_1P_CTRL			REG_PORT_CTRL_2
+#define P_STP_CTRL			REG_PORT_CTRL_2
+#define P_LOCAL_CTRL			REG_PORT_CTRL_5
+#define P_REMOTE_STATUS			REG_PORT_STATUS_1
+#define P_FORCE_CTRL			REG_PORT_CTRL_5
+#define P_NEG_RESTART_CTRL		REG_PORT_CTRL_6
+#define P_SPEED_STATUS			REG_PORT_STATUS_0
+#define P_LINK_STATUS			REG_PORT_STATUS_1
+#define P_INS_SRC_PVID_CTRL		REG_PORT_CTRL_8
+#define P_DROP_TAG_CTRL			REG_PORT_CTRL_9
+#define P_RATE_LIMIT_CTRL		REG_PORT_RATE_LIMIT
+
+#define S_FLUSH_TABLE_CTRL		REG_SW_CTRL_0
+#define S_LINK_AGING_CTRL		REG_SW_CTRL_0
+#define S_HUGE_PACKET_CTRL		REG_SW_CTRL_2
+#define S_MIRROR_CTRL			REG_SW_CTRL_3
+#define S_REPLACE_VID_CTRL		REG_SW_CTRL_4
+#define S_PASS_PAUSE_CTRL		REG_SW_CTRL_10
+#define S_TAIL_TAG_CTRL			REG_SW_CTRL_10
+#define S_802_1P_PRIO_CTRL		REG_SW_CTRL_12
+#define S_TOS_PRIO_CTRL			REG_TOS_PRIO_CTRL_0
+#define S_IPV6_MLD_CTRL			REG_SW_CTRL_21
+
+#define IND_ACC_TABLE(table)		((table) << 8)
+
+#define TAIL_TAG_OVERRIDE		(1 << 6)
+#define TAIL_TAG_LOOKUP			(1 << 7)
+
+#endif
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index de66ca8e6201..4f973723d32a 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -29,7 +29,7 @@
  *	  (eg, 0x00=port1, 0x02=port3, 0x06=port7)
  */
 
-#define	KSZ_INGRESS_TAG_LEN	2
+#define	KSZ_INGRESS_TAG_LEN	1
 #define	KSZ_EGRESS_TAG_LEN	1
 
 static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -40,6 +40,7 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
 	u8 *tag;
 
 	padlen = (skb->len >= ETH_ZLEN) ? 0 : ETH_ZLEN - skb->len;
+	printk("ksz_xmit...\n");
 
 	if (skb_tailroom(skb) >= padlen + KSZ_INGRESS_TAG_LEN) {
 		if (skb_put_padto(skb, skb->len + padlen))
@@ -69,8 +70,9 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	tag = skb_put(nskb, KSZ_INGRESS_TAG_LEN);
-	tag[0] = 0;
-	tag[1] = 1 << p->dp->index; /* destination port */
+	tag[0] = 1 << p->dp->index; /* destination port */
+
+	printk("ksz_xmit: tagging with %lx\n", 1 << p->dp->index);
 
 	return nskb;
 }
@@ -88,6 +90,7 @@ static struct sk_buff *ksz_rcv(struct sk_buff *skb, struct net_device *dev,
 	tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
 
 	source_port = tag[0] & 7;
+	printk("ksz_rcv: got source port %d\n", source_port);
 	if (source_port >= ds->num_ports || !ds->ports[source_port].netdev)
 		return NULL;
 

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: DSA support for Micrel KSZ8895
  2017-08-23  9:09     ` Pavel Machek
@ 2017-08-23 12:42       ` Andrew Lunn
  2017-08-23 21:48       ` Woojung.Huh
  1 sibling, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2017-08-23 12:42 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Tristram.Ha

> Any ideas how to do the work in a way to minimize code duplication are
> welcome...

A lot depends on how much duplication there is. mv88e6xxx uses a set
of function points per chip variant. Another option is to put the
common code into a library, and have two drivers. Or if it is the same
registers, but at different locations, you can add a translation
function, which is what i think the b53 driver does.

	  Andrew

^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: DSA support for Micrel KSZ8895
  2017-08-23  9:09     ` Pavel Machek
  2017-08-23 12:42       ` Andrew Lunn
@ 2017-08-23 21:48       ` Woojung.Huh
  2017-08-28 10:14         ` Pavel Machek
  1 sibling, 1 reply; 35+ messages in thread
From: Woojung.Huh @ 2017-08-23 21:48 UTC (permalink / raw)
  To: pavel, nathan.leigh.conrad
  Cc: vivien.didelot, f.fainelli, netdev, linux-kernel, Tristram.Ha, andrew

Pavel,

> > I'll forward your email to our support.
> > AFAIK, KSZ8895 has different register mapping from KSZ9477,
> > it will be more than ID changes in current driver.
> 
> More than ID changes, indeed. As layout is completely different, it
> looks like different source file will be needed for support.
> 
> I'm not nearly there; but I can ifconfig lanX up, already, and perform
> some pings.
> 
> Any ideas how to do the work in a way to minimize code duplication are
> welcome...

Which version do you use to create patch?
Getting error when applying patch to the latest net-next.

- Woojung

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH] DSA support for Micrel KSZ8895
  2017-08-16 14:25   ` Woojung.Huh
  2017-08-23  9:09     ` Pavel Machek
@ 2017-08-27 12:36     ` Pavel Machek
  2017-08-27 13:59       ` Andrew Lunn
                         ` (5 more replies)
  1 sibling, 6 replies; 35+ messages in thread
From: Pavel Machek @ 2017-08-27 12:36 UTC (permalink / raw)
  To: Woojung.Huh, nathan.leigh.conrad
  Cc: vivien.didelot, f.fainelli, netdev, linux-kernel, Tristram.Ha,
	andrew, pavel

[-- Attachment #1: Type: text/plain, Size: 62101 bytes --]

Hi!

So I fought with the driver a bit more, and now I have something that
kind-of-works.

"great great hack" belows worries me.

Yeah, disabled code needs to be removed before merge.

No, tag_ksz part probably is not acceptable. Do you see solution
better than just copying it into tag_ksz1 file?

Any more comments, etc?

Help would be welcome.

Best regards,
									Pavel

Signed-off-by: Pavel Machek <pavel@denx.de>

diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
index a8b8f59099ce..7b7d7ddb3488 100644
--- a/drivers/net/dsa/microchip/Kconfig
+++ b/drivers/net/dsa/microchip/Kconfig
@@ -1,12 +1,25 @@
 menuconfig MICROCHIP_KSZ
-	tristate "Microchip KSZ series switch support"
+	tristate "Microchip KSZ 9477 series switch support"
+	depends on NET_DSA
+	select NET_DSA_TAG_KSZ
+	help
+	  This driver adds support for Microchip KSZ switch chips.
+
+menuconfig MICROCHIP_KSZ_8895
+	tristate "Microchip KSZ 8895 series switch support"
 	depends on NET_DSA
 	select NET_DSA_TAG_KSZ
 	help
 	  This driver adds support for Microchip KSZ switch chips.
 
 config MICROCHIP_KSZ_SPI_DRIVER
-	tristate "KSZ series SPI connected switch driver"
+	tristate "KSZ 9477 series SPI connected switch driver"
 	depends on MICROCHIP_KSZ && SPI
 	help
 	  Select to enable support for registering switches configured through SPI.
+
+config MICROCHIP_KSZ_8895_SPI_DRIVER
+	tristate "KSZ 8895 series SPI connected switch driver"
+	depends on MICROCHIP_KSZ_8895 && SPI
+	help
+	  Select to enable support for registering switches configured through SPI.
diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile
index ed335e29fae8..b6a17f79d2d9 100644
--- a/drivers/net/dsa/microchip/Makefile
+++ b/drivers/net/dsa/microchip/Makefile
@@ -1,2 +1,4 @@
 obj-$(CONFIG_MICROCHIP_KSZ)	        += ksz_common.o
+obj-$(CONFIG_MICROCHIP_KSZ_8895)        += ksz_8895.o
 obj-$(CONFIG_MICROCHIP_KSZ_SPI_DRIVER)	+= ksz_spi.o
+obj-$(CONFIG_MICROCHIP_KSZ_8895_SPI_DRIVER)	+= ksz_8895_spi.o
diff --git a/drivers/net/dsa/microchip/ksz_8895.c b/drivers/net/dsa/microchip/ksz_8895.c
new file mode 100644
index 000000000000..d546e08b1281
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz_8895.c
@@ -0,0 +1,721 @@
+/*
+ * Microchip switch driver main logic
+ *
+ * Copyright (C) 2017
+ * Copyright (C) 2017 Pavel Machek <pavel@denx.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_data/microchip-ksz.h>
+#include <linux/phy.h>
+#include <linux/etherdevice.h>
+#include <linux/if_bridge.h>
+#include <net/dsa.h>
+#include <net/switchdev.h>
+
+#include "ksz_8895_reg.h"
+#include "ksz_priv.h"
+
+static const struct {
+	int index;
+	char string[ETH_GSTRING_LEN];
+} mib_names[TOTAL_SWITCH_COUNTER_NUM] = {
+	{ 0x00, "???" },
+};
+
+static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
+{
+	u8 data;
+
+	ksz_read8(dev, addr, &data);
+	if (set)
+		data |= bits;
+	else
+		data &= ~bits;
+	ksz_write8(dev, addr, data);
+}
+
+#if 0
+static void ksz_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set)
+{
+	u32 data;
+
+	ksz_read32(dev, addr, &data);
+	if (set)
+		data |= bits;
+	else
+		data &= ~bits;
+	ksz_write32(dev, addr, data);
+}
+#endif
+
+static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
+			 bool set)
+{
+	u32 addr;
+	u8 data;
+
+	addr = PORT_CTRL_ADDR(port, offset);
+	ksz_read8(dev, addr, &data);
+
+	if (set)
+		data |= bits;
+	else
+		data &= ~bits;
+
+	ksz_write8(dev, addr, data);
+}
+
+#if 0
+static void ksz_port_cfg32(struct ksz_device *dev, int port, int offset,
+			   u32 bits, bool set)
+{
+	u32 addr;
+	u32 data;
+
+	addr = PORT_CTRL_ADDR(port, offset);
+	ksz_read32(dev, addr, &data);
+
+	if (set)
+		data |= bits;
+	else
+		data &= ~bits;
+
+	ksz_write32(dev, addr, data);
+}
+#endif
+
+#define NOTIMPL() do { NOTIMPLV(); return -EJUKEBOX; } while (0)
+#define NOTIMPLV() do { printk("Not implemented -- %s\n",  __func__); } while (0)
+
+static int ksz_reset_switch(struct dsa_switch *ds)
+{
+	struct ksz_device *dev = ds->priv;
+#if 0
+	/* This seems to break the code. */
+	ksz_write8(dev, REG_POWER_MANAGEMENT_1, SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S);
+        ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0);
+#endif
+	return 0;
+}
+
+#define PORT_MAC_LOOPBACK_my 0x80
+#define REG_PORT_CTRL_LOOPBACK 0x0f
+
+static void port_setup(struct ksz_device *dev, int port, bool cpu_port)
+{
+	printk("Port setup %d, %d\n", port, cpu_port);
+
+	if (cpu_port && port != 4)
+		printk("!!! tail tagging only works on port 5\n");
+	if (cpu_port) {
+		printk("enable tail tagging\n");
+		ksz_cfg(dev, S_TAIL_TAG_CTRL, SW_TAIL_TAG_ENABLE, true);
+	}
+
+	ksz_port_cfg(dev, port, REG_PORT_CTRL_LOOPBACK, PORT_MAC_LOOPBACK_my, false);
+#ifdef FIXME
+	/* set back pressure */
+	ksz_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, true);
+
+	/* set flow control */
+	ksz_port_cfg(dev, port, REG_PORT_CTRL_0,
+		     PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, true);
+
+	/* enable broadcast storm limit */
+	ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true);
+
+	/* disable DiffServ priority */
+	ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_PRIO_ENABLE, false);
+
+	/* replace priority */
+	ksz_port_cfg(dev, port, REG_PORT_MRI_MAC_CTRL, PORT_USER_PRIO_CEILING,
+		     false);
+	ksz_port_cfg32(dev, port, REG_PORT_MTI_QUEUE_CTRL_0__4,
+		       MTI_PVID_REPLACE, false);
+
+	/* enable 802.1p priority */
+	ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true);
+
+	/* configure MAC to 1G & RGMII mode */
+	ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8);
+	data8 |= PORT_RGMII_ID_EG_ENABLE;
+	data8 &= ~PORT_MII_NOT_1GBIT;
+	data8 &= ~PORT_MII_SEL_M;
+	data8 |= PORT_RGMII_SEL;
+	ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8);
+
+	/* clear pending interrupts */
+	ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16);
+#endif
+}
+
+static void ksz_config_cpu_port(struct dsa_switch *ds)
+{
+	struct ksz_device *dev = ds->priv;
+	int i;
+
+	ds->num_ports = dev->port_cnt;
+
+	for (i = 0; i < ds->num_ports; i++) {
+		if (dsa_is_cpu_port(ds, i) && (dev->cpu_ports & (1 << i))) {
+			dev->cpu_port = i;
+
+			/* enable cpu port */
+			port_setup(dev, i, true);
+		}
+	}
+}
+
+#if 0
+/*
+ * sw_init_vlan - initialize switch VLAN
+ *
+ * Everyone can communicate with CPU, ports do not communicate with each other
+ */
+static void sw_init_vlan(struct ksz_device *dev)
+{
+	int port;
+	
+	for (port = 0; port < dev->port_cnt; port++) {
+		//port_get_def_vid(sw, port, &info->port_cfg[port].vid);
+		//port_r(sw, port, P_MIRROR_CTRL, &data);
+
+		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_VLAN_MEMBERSHIP, false);
+		ksz_port_cfg(dev, port, P_MIRROR_CTRL, 1<<port, true);		
+#if 0
+		port_cfg(sw, port, P_INS_SRC_PVID_CTRL,
+			(PORT_INS_TAG_FOR_PORT_5 | PORT_INS_TAG_FOR_PORT_4 |
+			PORT_INS_TAG_FOR_PORT_3 | PORT_INS_TAG_FOR_PORT_2),
+			true);
+#endif
+	}
+	ksz_port_cfg(dev, dev->port_cnt-1, P_MIRROR_CTRL, PORT_VLAN_MEMBERSHIP, true);
+}
+
+static void sw_init_bridge(struct ksz_device *dev)
+{
+	int port;
+
+	for (port = 0; port < dev->port_cnt; port++) {
+		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_VLAN_MEMBERSHIP, true);
+	}
+}
+#endif
+
+static void br_update(struct dsa_switch *ds)
+{
+	struct ksz_device *dev = ds->priv;
+	int i,j;
+	int mask[5];
+	u8 val;
+
+	for (i = 0; i < dev->port_cnt; i++) {
+		mask[i] = 0;
+	}
+
+	for (i = 0; i < dev->port_cnt; i++) {
+		for (j = 0; j < dev->port_cnt; j++) {
+			//printk("port %d bridge %lx\n", i, (unsigned long) ds->ports[i].bridge_dev);
+			if (ds->ports[i].bridge_dev &&
+			    (ds->ports[i].bridge_dev == ds->ports[j].bridge_dev))
+				mask[i] |= 1<<j;
+		}
+	}
+
+	for (i = 0; i < dev->port_cnt-1; i++) {
+		printk("port %d mask %x\n", i, mask[i]);
+		ksz_pread8(dev, i, P_MIRROR_CTRL, &val);
+		val &= ~PORT_VLAN_MEMBERSHIP;
+		val |= mask[i] | 0x10 | (1 << i);
+		ksz_pwrite8(dev, i, P_MIRROR_CTRL, val);
+	}
+
+	ksz_pread8(dev, dev->port_cnt-1, P_MIRROR_CTRL, &val);
+	val &= ~PORT_VLAN_MEMBERSHIP;
+	val |= mask[i] | 0x1f;
+	ksz_pwrite8(dev, dev->port_cnt-1, P_MIRROR_CTRL, val);
+
+}
+
+
+/* bridge_change -- need to get it here */
+
+int ksz_br_join(struct dsa_switch *ds, int port, struct net_device *br)
+{
+	struct ksz_device *dev = ds->priv;
+
+	br_update(ds);
+	return 0;
+}
+
+void ksz_br_leave(struct dsa_switch *ds, int port, struct net_device *br)
+{
+	struct ksz_device *dev = ds->priv;
+
+//	sw_init_vlan(dev);
+	
+	br_update(ds);
+}
+
+
+
+static int ksz_setup(struct dsa_switch *ds)
+{
+	struct ksz_device *dev = ds->priv;
+	int ret = 0;
+
+	dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
+				       dev->num_vlans, GFP_KERNEL);
+	if (!dev->vlan_cache)
+		return -ENOMEM;
+
+	ret = ksz_reset_switch(ds);
+	if (ret) {
+		dev_err(ds->dev, "failed to reset switch\n");
+		return ret;
+	}
+
+	/* accept packet up to 2000bytes */
+	//ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_LEGAL_PACKET_DISABLE, true);
+
+	ksz_config_cpu_port(ds);
+
+	ksz_cfg(dev, REG_SW_CTRL_2, MULTICAST_STORM_DISABLE, true);
+
+	/* queue based egress rate limit */
+	//ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
+
+	//sw_init_broad_storm(sw);
+        //sw_init_prio(sw);
+        //sw_init_prio_rate(sw);
+	//sw_init_vlan(ds); FIXME!!!
+
+	/* start switch */
+	ksz_cfg(dev, REG_CHIP_ID1, SW_START, true);
+
+	return 0;
+}
+
+static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds)
+{
+	return DSA_TAG_PROTO_KSZ;
+}
+
+#include "ksz_mdio_emulation.c"
+
+static int ksz_enable_port(struct dsa_switch *ds, int port,
+			   struct phy_device *phy)
+{
+	struct ksz_device *dev = ds->priv;
+
+	/* setup slave port */
+	port_setup(dev, port, false);
+
+	return 0;
+}
+
+
+static void ksz_disable_port(struct dsa_switch *ds, int port,
+			     struct phy_device *phy)
+{
+	struct ksz_device *dev = ds->priv;
+
+	/* there is no port disable */
+	ksz_port_cfg(dev, port, REG_PORT_CTRL_LOOPBACK, PORT_MAC_LOOPBACK_my, true);
+}
+
+static int ksz_sset_count(struct dsa_switch *ds)
+{
+	return TOTAL_SWITCH_COUNTER_NUM;
+}
+
+static void ksz_get_strings(struct dsa_switch *ds, int port, uint8_t *buf)
+{
+	int i;
+
+	for (i = 0; i < TOTAL_SWITCH_COUNTER_NUM; i++) {
+		memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string,
+		       ETH_GSTRING_LEN);
+	}
+}
+
+static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
+				  uint64_t *buf)
+{
+	NOTIMPLV();
+}
+
+#if 0
+static void ksz_dump(struct ksz_device *dev)
+{
+	int i;
+	u8 v;
+
+	printk("ksz: dumping:\n");
+	for (i = 0; i < 0x100; i++) {
+		if (!(i % 0x10))
+			printk("\n %x: ", i);
+		ksz_read8(dev, i, &v);
+		printk("%02x ", v);
+	}
+	printk("\nksz: dump done\n");
+}
+#endif
+
+static void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
+{
+	struct ksz_device *dev = ds->priv;
+	u8 data;
+
+	printk("port %d state %d\n", port, state);
+	ksz_pread8(dev, port, P_STP_CTRL, &data);
+	data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
+
+	switch (state) {
+	case BR_STATE_DISABLED:
+		printk("port %d state %d disable\n", port, state);				
+		data |= PORT_LEARN_DISABLE;
+		break;
+	case BR_STATE_LISTENING:
+		printk("port %d state %d listen\n", port, state);
+		data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE);
+		break;
+	case BR_STATE_LEARNING:
+		printk("port %d state %d learn\n", port, state);
+		data |= PORT_RX_ENABLE;
+		break;
+	case BR_STATE_FORWARDING:
+		printk("port %d state %d forwarding\n", port, state);		
+		data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
+		break;
+	case BR_STATE_BLOCKING:
+		printk("port %d state %d blocking\n", port, state);
+		data |= PORT_LEARN_DISABLE;
+		break;
+	default:
+		dev_err(ds->dev, "invalid STP state: %d\n", state);
+		return;
+	}
+	/* FIXME: great great hack */
+	data |= (PORT_RX_ENABLE | PORT_TX_ENABLE);
+	
+
+	ksz_pwrite8(dev, port, P_STP_CTRL, data);
+	//ksz_dump(dev);
+}
+
+static void ksz_port_fast_age(struct dsa_switch *ds, int port)
+{
+	NOTIMPLV();
+	
+}
+
+static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag)
+{
+	NOTIMPL();
+	return 0;
+}
+
+static int ksz_port_vlan_prepare(struct dsa_switch *ds, int port,
+				 const struct switchdev_obj_port_vlan *vlan,
+				 struct switchdev_trans *trans)
+{
+	/* nothing needed */
+
+	return 0;
+}
+
+static void ksz_port_vlan_add(struct dsa_switch *ds, int port,
+			      const struct switchdev_obj_port_vlan *vlan,
+			      struct switchdev_trans *trans)
+{
+	NOTIMPLV();
+}
+
+static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
+			     const struct switchdev_obj_port_vlan *vlan)
+{
+	NOTIMPL();
+
+	return 0;
+}
+
+static int ksz_port_vlan_dump(struct dsa_switch *ds, int port,
+			      struct switchdev_obj_port_vlan *vlan,
+			      switchdev_obj_dump_cb_t *cb)
+{
+	NOTIMPL();
+}
+
+static int ksz_port_fdb_prepare(struct dsa_switch *ds, int port,
+				const struct switchdev_obj_port_fdb *fdb,
+				struct switchdev_trans *trans)
+{
+	/* nothing needed */
+
+	return 0;
+}
+
+struct alu_struct {
+	/* entry 1 */
+	u8	is_static:1;
+	u8	is_src_filter:1;
+	u8	is_dst_filter:1;
+	u8	prio_age:3;
+	u32	_reserv_0_1:23;
+	u8	mstp:3;
+	/* entry 2 */
+	u8	is_override:1;
+	u8	is_use_fid:1;
+	u32	_reserv_1_1:23;
+	u8	port_forward:7;
+	/* entry 3 & 4*/
+	u32	_reserv_2_1:9;
+	u8	fid:7;
+	u8	mac[ETH_ALEN];
+};
+
+static void ksz_port_fdb_add(struct dsa_switch *ds, int port,
+			     const struct switchdev_obj_port_fdb *fdb,
+			     struct switchdev_trans *trans)
+{
+	NOTIMPLV();
+}
+
+static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
+			    const struct switchdev_obj_port_fdb *fdb)
+{
+	NOTIMPL();
+}
+
+static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
+			     struct switchdev_obj_port_fdb *fdb,
+			     switchdev_obj_dump_cb_t *cb)
+{
+	NOTIMPL();
+}
+
+static int ksz_port_mdb_prepare(struct dsa_switch *ds, int port,
+				const struct switchdev_obj_port_mdb *mdb,
+				struct switchdev_trans *trans)
+{
+	/* nothing to do */
+	return 0;
+}
+
+static void ksz_port_mdb_add(struct dsa_switch *ds, int port,
+			     const struct switchdev_obj_port_mdb *mdb,
+			     struct switchdev_trans *trans)
+{
+	NOTIMPLV();
+}
+
+static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
+			    const struct switchdev_obj_port_mdb *mdb)
+{
+	NOTIMPL();
+}
+
+static int ksz_port_mdb_dump(struct dsa_switch *ds, int port,
+			     struct switchdev_obj_port_mdb *mdb,
+			     switchdev_obj_dump_cb_t *cb)
+{
+	/* this is not called by switch layer */
+	return 0;
+}
+
+static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
+			       struct dsa_mall_mirror_tc_entry *mirror,
+			       bool ingress)
+{
+	NOTIMPL();
+
+}
+
+static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
+				struct dsa_mall_mirror_tc_entry *mirror)
+{
+	NOTIMPLV();
+}
+
+static const struct dsa_switch_ops ksz_switch_ops = {
+	.get_tag_protocol	= ksz_get_tag_protocol,
+	.setup			= ksz_setup,
+	.phy_read		= ksz_phy_read16,
+	.phy_write		= ksz_phy_write16,
+	.port_enable		= ksz_enable_port,
+	.port_disable		= ksz_disable_port,
+	.get_strings		= ksz_get_strings,
+	.get_ethtool_stats	= ksz_get_ethtool_stats,
+	.get_sset_count		= ksz_sset_count,
+	.port_bridge_join	= ksz_br_join,
+	.port_bridge_leave	= ksz_br_leave,
+	.port_stp_state_set	= ksz_port_stp_state_set,
+	.port_fast_age		= ksz_port_fast_age,
+	.port_vlan_filtering	= ksz_port_vlan_filtering,
+	.port_vlan_prepare	= ksz_port_vlan_prepare,
+	.port_vlan_add		= ksz_port_vlan_add,
+	.port_vlan_del		= ksz_port_vlan_del,
+	.port_vlan_dump		= ksz_port_vlan_dump,
+	.port_fdb_prepare	= ksz_port_fdb_prepare,
+	.port_fdb_dump		= ksz_port_fdb_dump,
+	.port_fdb_add		= ksz_port_fdb_add,
+	.port_fdb_del		= ksz_port_fdb_del,
+	.port_mdb_prepare       = ksz_port_mdb_prepare,
+	.port_mdb_add           = ksz_port_mdb_add,
+	.port_mdb_del           = ksz_port_mdb_del,
+	.port_mdb_dump          = ksz_port_mdb_dump,
+	.port_mirror_add	= ksz_port_mirror_add,
+	.port_mirror_del	= ksz_port_mirror_del,
+};
+
+struct ksz_chip_data {
+	u32 chip_id;
+	const char *dev_name;
+	int num_vlans;
+	int num_alus;
+	int num_statics;
+	int cpu_ports;
+	int port_cnt;
+};
+
+static const struct ksz_chip_data ksz_switch_chips[] = {
+	{
+		.chip_id = 0x95600c04,
+		.dev_name = "KSZ8895",
+		.num_vlans = 4096, /* FIXME ? */
+		.num_alus = 4096,
+		.num_statics = 16,
+		.cpu_ports = 0x10,	/* can be configured as cpu port */
+		.port_cnt = 5,		/* total physical port count */
+	},
+};
+
+static int ksz_switch_init(struct ksz_device *dev)
+{
+	int i;
+
+	mutex_init(&dev->reg_mutex);
+	mutex_init(&dev->stats_mutex);
+	mutex_init(&dev->alu_mutex);
+	mutex_init(&dev->vlan_mutex);
+
+	dev->ds->ops = &ksz_switch_ops;
+
+	for (i = 0; i < ARRAY_SIZE(ksz_switch_chips); i++) {
+		const struct ksz_chip_data *chip = &ksz_switch_chips[i];
+
+		if (dev->chip_id == chip->chip_id) {
+			dev->name = chip->dev_name;
+			dev->num_vlans = chip->num_vlans;
+			dev->num_alus = chip->num_alus;
+			dev->num_statics = chip->num_statics;
+			dev->port_cnt = chip->port_cnt;
+			dev->cpu_ports = chip->cpu_ports;
+
+			break;
+		}
+	}
+	
+	printk("ksz_switch_init: detected %s\n", dev->name);
+
+	/* no switch found */
+	if (!dev->port_cnt)
+		return -ENODEV;
+
+	return 0;
+}
+
+struct ksz_device *ksz_switch_alloc(struct device *base,
+				    const struct ksz_io_ops *ops,
+				    void *priv)
+{
+	struct dsa_switch *ds;
+	struct ksz_device *swdev;
+
+	ds = dsa_switch_alloc(base, DSA_MAX_PORTS);
+	if (!ds)
+		return NULL;
+
+	swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL);
+	if (!swdev)
+		return NULL;
+
+	ds->priv = swdev;
+	swdev->dev = base;
+
+	swdev->ds = ds;
+	swdev->priv = priv;
+	swdev->ops = ops;
+
+	return swdev;
+}
+EXPORT_SYMBOL(ksz_switch_alloc);
+
+int ksz_switch_detect(struct ksz_device *dev)
+{
+	u8 data8;
+	u32 id32;
+	int ret;
+
+	/* read chip id */
+	ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32);
+	if (ret)
+		return ret;
+	
+	ret = ksz_read8(dev, 0, &data8);
+	ret = ksz_read8(dev, 1, &data8);
+	ret = ksz_read8(dev, 2, &data8);
+	ret = ksz_read8(dev, 3, &data8);
+	
+	dev->chip_id = id32;
+
+	return 0;
+}
+EXPORT_SYMBOL(ksz_switch_detect);
+
+int ksz_switch_register(struct ksz_device *dev)
+{
+	int ret;
+
+	if (dev->pdata)
+		dev->chip_id = dev->pdata->chip_id;
+
+	if (ksz_switch_detect(dev))
+		return -EINVAL;
+
+	ret = ksz_switch_init(dev);
+	if (ret)
+		return ret;
+
+
+	return dsa_register_switch(dev->ds);
+}
+EXPORT_SYMBOL(ksz_switch_register);
+
+void ksz_switch_remove(struct ksz_device *dev)
+{
+	dsa_unregister_switch(dev->ds);
+}
+EXPORT_SYMBOL(ksz_switch_remove);
+
+MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
+MODULE_DESCRIPTION("Microchip KSZ Series Switch DSA Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/ksz_8895_reg.h b/drivers/net/dsa/microchip/ksz_8895_reg.h
new file mode 100644
index 000000000000..b6490c42448e
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz_8895_reg.h
@@ -0,0 +1,769 @@
+/*
+ * Microchip KSZ9477 register definitions
+ *
+ * Copyright (C) 2017
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __KSZ9477_REGS_H
+#define __KSZ9477_REGS_H
+
+#define KS_PRIO_M			0x3
+#define KS_PRIO_S			2
+
+/* 0 - Operation */
+#define REG_CHIP_ID0__1			0x0000
+
+#define REG_CHIP_ID1__1			0x0001
+
+#define SW_START 1
+
+#define FAMILY_ID			0x95
+#define FAMILY_ID_94			0x94
+#define FAMILY_ID_95			0x95
+#define FAMILY_ID_85			0x85
+#define FAMILY_ID_98			0x98
+#define FAMILY_ID_88			0x88
+
+#define TOTAL_SWITCH_COUNTER_NUM	1
+#define PORT_CTRL_ADDR(port, addr)	((addr) | (((port) + 1) << 4))
+
+#define ADDR_SHIFT			14
+#define ADDR_8				1
+#define ADDR_16				2
+#define ADDR_24				3
+#define ADDR_32				4
+
+#define BANK_SHIFT			12
+
+#define PHY_REG(addr, reg)		\
+	(((addr) << ADDR_SHIFT) | (reg))
+
+#define PHY_BANK_REG(addr, bank, reg)	\
+	(((addr) << ADDR_SHIFT) | ((bank) << BANK_SHIFT) | (reg))
+
+/* Use PHY access if no direct access. */
+#ifndef SW_R8
+#define SW_R8(s, r)	phy_read(s->phydev, PHY_REG(ADDR_8, r))
+#define SW_W8(s, r, v)	phy_write(s->phydev, PHY_REG(ADDR_8, r), v)
+#define SW_R16(s, r)	phy_read(s->phydev, PHY_REG(ADDR_16, r))
+#define SW_W16(s, r, v)	phy_write(s->phydev, PHY_REG(ADDR_16, r), v)
+#define SW_R32(s, r)	phy_read(s->phydev, PHY_REG(ADDR_32, r))
+#define SW_W32(s, r, v) \
+	do { \
+		phy_write(s->phydev, PHY_REG(ADDR_32, (r) + 2), (v) >> 16); \
+		phy_write(s->phydev, PHY_REG(ADDR_32, r), v); \
+	} while (0)
+#define SW_LOCK(s)				\
+	do {					\
+		mutex_lock(s->hwlock);		\
+	} while (0)
+#define SW_UNLOCK(s)				\
+	do {					\
+		mutex_unlock(s->hwlock);	\
+	} while (0)
+#endif
+
+
+#define KS_PORT_M			0x1F
+
+#define REG_CHIP_ID0			0x00
+
+#define FAMILY_ID			0x95
+
+#define REG_CHIP_ID1			0x01
+
+#define SW_CHIP_ID_M			0xF0
+#define SW_CHIP_ID_S			4
+#define SW_REVISION_M			0x0E
+#define SW_REVISION_S			1
+
+#define CHIP_ID_95			0x40
+#define CHIP_ID_95R			0x60
+
+#define REG_SW_CTRL_0			0x02
+
+#define SW_NEW_BACKOFF			(1 << 7)
+#define SW_FLUSH_DYN_MAC_TABLE		(1 << 5)
+#define SW_FLUSH_STA_MAC_TABLE		(1 << 4)
+#define SW_UNH_MODE			(1 << 1)
+#define SW_LINK_AUTO_AGING		(1 << 0)
+
+#define REG_SW_CTRL_1			0x03
+
+#define SW_PASS_ALL			(1 << 7)
+#define SW_2K_PACKET			(1 << 6)
+#define SW_TX_FLOW_CTRL_DISABLE		(1 << 5)
+#define SW_RX_FLOW_CTRL_DISABLE		(1 << 4)
+#define SW_CHECK_LENGTH			(1 << 3)
+#define SW_AGING_ENABLE			(1 << 2)
+#define SW_FAST_AGING			(1 << 1)
+#define SW_AGGR_BACKOFF			(1 << 0)
+
+#define REG_SW_CTRL_2			0x04
+
+#define UNICAST_VLAN_BOUNDARY		(1 << 7)
+#define MULTICAST_STORM_DISABLE		(1 << 6)
+#define SW_BACK_PRESSURE		(1 << 5)
+#define FAIR_FLOW_CTRL			(1 << 4)
+#define NO_EXC_COLLISION_DROP		(1 << 3)
+#define SW_HUGE_PACKET			(1 << 2)
+#define SW_LEGAL_PACKET			(1 << 1)
+
+#define REG_SW_CTRL_3			0x05
+#define SW_VLAN_ENABLE			(1 << 7)
+#define SW_IGMP_SNOOP			(1 << 6)
+#define SW_DIRECT			(1 << 5)
+#define SW_PRE_TAG			(1 << 4)
+#define SW_VLAN_TAG			(1 << 1)
+#define SW_MIRROR_RX_TX			(1 << 0)
+
+#define REG_SW_CTRL_4			0x06
+
+#define SW_HALF_DUPLEX_FLOW_CTRL	(1 << 7)
+#define SW_HALF_DUPLEX			(1 << 6)
+#define SW_FLOW_CTRL			(1 << 5)
+#define SW_10_MBIT			(1 << 4)
+#define SW_REPLACE_VID			(1 << 3)
+#define BROADCAST_STORM_RATE_HI		0x07
+
+#define REG_SW_CTRL_5			0x07
+
+#define BROADCAST_STORM_RATE_LO		0xFF
+#define BROADCAST_STORM_RATE		0x07FF
+
+#define REG_SW_CTRL_9			0x0B
+
+#define SW_DATA_SAMPLING_NEG		(1 << 6)
+#define SW_PHY_POWER_SAVE_DISABLE	(1 << 3)
+#define SW_LED_MODE_1			(1 << 1)
+#define SW_SPI_SAMPLING_RISING		(1 << 0)
+
+#define REG_SW_CTRL_10			0x0C
+
+#define SPI_CLK_125_MHZ			0x20
+#define SPI_CLK_83_33_MHZ		0x10
+#define SPI_CLK_41_67_MHZ		0x00
+#define SW_TAIL_TAG_ENABLE		(1 << 1)
+#define SW_PASS_PAUSE			(1 << 0)
+
+#define REG_SW_CTRL_11			0x0D
+
+#define REG_POWER_MANAGEMENT_1		0x0E
+
+#define SW_PLL_POWER_DOWN		(1 << 5)
+#define SW_POWER_MANAGEMENT_MODE_M	0x3
+#define SW_POWER_MANAGEMENT_MODE_S	3
+#define SW_POWER_NORMAL			0
+#define SW_ENERGY_DETECTION		1
+#define SW_SOFTWARE_POWER_DOWN		2
+#define SW_POWER_SAVING			3
+
+#define REG_POWER_MANAGEMENT_2		0x0F
+
+
+#define REG_PORT_1_CTRL_0		0x10
+#define REG_PORT_2_CTRL_0		0x20
+#define REG_PORT_3_CTRL_0		0x30
+#define REG_PORT_4_CTRL_0		0x40
+#define REG_PORT_5_CTRL_0		0x50
+
+#define PORT_BROADCAST_STORM		(1 << 7)
+#define PORT_DIFFSERV_ENABLE		(1 << 6)
+#define PORT_802_1P_ENABLE		(1 << 5)
+#define PORT_BASED_PRIO_S		3
+#define PORT_BASED_PRIO_M		(KS_PRIO_M << PORT_BASED_PRIO_S)
+#define PORT_PORT_PRIO_0		0
+#define PORT_PORT_PRIO_1		1
+#define PORT_PORT_PRIO_2		2
+#define PORT_PORT_PRIO_3		3
+#define PORT_INSERT_TAG			(1 << 2)
+#define PORT_REMOVE_TAG			(1 << 1)
+#define PORT_QUEUE_SPLIT_L		(1 << 0)
+
+#define REG_PORT_1_CTRL_1		0x11
+#define REG_PORT_2_CTRL_1		0x21
+#define REG_PORT_3_CTRL_1		0x31
+#define REG_PORT_4_CTRL_1		0x41
+#define REG_PORT_5_CTRL_1		0x51
+
+#define PORT_MIRROR_SNIFFER		(1 << 7)
+#define PORT_MIRROR_RX			(1 << 6)
+#define PORT_MIRROR_TX			(1 << 5)
+#define PORT_VLAN_MEMBERSHIP		KS_PORT_M
+
+#define REG_PORT_1_CTRL_2		0x12
+#define REG_PORT_2_CTRL_2		0x22
+#define REG_PORT_3_CTRL_2		0x32
+#define REG_PORT_4_CTRL_2		0x42
+#define REG_PORT_5_CTRL_2		0x52
+
+#define PORT_802_1P_REMAPPING		(1 << 7)
+#define PORT_INGRESS_FILTER		(1 << 6)
+#define PORT_DISCARD_NON_VID		(1 << 5)
+#define PORT_FORCE_FLOW_CTRL		(1 << 4)
+#define PORT_BACK_PRESSURE		(1 << 3)
+#define PORT_TX_ENABLE			(1 << 2)
+#define PORT_RX_ENABLE			(1 << 1)
+#define PORT_LEARN_DISABLE		(1 << 0)
+
+#define REG_PORT_1_CTRL_3		0x13
+#define REG_PORT_2_CTRL_3		0x23
+#define REG_PORT_3_CTRL_3		0x33
+#define REG_PORT_4_CTRL_3		0x43
+#define REG_PORT_5_CTRL_3		0x53
+#define REG_PORT_1_CTRL_4		0x14
+#define REG_PORT_2_CTRL_4		0x24
+#define REG_PORT_3_CTRL_4		0x34
+#define REG_PORT_4_CTRL_4		0x44
+#define REG_PORT_5_CTRL_4		0x54
+
+#define PORT_DEFAULT_VID		0x0001
+
+#define REG_PORT_1_STATUS_0		0x19
+#define REG_PORT_2_STATUS_0		0x29
+#define REG_PORT_3_STATUS_0		0x39
+#define REG_PORT_4_STATUS_0		0x49
+#define REG_PORT_5_STATUS_0		0x59
+
+#define PORT_HP_MDIX			(1 << 7)
+#define PORT_REVERSED_POLARITY		(1 << 5)
+#define PORT_TX_FLOW_CTRL		(1 << 4)
+#define PORT_RX_FLOW_CTRL		(1 << 3)
+#define PORT_STAT_SPEED_100MBIT		(1 << 2)
+#define PORT_STAT_FULL_DUPLEX		(1 << 1)
+
+#define REG_PORT_1_LINK_MD_CTRL		0x1A
+#define REG_PORT_2_LINK_MD_CTRL		0x2A
+#define REG_PORT_3_LINK_MD_CTRL		0x3A
+#define REG_PORT_4_LINK_MD_CTRL		0x4A
+#define REG_PORT_5_LINK_MD_CTRL		0x5A
+
+#define PORT_CABLE_10M_SHORT		(1 << 7)
+#define PORT_CABLE_DIAG_RESULT_M	0x3
+#define PORT_CABLE_DIAG_RESULT_S	5
+#define PORT_CABLE_STAT_NORMAL		0
+#define PORT_CABLE_STAT_OPEN		1
+#define PORT_CABLE_STAT_SHORT		2
+#define PORT_CABLE_STAT_FAILED		3
+#define PORT_START_CABLE_DIAG		(1 << 4)
+#define PORT_FORCE_LINK			(1 << 3)
+#define PORT_POWER_SAVING		(1 << 2)
+#define PORT_PHY_REMOTE_LOOPBACK	(1 << 1)
+#define PORT_CABLE_FAULT_COUNTER_H	0x01
+
+#define REG_PORT_1_LINK_MD_RESULT	0x1B
+#define REG_PORT_2_LINK_MD_RESULT	0x2B
+#define REG_PORT_3_LINK_MD_RESULT	0x3B
+#define REG_PORT_4_LINK_MD_RESULT	0x4B
+#define REG_PORT_5_LINK_MD_RESULT	0x5B
+
+#define PORT_CABLE_FAULT_COUNTER_L	0xFF
+#define PORT_CABLE_FAULT_COUNTER	0x1FF
+
+#define REG_PORT_1_CTRL_5		0x1C
+#define REG_PORT_2_CTRL_5		0x2C
+#define REG_PORT_3_CTRL_5		0x3C
+#define REG_PORT_4_CTRL_5		0x4C
+#define REG_PORT_5_CTRL_5		0x5C
+
+#define PORT_AUTO_NEG_DISABLE		(1 << 7)
+#define PORT_FORCE_100_MBIT		(1 << 6)
+#define PORT_FORCE_FULL_DUPLEX		(1 << 5)
+#define PORT_AUTO_NEG_SYM_PAUSE		(1 << 4)
+#define PORT_AUTO_NEG_100BTX_FD		(1 << 3)
+#define PORT_AUTO_NEG_100BTX		(1 << 2)
+#define PORT_AUTO_NEG_10BT_FD		(1 << 1)
+#define PORT_AUTO_NEG_10BT		(1 << 0)
+
+#define REG_PORT_1_CTRL_6		0x1D
+#define REG_PORT_2_CTRL_6		0x2D
+#define REG_PORT_3_CTRL_6		0x3D
+#define REG_PORT_4_CTRL_6		0x4D
+#define REG_PORT_5_CTRL_6		0x5D
+
+#define PORT_LED_OFF			(1 << 7)
+#define PORT_TX_DISABLE			(1 << 6)
+#define PORT_AUTO_NEG_RESTART		(1 << 5)
+#define PORT_POWER_DOWN			(1 << 3)
+#define PORT_AUTO_MDIX_DISABLE		(1 << 2)
+#define PORT_FORCE_MDIX			(1 << 1)
+#define PORT_MAC_LOOPBACK		(1 << 0)
+
+#define REG_PORT_1_STATUS_1		0x1E
+#define REG_PORT_2_STATUS_1		0x2E
+#define REG_PORT_3_STATUS_1		0x3E
+#define REG_PORT_4_STATUS_1		0x4E
+#define REG_PORT_5_STATUS_1		0x5E
+
+#define PORT_MDIX_STATUS		(1 << 7)
+#define PORT_AUTO_NEG_COMPLETE		(1 << 6)
+#define PORT_STAT_LINK_GOOD		(1 << 5)
+#define PORT_REMOTE_SYM_PAUSE		(1 << 4)
+#define PORT_REMOTE_100BTX_FD		(1 << 3)
+#define PORT_REMOTE_100BTX		(1 << 2)
+#define PORT_REMOTE_10BT_FD		(1 << 1)
+#define PORT_REMOTE_10BT		(1 << 0)
+
+#define REG_PORT_1_STATUS_2		0x1F
+#define REG_PORT_2_STATUS_2		0x2F
+#define REG_PORT_3_STATUS_2		0x3F
+#define REG_PORT_4_STATUS_2		0x4F
+#define REG_PORT_5_STATUS_2		0x5F
+
+#define PORT_PHY_LOOPBACK		(1 << 7)
+#define PORT_PHY_ISOLATE		(1 << 5)
+#define PORT_PHY_SOFT_RESET		(1 << 4)
+#define PORT_PHY_FORCE_LINK		(1 << 3)
+#define PORT_PHY_MODE_M			0x7
+#define PHY_MODE_IN_AUTO_NEG		1
+#define PHY_MODE_10BT_HALF		2
+#define PHY_MODE_100BT_HALF		3
+#define PHY_MODE_10BT_FULL		5
+#define PHY_MODE_100BT_FULL		6
+#define PHY_MODE_ISOLDATE		7
+
+#define REG_PORT_CTRL_0			0x00
+#define REG_PORT_CTRL_1			0x01
+#define REG_PORT_CTRL_2			0x02
+#define REG_PORT_CTRL_VID		0x03
+
+#define REG_PORT_STATUS_0		0x09
+#define REG_PORT_LINK_MD_CTRL		0x0A
+#define REG_PORT_LINK_MD_RESULT		0x0B
+#define REG_PORT_CTRL_5			0x0C
+#define REG_PORT_CTRL_6			0x0D
+#define REG_PORT_STATUS_1		0x0E
+#define REG_PORT_STATUS_2		0x0F
+
+#define REG_PORT_CTRL_8			0xA0
+#define REG_PORT_CTRL_9			0xA1
+#define REG_PORT_RATE_CTRL_3		0xA2
+#define REG_PORT_RATE_CTRL_2		0xA3
+#define REG_PORT_RATE_CTRL_1		0xA4
+#define REG_PORT_RATE_CTRL_0		0xA5
+#define REG_PORT_RATE_LIMIT		0xA6
+#define REG_PORT_IN_RATE_0		0xA7
+#define REG_PORT_IN_RATE_1		0xA8
+#define REG_PORT_IN_RATE_2		0xA9
+#define REG_PORT_IN_RATE_3		0xAA
+#define REG_PORT_OUT_RATE_0		0xAB
+#define REG_PORT_OUT_RATE_1		0xAC
+#define REG_PORT_OUT_RATE_2		0xAD
+#define REG_PORT_OUT_RATE_3		0xAE
+
+#define REG_SW_MAC_ADDR_0		0x68
+#define REG_SW_MAC_ADDR_1		0x69
+#define REG_SW_MAC_ADDR_2		0x6A
+#define REG_SW_MAC_ADDR_3		0x6B
+#define REG_SW_MAC_ADDR_4		0x6C
+#define REG_SW_MAC_ADDR_5		0x6D
+
+#define REG_IND_CTRL_0			0x6E
+
+#define TABLE_READ			(1 << 4)
+#define TABLE_SELECT_S			2
+#define TABLE_STATIC_MAC		(0 << TABLE_SELECT_S)
+#define TABLE_VLAN			(1 << TABLE_SELECT_S)
+#define TABLE_DYNAMIC_MAC		(2 << TABLE_SELECT_S)
+#define TABLE_MIB			(3 << TABLE_SELECT_S)
+
+#define REG_IND_CTRL_1			0x6F
+
+#define TABLE_ENTRY_MASK		0x03FF
+
+#define REG_IND_DATA_8			0x70
+#define REG_IND_DATA_7			0x71
+#define REG_IND_DATA_6			0x72
+#define REG_IND_DATA_5			0x73
+#define REG_IND_DATA_4			0x74
+#define REG_IND_DATA_3			0x75
+#define REG_IND_DATA_2			0x76
+#define REG_IND_DATA_1			0x77
+#define REG_IND_DATA_0			0x78
+
+#define REG_IND_DATA_CHECK		REG_IND_DATA_6
+#define REG_IND_MIB_CHECK		REG_IND_DATA_3
+#define REG_IND_DATA_HI			REG_IND_DATA_7
+#define REG_IND_DATA_LO			REG_IND_DATA_3
+
+#define REG_INT_STATUS			0x7C
+#define REG_INT_ENABLE			0x7D
+
+#define INT_PORT_5			(1 << 4)
+#define INT_PORT_4			(1 << 3)
+#define INT_PORT_3			(1 << 2)
+#define INT_PORT_2			(1 << 1)
+#define INT_PORT_1			(1 << 0)
+
+#define REG_SW_CTRL_12			0x80
+#define REG_SW_CTRL_13			0x81
+
+#define SWITCH_802_1P_MASK		3
+#define SWITCH_802_1P_BASE		3
+#define SWITCH_802_1P_SHIFT		2
+
+#define SW_802_1P_MAP_M			KS_PRIO_M
+#define SW_802_1P_MAP_S			KS_PRIO_S
+
+#define REG_SWITCH_CTRL_14		0x82
+
+#define SW_PRIO_MAPPING_M		KS_PRIO_M
+#define SW_PRIO_MAPPING_S		6
+#define SW_PRIO_MAP_3_HI		0
+#define SW_PRIO_MAP_2_HI		2
+#define SW_PRIO_MAP_0_LO		3
+
+#define REG_SW_CTRL_15			0x83
+#define REG_SW_CTRL_16			0x84
+
+#define SW_DRIVE_STRENGTH_M		0x3
+#define SW_DRIVE_STRENGTH_4MA		0
+#define SW_DRIVE_STRENGTH_8MA		1
+#define SW_DRIVE_STRENGTH_10MA		2
+#define SW_DRIVE_STRENGTH_14MA		3
+#define SW_MII_DRIVE_STRENGTH_S		6
+
+#define REG_SW_CTRL_17			0x85
+#define REG_SW_CTRL_18			0x86
+
+#define SW_SELF_ADDR_FILTER_ENABLE	(1 << 6)
+
+#define REG_SW_UNK_UCAST_CTRL		0x83
+#define REG_SW_UNK_MCAST_CTRL		0x84
+#define REG_SW_UNK_VID_CTRL		0x85
+#define REG_SW_UNK_IP_MCAST_CTRL	0x86
+
+#define SW_UNK_FWD_ENABLE		(1 << 5)
+#define SW_UNK_FWD_MAP			KS_PORT_M
+
+#define REG_SW_CTRL_19			0x87
+
+#define SW_IN_RATE_LIMIT_PERIOD_M	0x3
+#define SW_IN_RATE_LIMIT_PERIOD_S	4
+#define SW_IN_RATE_LIMIT_16_MS		0
+#define SW_IN_RATE_LIMIT_64_MS		1
+#define SW_IN_RATE_LIMIT_256_MS		2
+#define SW_QUEUE_BASED_OUT_RATE_LIMIT	(1 << 3)
+#define SW_INS_TAG_ENABLE		(1 << 2)
+
+#define REG_TOS_PRIO_CTRL_0		0x90
+#define REG_TOS_PRIO_CTRL_1		0x91
+#define REG_TOS_PRIO_CTRL_2		0x92
+#define REG_TOS_PRIO_CTRL_3		0x93
+#define REG_TOS_PRIO_CTRL_4		0x94
+#define REG_TOS_PRIO_CTRL_5		0x95
+#define REG_TOS_PRIO_CTRL_6		0x96
+#define REG_TOS_PRIO_CTRL_7		0x97
+#define REG_TOS_PRIO_CTRL_8		0x98
+#define REG_TOS_PRIO_CTRL_9		0x99
+#define REG_TOS_PRIO_CTRL_10		0x9A
+#define REG_TOS_PRIO_CTRL_11		0x9B
+#define REG_TOS_PRIO_CTRL_12		0x9C
+#define REG_TOS_PRIO_CTRL_13		0x9D
+#define REG_TOS_PRIO_CTRL_14		0x9E
+#define REG_TOS_PRIO_CTRL_15		0x9F
+
+#define TOS_PRIO_M			KS_PRIO_M
+#define TOS_PRIO_S			KS_PRIO_S
+
+
+#define REG_PORT_1_CTRL_8		0xB0
+#define REG_PORT_2_CTRL_8		0xC0
+#define REG_PORT_3_CTRL_8		0xD0
+#define REG_PORT_4_CTRL_8		0xE0
+#define REG_PORT_5_CTRL_8		0xF0
+
+#define PORT_INS_TAG_FOR_PORT_5_S	3
+#define PORT_INS_TAG_FOR_PORT_5		(1 << 3)
+#define PORT_INS_TAG_FOR_PORT_4		(1 << 2)
+#define PORT_INS_TAG_FOR_PORT_3		(1 << 1)
+#define PORT_INS_TAG_FOR_PORT_2		(1 << 0)
+
+#define REG_PORT_1_CTRL_9		0xB1
+#define REG_PORT_2_CTRL_9		0xC1
+#define REG_PORT_3_CTRL_9		0xD1
+#define REG_PORT_4_CTRL_9		0xE1
+#define REG_PORT_5_CTRL_9		0xF1
+
+#define PORT_QUEUE_SPLIT_H		(1 << 1)
+#define PORT_QUEUE_SPLIT_1		0
+#define PORT_QUEUE_SPLIT_2		1
+#define PORT_QUEUE_SPLIT_4		2
+#define PORT_DROP_TAG			(1 << 0)
+
+#define REG_PORT_1_CTRL_10		0xB2
+#define REG_PORT_2_CTRL_10		0xC2
+#define REG_PORT_3_CTRL_10		0xD2
+#define REG_PORT_4_CTRL_10		0xE2
+#define REG_PORT_5_CTRL_10		0xF2
+#define REG_PORT_1_CTRL_11		0xB3
+#define REG_PORT_2_CTRL_11		0xC3
+#define REG_PORT_3_CTRL_11		0xD3
+#define REG_PORT_4_CTRL_11		0xE3
+#define REG_PORT_5_CTRL_11		0xF3
+#define REG_PORT_1_CTRL_12		0xB4
+#define REG_PORT_2_CTRL_12		0xC4
+#define REG_PORT_3_CTRL_12		0xD4
+#define REG_PORT_4_CTRL_12		0xE4
+#define REG_PORT_5_CTRL_12		0xF4
+#define REG_PORT_1_CTRL_13		0xB5
+#define REG_PORT_2_CTRL_13		0xC5
+#define REG_PORT_3_CTRL_13		0xD5
+#define REG_PORT_4_CTRL_13		0xE5
+#define REG_PORT_5_CTRL_13		0xF5
+
+#define REG_PORT_1_RATE_CTRL_3		0xB2
+#define REG_PORT_1_RATE_CTRL_2		0xB3
+#define REG_PORT_1_RATE_CTRL_1		0xB4
+#define REG_PORT_1_RATE_CTRL_0		0xB5
+#define REG_PORT_2_RATE_CTRL_3		0xC2
+#define REG_PORT_2_RATE_CTRL_2		0xC3
+#define REG_PORT_2_RATE_CTRL_1		0xC4
+#define REG_PORT_2_RATE_CTRL_0		0xC5
+#define REG_PORT_3_RATE_CTRL_3		0xD2
+#define REG_PORT_3_RATE_CTRL_2		0xD3
+#define REG_PORT_3_RATE_CTRL_1		0xD4
+#define REG_PORT_3_RATE_CTRL_0		0xD5
+#define REG_PORT_4_RATE_CTRL_3		0xE2
+#define REG_PORT_4_RATE_CTRL_2		0xE3
+#define REG_PORT_4_RATE_CTRL_1		0xE4
+#define REG_PORT_4_RATE_CTRL_0		0xE5
+#define REG_PORT_5_RATE_CTRL_3		0xF2
+#define REG_PORT_5_RATE_CTRL_2		0xF3
+#define REG_PORT_5_RATE_CTRL_1		0xF4
+#define REG_PORT_5_RATE_CTRL_0		0xF5
+
+#define RATE_CTRL_ENABLE		(1 << 7)
+#define RATE_RATIO_M			((1 << 7) - 1)
+
+#define REG_PORT_1_RATE_LIMIT		0xB6
+#define REG_PORT_2_RATE_LIMIT		0xC6
+#define REG_PORT_3_RATE_LIMIT		0xD6
+#define REG_PORT_4_RATE_LIMIT		0xE6
+#define REG_PORT_5_RATE_LIMIT		0xF6
+
+#define PORT_IN_FLOW_CTRL_S		4
+#define PORT_IN_LIMIT_MODE_M		0x3
+#define PORT_IN_LIMIT_MODE_S		2
+#define PORT_COUNT_IFG_S		1
+#define PORT_COUNT_PREAMBLE_S		0
+#define PORT_IN_FLOW_CTRL		(1 << PORT_IN_FLOW_CTRL_S)
+#define PORT_IN_ALL			0
+#define PORT_IN_UNICAST			1
+#define PORT_IN_MULTICAST		2
+#define PORT_IN_BROADCAST		3
+#define PORT_COUNT_IFG			(1 << PORT_COUNT_IFG_S)
+#define PORT_COUNT_PREAMBLE		(1 << PORT_COUNT_PREAMBLE_S)
+
+#define REG_PORT_1_IN_RATE_0		0xB7
+#define REG_PORT_2_IN_RATE_0		0xC7
+#define REG_PORT_3_IN_RATE_0		0xD7
+#define REG_PORT_4_IN_RATE_0		0xE7
+#define REG_PORT_5_IN_RATE_0		0xF7
+#define REG_PORT_1_IN_RATE_1		0xB8
+#define REG_PORT_2_IN_RATE_1		0xC8
+#define REG_PORT_3_IN_RATE_1		0xD8
+#define REG_PORT_4_IN_RATE_1		0xE8
+#define REG_PORT_5_IN_RATE_1		0xF8
+#define REG_PORT_1_IN_RATE_2		0xB9
+#define REG_PORT_2_IN_RATE_2		0xC9
+#define REG_PORT_3_IN_RATE_2		0xD9
+#define REG_PORT_4_IN_RATE_2		0xE9
+#define REG_PORT_5_IN_RATE_2		0xF9
+#define REG_PORT_1_IN_RATE_3		0xBA
+#define REG_PORT_2_IN_RATE_3		0xCA
+#define REG_PORT_3_IN_RATE_3		0xDA
+#define REG_PORT_4_IN_RATE_3		0xEA
+#define REG_PORT_5_IN_RATE_3		0xFA
+
+#define PORT_RATE_LIMIT_M		((1 << 7) - 1)
+
+#define REG_PORT_1_OUT_RATE_0		0xBB
+#define REG_PORT_2_OUT_RATE_0		0xCB
+#define REG_PORT_3_OUT_RATE_0		0xDB
+#define REG_PORT_4_OUT_RATE_0		0xEB
+#define REG_PORT_5_OUT_RATE_0		0xFB
+#define REG_PORT_1_OUT_RATE_1		0xBC
+#define REG_PORT_2_OUT_RATE_1		0xCC
+#define REG_PORT_3_OUT_RATE_1		0xDC
+#define REG_PORT_4_OUT_RATE_1		0xEC
+#define REG_PORT_5_OUT_RATE_1		0xFC
+#define REG_PORT_1_OUT_RATE_2		0xBD
+#define REG_PORT_2_OUT_RATE_2		0xCD
+#define REG_PORT_3_OUT_RATE_2		0xDD
+#define REG_PORT_4_OUT_RATE_2		0xED
+#define REG_PORT_5_OUT_RATE_2		0xFD
+#define REG_PORT_1_OUT_RATE_3		0xBE
+#define REG_PORT_2_OUT_RATE_3		0xCE
+#define REG_PORT_3_OUT_RATE_3		0xDE
+#define REG_PORT_4_OUT_RATE_3		0xEE
+#define REG_PORT_5_OUT_RATE_3		0xFE
+
+
+#define REG_SW_CFG			0xEF
+
+#define SW_PORT_3_FIBER			(1 << 7)
+
+/* KSZ8864 */
+
+#define REG_PHY_PORT_CTRL_1		0xCF
+
+#define PORT_HALF_DUPLEX		(1 << 7)
+#define PORT_FLOW_CTRL			(1 << 6)
+#define PORT_10_MBIT			(1 << 5)
+
+#define REG_PHY_PORT_CTRL_2		0xDF
+
+#define PORT_MII_MAC_MODE		(1 << 6)
+
+#define REG_KSZ8864_CHIP_ID		0xFE
+
+#define SW_KSZ8864			(1 << 7)
+
+
+#ifndef PHY_REG_CTRL
+#define PHY_REG_CTRL			0
+
+#define PHY_RESET			(1 << 15)
+#define PHY_LOOPBACK			(1 << 14)
+#define PHY_SPEED_100MBIT		(1 << 13)
+#define PHY_AUTO_NEG_ENABLE		(1 << 12)
+#define PHY_POWER_DOWN			(1 << 11)
+#define PHY_MII_DISABLE			(1 << 10)
+#define PHY_AUTO_NEG_RESTART		(1 << 9)
+#define PHY_FULL_DUPLEX			(1 << 8)
+#define PHY_COLLISION_TEST_NOT		(1 << 7)
+#define PHY_HP_MDIX			(1 << 5)
+#define PHY_FORCE_MDIX			(1 << 4)
+#define PHY_AUTO_MDIX_DISABLE		(1 << 3)
+#define PHY_REMOTE_FAULT_DISABLE	(1 << 2)
+#define PHY_TRANSMIT_DISABLE		(1 << 1)
+#define PHY_LED_DISABLE			(1 << 0)
+
+#define PHY_REG_STATUS			1
+
+#define PHY_100BT4_CAPABLE		(1 << 15)
+#define PHY_100BTX_FD_CAPABLE		(1 << 14)
+#define PHY_100BTX_CAPABLE		(1 << 13)
+#define PHY_10BT_FD_CAPABLE		(1 << 12)
+#define PHY_10BT_CAPABLE		(1 << 11)
+#define PHY_MII_SUPPRESS_CAPABLE_NOT	(1 << 6)
+#define PHY_AUTO_NEG_ACKNOWLEDGE	(1 << 5)
+#define PHY_REMOTE_FAULT		(1 << 4)
+#define PHY_AUTO_NEG_CAPABLE		(1 << 3)
+#define PHY_LINK_STATUS			(1 << 2)
+#define PHY_JABBER_DETECT_NOT		(1 << 1)
+#define PHY_EXTENDED_CAPABILITY		(1 << 0)
+
+#define PHY_REG_ID_1			2
+#define PHY_REG_ID_2			3
+
+#define KSZ8895_ID_HI			0x0022
+#define KSZ8895_ID_LO			0x1450
+
+#define PHY_REG_AUTO_NEGOTIATION	4
+
+#define PHY_AUTO_NEG_NEXT_PAGE_NOT	(1 << 15)
+#define PHY_AUTO_NEG_REMOTE_FAULT_NOT	(1 << 13)
+#define PHY_AUTO_NEG_SYM_PAUSE		(1 << 10)
+#define PHY_AUTO_NEG_100BT4		(1 << 9)
+#define PHY_AUTO_NEG_100BTX_FD		(1 << 8)
+#define PHY_AUTO_NEG_100BTX		(1 << 7)
+#define PHY_AUTO_NEG_10BT_FD		(1 << 6)
+#define PHY_AUTO_NEG_10BT		(1 << 5)
+#define PHY_AUTO_NEG_SELECTOR		0x001F
+#define PHY_AUTO_NEG_802_3		0x0001
+
+#define PHY_REG_REMOTE_CAPABILITY	5
+
+#define PHY_REMOTE_NEXT_PAGE_NOT	(1 << 15)
+#define PHY_REMOTE_ACKNOWLEDGE_NOT	(1 << 14)
+#define PHY_REMOTE_REMOTE_FAULT_NOT	(1 << 13)
+#define PHY_REMOTE_SYM_PAUSE		(1 << 10)
+#define PHY_REMOTE_100BTX_FD		(1 << 8)
+#define PHY_REMOTE_100BTX		(1 << 7)
+#define PHY_REMOTE_10BT_FD		(1 << 6)
+#define PHY_REMOTE_10BT			(1 << 5)
+
+#define PHY_REG_LINK_MD			0x1D
+
+#define PHY_START_CABLE_DIAG		(1 << 15)
+#define PHY_CABLE_DIAG_RESULT		0x6000
+#define PHY_CABLE_STAT_NORMAL		0x0000
+#define PHY_CABLE_STAT_OPEN		0x2000
+#define PHY_CABLE_STAT_SHORT		0x4000
+#define PHY_CABLE_STAT_FAILED		0x6000
+#define PHY_CABLE_10M_SHORT		(1 << 12)
+#define PHY_CABLE_FAULT_COUNTER		0x01FF
+
+#define PHY_REG_PHY_CTRL		0x1F
+
+#define PHY_MODE_M			0x7
+#define PHY_MODE_S			8
+#define PHY_STAT_REVERSED_POLARITY	(1 << 5)
+#define PHY_STAT_MDIX			(1 << 4)
+#define PHY_FORCE_LINK			(1 << 3)
+#define PHY_POWER_SAVING_ENABLE		(1 << 2)
+#define PHY_REMOTE_LOOPBACK		(1 << 1)
+#endif
+
+
+/* Default values are used in ksz_sw.h if these are not defined. */
+#define PRIO_QUEUES			4
+
+#define KS_PRIO_IN_REG			4
+
+#define SWITCH_PORT_NUM			4
+
+#define SW_D				u8
+#define SW_R(sw, addr)			(sw)->reg->r8(sw, addr)
+#define SW_W(sw, addr, val)		(sw)->reg->w8(sw, addr, val)
+#define SW_SIZE				(1)
+#define SW_SIZE_STR			"%02x"
+
+
+#define P_BCAST_STORM_CTRL		REG_PORT_CTRL_0
+#define P_PRIO_CTRL			REG_PORT_CTRL_0
+#define P_TAG_CTRL			REG_PORT_CTRL_0
+#define P_MIRROR_CTRL			REG_PORT_CTRL_1
+#define P_802_1P_CTRL			REG_PORT_CTRL_2
+#define P_STP_CTRL			REG_PORT_CTRL_2
+#define P_LOCAL_CTRL			REG_PORT_CTRL_5
+#define P_REMOTE_STATUS			REG_PORT_STATUS_1
+#define P_FORCE_CTRL			REG_PORT_CTRL_5
+#define P_NEG_RESTART_CTRL		REG_PORT_CTRL_6
+#define P_SPEED_STATUS			REG_PORT_STATUS_0
+#define P_LINK_STATUS			REG_PORT_STATUS_1
+#define P_INS_SRC_PVID_CTRL		REG_PORT_CTRL_8
+#define P_DROP_TAG_CTRL			REG_PORT_CTRL_9
+#define P_RATE_LIMIT_CTRL		REG_PORT_RATE_LIMIT
+
+#define S_FLUSH_TABLE_CTRL		REG_SW_CTRL_0
+#define S_LINK_AGING_CTRL		REG_SW_CTRL_0
+#define S_HUGE_PACKET_CTRL		REG_SW_CTRL_2
+#define S_MIRROR_CTRL			REG_SW_CTRL_3
+#define S_REPLACE_VID_CTRL		REG_SW_CTRL_4
+#define S_PASS_PAUSE_CTRL		REG_SW_CTRL_10
+#define S_TAIL_TAG_CTRL			REG_SW_CTRL_10
+#define S_802_1P_PRIO_CTRL		REG_SW_CTRL_12
+#define S_TOS_PRIO_CTRL			REG_TOS_PRIO_CTRL_0
+#define S_IPV6_MLD_CTRL			REG_SW_CTRL_21
+
+#define IND_ACC_TABLE(table)		((table) << 8)
+
+#define TAIL_TAG_OVERRIDE		(1 << 6)
+#define TAIL_TAG_LOOKUP			(1 << 7)
+
+#endif /* KSZ9477_REGS_H */
diff --git a/drivers/net/dsa/microchip/ksz_8895_spi.c b/drivers/net/dsa/microchip/ksz_8895_spi.c
new file mode 100644
index 000000000000..b1c9571c8e99
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz_8895_spi.c
@@ -0,0 +1,275 @@
+/*
+ * Microchip KSZ series register access through SPI
+ *
+ * Copyright (C) 2017 Woojung Huh <Woojung.Huh@microchip.com>
+ * Copyright (C) 2017 Pavel Machek <pavel@denx.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <asm/unaligned.h>
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "ksz_8895_reg.h"
+#include "ksz_priv.h"
+
+/* SPI frame opcodes */
+#define KS_SPIOP_RD			3
+#define KS_SPIOP_WR			2
+
+static int ksz_spi_read_reg(struct spi_device *spi, u32 reg, u8 *val,
+			    unsigned int len)
+{
+	int ret;
+
+	u8 buf[2];
+
+	buf[0] = KS_SPIOP_RD;
+	buf[1] = reg;
+
+	ret = spi_write_then_read(spi, buf, 2, val, len);
+	return ret;
+}
+
+static int ksz_spi_read(struct ksz_device *dev, u32 reg, u8 *data,
+			unsigned int len)
+{
+	struct spi_device *spi = dev->priv;
+
+	return ksz_spi_read_reg(spi, reg, data, len);
+}
+
+static int ksz_spi_read8(struct ksz_device *dev, u32 reg, u8 *val)
+{
+	return ksz_spi_read(dev, reg, val, 1);
+}
+
+static int ksz_spi_read16(struct ksz_device *dev, u32 reg, u16 *val)
+{
+	int ret = ksz_spi_read(dev, reg, (u8 *)val, 2);
+
+	if (!ret)
+		*val = be16_to_cpu(*val);
+
+	return ret;
+}
+
+static int ksz_spi_read24(struct ksz_device *dev, u32 reg, u32 *val)
+{
+	int ret;
+
+	*val = 0;
+	ret = ksz_spi_read(dev, reg, (u8 *)val, 3);
+	if (!ret) {
+		*val = be32_to_cpu(*val);
+		/* convert to 24bit */
+		*val >>= 8;
+	}
+
+	return ret;
+}
+
+static int ksz_spi_read32(struct ksz_device *dev, u32 reg, u32 *val)
+{
+	int ret = ksz_spi_read(dev, reg, (u8 *)val, 4);
+
+	if (!ret)
+		*val = be32_to_cpu(*val);
+
+	return ret;
+}
+
+static int ksz_spi_write_reg(struct spi_device *spi, u32 reg, u8 *val,
+			     unsigned int len)
+{
+	u8 data[12];
+
+	int i;
+	
+	data[0] = KS_SPIOP_WR;
+	data[1] = reg;
+	for (i = 0; i < len; i++)
+		data[i + 2] = val[i];
+
+	return spi_write(spi, &data, 2 + len);
+}
+
+static int ksz_spi_write8(struct ksz_device *dev, u32 reg, u8 value)
+{
+	struct spi_device *spi = dev->priv;
+
+	return ksz_spi_write_reg(spi, reg, &value, 1);
+}
+
+static int ksz_spi_write16(struct ksz_device *dev, u32 reg, u16 value)
+{
+	struct spi_device *spi = dev->priv;
+
+	value = cpu_to_be16(value);
+	return ksz_spi_write_reg(spi, reg, (u8 *)&value, 2);
+}
+
+static int ksz_spi_write24(struct ksz_device *dev, u32 reg, u32 value)
+{
+	struct spi_device *spi = dev->priv;
+
+	/* make it to big endian 24bit from MSB */
+	value <<= 8;
+	value = cpu_to_be32(value);
+	return ksz_spi_write_reg(spi, reg, (u8 *)&value, 3);
+}
+
+static int ksz_spi_write32(struct ksz_device *dev, u32 reg, u32 value)
+{
+	struct spi_device *spi = dev->priv;
+
+	value = cpu_to_be32(value);
+	return ksz_spi_write_reg(spi, reg, (u8 *)&value, 4);
+}
+
+static const struct ksz_io_ops ksz_spi_ops = {
+	.read8 = ksz_spi_read8,
+	.read16 = ksz_spi_read16,
+	.read24 = ksz_spi_read24,
+	.read32 = ksz_spi_read32,
+	.write8 = ksz_spi_write8,
+	.write16 = ksz_spi_write16,
+	.write24 = ksz_spi_write24,
+	.write32 = ksz_spi_write32,
+};
+
+static int ksz_spi_sysfs_read(struct ksz_device *dev, char *buf,
+		 unsigned offset, size_t count)
+{
+	int err = 0;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		ksz_read8(dev, i+offset, buf+i+offset);
+	}
+
+	return err ? err : count;
+}
+
+static int ksz_spi_sysfs_write(struct ksz_device *dev, char *buf,
+		 unsigned offset, size_t count)
+{
+	int err = -EINVAL;
+
+	return err ? err : count;
+}
+
+static ssize_t ksz_spi_registers_read(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
+{
+	struct device *dev;
+	struct ksz_device *ks;
+
+	dev = container_of(kobj, struct device, kobj);
+	ks = dev_get_drvdata(dev);
+
+	return ksz_spi_sysfs_read(ks, buf, off, count);
+}
+
+static ssize_t ksz_spi_registers_write(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
+{
+	struct device *dev;
+	struct ksz_device *ks;
+
+	dev = container_of(kobj, struct device, kobj);
+	ks = dev_get_drvdata(dev);
+
+	return ksz_spi_sysfs_write(ks, buf, off, count);
+}
+
+static const struct bin_attribute ksz_spi_registers_attr = {
+	.attr = {
+		.name   = "registers",
+		.mode   = S_IRUSR | S_IWUSR,
+	},
+	.size   = 0x100,
+	.read   = ksz_spi_registers_read,
+	.write  = ksz_spi_registers_write,
+};
+
+static int ksz_spi_probe(struct spi_device *spi)
+{
+	struct ksz_device *dev;
+	int ret;
+
+	dev = ksz_switch_alloc(&spi->dev, &ksz_spi_ops, spi);
+	if (!dev)
+		return -ENOMEM;
+
+	if (spi->dev.platform_data)
+		dev->pdata = spi->dev.platform_data;
+
+	ret = ksz_switch_register(dev);
+	if (ret)
+		return ret;
+
+	memcpy(&dev->regs_attr, &ksz_spi_registers_attr, sizeof(dev->regs_attr));
+        dev->regs_attr.size = 0x100;
+
+        sysfs_attr_init(&dev->regs_attr.attr);
+        ret = sysfs_create_bin_file(&spi->dev.kobj, &dev->regs_attr);
+
+        if (ret) {
+                dev_err(&spi->dev, "unable to create sysfs file, err=%d\n",
+                                    ret);
+                return ret;
+        }
+	
+	spi_set_drvdata(spi, dev);
+
+	return 0;
+}
+
+static int ksz_spi_remove(struct spi_device *spi)
+{
+	struct ksz_device *dev = spi_get_drvdata(spi);
+
+	if (dev)
+		ksz_switch_remove(dev);
+
+	sysfs_remove_bin_file(&spi->dev.kobj, &dev->regs_attr);
+	
+	return 0;
+}
+
+static const struct of_device_id ksz_dt_ids[] = {
+	{ .compatible = "microchip,ksz8895" },	
+	{},
+};
+MODULE_DEVICE_TABLE(of, ksz_dt_ids);
+
+static struct spi_driver ksz_spi_driver = {
+	.driver = {
+		.name	= "ksz8895-switch",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ksz_dt_ids),
+	},
+	.probe	= ksz_spi_probe,
+	.remove	= ksz_spi_remove,
+};
+
+module_spi_driver(ksz_spi_driver);
+
+MODULE_AUTHOR("Pavel Machek <pavel@denx.de>");
+MODULE_DESCRIPTION("Microchip KSZ Series Switch SPI access Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/ksz_9477_reg.h b/drivers/net/dsa/microchip/ksz_9477_reg.h
index 6aa6752035a1..af4d29c2ba4f 100644
--- a/drivers/net/dsa/microchip/ksz_9477_reg.h
+++ b/drivers/net/dsa/microchip/ksz_9477_reg.h
@@ -16,6 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#error This is not switch we have
 #ifndef __KSZ9477_REGS_H
 #define __KSZ9477_REGS_H
 
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index b313ecdf2919..6741d05d0ac4 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -28,6 +28,7 @@
 #include <net/dsa.h>
 #include <net/switchdev.h>
 
+#include "ksz_9477_reg.h"
 #include "ksz_priv.h"
 
 static const struct {
diff --git a/drivers/net/dsa/microchip/ksz_mdio_emulation.c b/drivers/net/dsa/microchip/ksz_mdio_emulation.c
new file mode 100644
index 000000000000..a4e24506bed8
--- /dev/null
+++ b/drivers/net/dsa/microchip/ksz_mdio_emulation.c
@@ -0,0 +1,286 @@
+/**
+ * Micrel KSZ8895 SPI driver
+ *
+ * Copyright (c) 2015 Micrel, Inc.
+ *
+ * GPLv2
+ */
+
+#define PHY_ID_KSZ8895		((KSZ8895_ID_HI << 16) | KSZ8895_ID_LO)
+
+/**
+ * sw_r_phy - read data from PHY register
+ * @sw:		The switch instance.
+ * @phy:	PHY address to read.
+ * @reg:	PHY register to read.
+ * @val:	Buffer to store the read data.
+ *
+ * This routine reads data from the PHY register.
+ */
+static void sw_r_phy(struct ksz_device *sw, u16 phy, u16 reg, u16 *val)
+{
+	u8 ctrl;
+	u8 restart;
+	u8 link;
+	u8 speed;
+	u8 force;
+	u8 p = phy;
+	u16 data = 0;
+
+	switch (reg) {
+	case PHY_REG_CTRL:
+		ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
+		ksz_pread8(sw, p, P_NEG_RESTART_CTRL, &restart);
+		ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
+		ksz_pread8(sw, p, P_FORCE_CTRL, &force);
+		if (restart & PORT_PHY_LOOPBACK)
+			data |= PHY_LOOPBACK;
+		if (force & PORT_FORCE_100_MBIT)
+			data |= PHY_SPEED_100MBIT;
+		if (!(force & PORT_AUTO_NEG_DISABLE))
+			data |= PHY_AUTO_NEG_ENABLE;
+		if (restart & PORT_POWER_DOWN)
+			data |= PHY_POWER_DOWN;
+		if (restart & PORT_AUTO_NEG_RESTART)
+			data |= PHY_AUTO_NEG_RESTART;
+		if (force & PORT_FORCE_FULL_DUPLEX)
+			data |= PHY_FULL_DUPLEX;
+		if (speed & PORT_HP_MDIX)
+			data |= PHY_HP_MDIX;
+		if (restart & PORT_FORCE_MDIX)
+			data |= PHY_FORCE_MDIX;
+		if (restart & PORT_AUTO_MDIX_DISABLE)
+			data |= PHY_AUTO_MDIX_DISABLE;
+		if (restart & PORT_TX_DISABLE)
+			data |= PHY_TRANSMIT_DISABLE;
+		if (restart & PORT_LED_OFF)
+			data |= PHY_LED_DISABLE;
+		break;
+	case PHY_REG_STATUS:
+		ksz_pread8(sw, p, P_LINK_STATUS, &link);
+		ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
+		data = PHY_100BTX_FD_CAPABLE |
+			PHY_100BTX_CAPABLE |
+			PHY_10BT_FD_CAPABLE |
+			PHY_10BT_CAPABLE |
+			PHY_AUTO_NEG_CAPABLE;
+		if (link & PORT_AUTO_NEG_COMPLETE)
+			data |= PHY_AUTO_NEG_ACKNOWLEDGE;
+		if (link & PORT_STAT_LINK_GOOD)
+			data |= PHY_LINK_STATUS;
+		break;
+	case PHY_REG_ID_1:
+		data = KSZ8895_ID_HI;
+		break;
+	case PHY_REG_ID_2:
+		data = KSZ8895_ID_LO;
+		break;
+	case PHY_REG_AUTO_NEGOTIATION:
+		ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
+		data = PHY_AUTO_NEG_802_3;
+		if (ctrl & PORT_AUTO_NEG_SYM_PAUSE)
+			data |= PHY_AUTO_NEG_SYM_PAUSE;
+		if (ctrl & PORT_AUTO_NEG_100BTX_FD)
+			data |= PHY_AUTO_NEG_100BTX_FD;
+		if (ctrl & PORT_AUTO_NEG_100BTX)
+			data |= PHY_AUTO_NEG_100BTX;
+		if (ctrl & PORT_AUTO_NEG_10BT_FD)
+			data |= PHY_AUTO_NEG_10BT_FD;
+		if (ctrl & PORT_AUTO_NEG_10BT)
+			data |= PHY_AUTO_NEG_10BT;
+		break;
+	case PHY_REG_REMOTE_CAPABILITY:
+		ksz_pread8(sw, p, P_REMOTE_STATUS, &link);
+		data = PHY_AUTO_NEG_802_3;
+		if (link & PORT_REMOTE_SYM_PAUSE)
+			data |= PHY_AUTO_NEG_SYM_PAUSE;
+		if (link & PORT_REMOTE_100BTX_FD)
+			data |= PHY_AUTO_NEG_100BTX_FD;
+		if (link & PORT_REMOTE_100BTX)
+			data |= PHY_AUTO_NEG_100BTX;
+		if (link & PORT_REMOTE_10BT_FD)
+			data |= PHY_AUTO_NEG_10BT_FD;
+		if (link & PORT_REMOTE_10BT)
+			data |= PHY_AUTO_NEG_10BT;
+		break;
+	default:
+		break;
+	}
+	*val = data;
+}  /* sw_r_phy */
+
+/**
+ * sw_w_phy - write data to PHY register
+ * @hw:		The switch instance.
+ * @phy:	PHY address to write.
+ * @reg:	PHY register to write.
+ * @val:	Word data to write.
+ *
+ * This routine writes data to the PHY register.
+ */
+static void sw_w_phy(struct ksz_device *sw, u16 phy, u16 reg, u16 val)
+{
+	u8 ctrl;
+	u8 restart;
+	u8 speed;
+	u8 data;
+	u8 p = phy;
+
+	switch (reg) {
+	case PHY_REG_CTRL:
+		ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
+		data = speed;
+		if (val & PHY_HP_MDIX)
+			data |= PORT_HP_MDIX;
+		else
+			data &= ~PORT_HP_MDIX;
+		if (data != speed)
+			ksz_pwrite8(sw, p, P_SPEED_STATUS, data);
+		ksz_pread8(sw, p, P_FORCE_CTRL, &ctrl);
+		data = ctrl;
+		if (!(val & PHY_AUTO_NEG_ENABLE))
+			data |= PORT_AUTO_NEG_DISABLE;
+		else
+			data &= ~PORT_AUTO_NEG_DISABLE;
+		if (val & PHY_SPEED_100MBIT)
+			data |= PORT_FORCE_100_MBIT;
+		else
+			data &= ~PORT_FORCE_100_MBIT;
+		if (val & PHY_FULL_DUPLEX)
+			data |= PORT_FORCE_FULL_DUPLEX;
+		else
+			data &= ~PORT_FORCE_FULL_DUPLEX;
+		if (data != ctrl)
+			ksz_pwrite8(sw, p, P_FORCE_CTRL, data);
+		ksz_pread8(sw, p, P_NEG_RESTART_CTRL, &restart);
+		data = restart;
+		if (val & PHY_LED_DISABLE)
+			data |= PORT_LED_OFF;
+		else
+			data &= ~PORT_LED_OFF;
+		if (val & PHY_TRANSMIT_DISABLE)
+			data |= PORT_TX_DISABLE;
+		else
+			data &= ~PORT_TX_DISABLE;
+		if (val & PHY_AUTO_NEG_RESTART)
+			data |= PORT_AUTO_NEG_RESTART;
+		else
+			data &= ~(PORT_AUTO_NEG_RESTART);
+		if (val & PHY_POWER_DOWN)
+			data |= PORT_POWER_DOWN;
+		else
+			data &= ~PORT_POWER_DOWN;
+		if (val & PHY_AUTO_MDIX_DISABLE)
+			data |= PORT_AUTO_MDIX_DISABLE;
+		else
+			data &= ~PORT_AUTO_MDIX_DISABLE;
+		if (val & PHY_FORCE_MDIX)
+			data |= PORT_FORCE_MDIX;
+		else
+			data &= ~PORT_FORCE_MDIX;
+		if (val & PHY_LOOPBACK)
+			data |= PORT_PHY_LOOPBACK;
+		else
+			data &= ~PORT_PHY_LOOPBACK;
+		if (data != restart)
+			ksz_pwrite8(sw, p, P_NEG_RESTART_CTRL, data);
+		break;
+	case PHY_REG_AUTO_NEGOTIATION:
+		ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
+		data = ctrl;
+		data &= ~(PORT_AUTO_NEG_SYM_PAUSE |
+			PORT_AUTO_NEG_100BTX_FD |
+			PORT_AUTO_NEG_100BTX |
+			PORT_AUTO_NEG_10BT_FD |
+			PORT_AUTO_NEG_10BT);
+		if (val & PHY_AUTO_NEG_SYM_PAUSE)
+			data |= PORT_AUTO_NEG_SYM_PAUSE;
+		if (val & PHY_AUTO_NEG_100BTX_FD)
+			data |= PORT_AUTO_NEG_100BTX_FD;
+		if (val & PHY_AUTO_NEG_100BTX)
+			data |= PORT_AUTO_NEG_100BTX;
+		if (val & PHY_AUTO_NEG_10BT_FD)
+			data |= PORT_AUTO_NEG_10BT_FD;
+		if (val & PHY_AUTO_NEG_10BT)
+			data |= PORT_AUTO_NEG_10BT;
+		if (data != ctrl)
+			ksz_pwrite8(sw, p, P_LOCAL_CTRL, data);
+		break;
+	default:
+		break;
+	}
+}  /* sw_w_phy */
+
+static int ksz_mii_addr(int *reg, int *bank)
+{
+	int ret;
+
+	ret = (*reg & 0xC000) >> ADDR_SHIFT;
+	*bank = (*reg & 0x3000) >> BANK_SHIFT;
+	*reg &= 0x0FFF;
+	return ret;
+}
+
+static int ksz_phy_read16(struct dsa_switch *ds, int phy_id, int regnum)
+{
+	struct ksz_device *sw = ds->priv;
+	int addr;
+	int bank;
+	u16 data;
+	int ret = 0xffff;
+
+	if (phy_id > SWITCH_PORT_NUM + 1)
+		return 0xffff;
+
+	addr = ksz_mii_addr(&regnum, &bank);
+	BUG_ON(addr >= 6);
+
+	switch (addr) {
+	case ADDR_8:
+	case ADDR_16:
+	case ADDR_32:
+		BUG();
+
+	default:
+		if (regnum < 6) {
+			sw_r_phy(sw, phy_id, regnum, &data);
+			ret = data;
+		} else
+			ret = 0;
+	}
+
+	return ret;
+}  /* ksz_mii_read */
+
+static int ksz_phy_write16(struct dsa_switch *ds, int phy_id, int regnum, u16 val)
+{
+	struct ksz_device *sw = ds->priv;
+	int addr;
+	int bank;
+	int reg;
+
+	if (phy_id > SWITCH_PORT_NUM + 1)
+		return -EINVAL;
+
+	BUG_ON(regnum >= 6);
+	reg = regnum;
+	addr = ksz_mii_addr(&regnum, &bank);
+
+	switch (addr) {
+	case ADDR_8:
+	case ADDR_16:
+	case ADDR_32:
+		BUG();
+	default:
+		if (regnum < 6) {
+			/* PHY device driver resets or powers down the PHY. */
+			if (0 == regnum &&
+			    (val & (PHY_RESET | PHY_POWER_DOWN)))
+				break;
+			sw_w_phy(sw, phy_id, regnum, val);
+		}
+		break;
+	}
+
+	return 0;
+}  /* ksz_mii_write */
diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h
index 2a98dbd51456..1c73cdb8bbca 100644
--- a/drivers/net/dsa/microchip/ksz_priv.h
+++ b/drivers/net/dsa/microchip/ksz_priv.h
@@ -25,8 +25,6 @@
 #include <linux/etherdevice.h>
 #include <net/dsa.h>
 
-#include "ksz_9477_reg.h"
-
 struct ksz_io_ops;
 
 struct vlan_table {
@@ -60,6 +58,8 @@ struct ksz_device {
 	struct vlan_table *vlan_cache;
 
 	u64 mib_value[TOTAL_SWITCH_COUNTER_NUM];
+	
+	struct bin_attribute regs_attr;
 };
 
 struct ksz_io_ops {
@@ -174,6 +174,7 @@ static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value)
 static inline void ksz_pread8(struct ksz_device *dev, int port, int offset,
 			      u8 *data)
 {
+	//printk("pread8 %d %d -> %d\n", port, offset, PORT_CTRL_ADDR(port, offset));
 	ksz_read8(dev, PORT_CTRL_ADDR(port, offset), data);
 }
 
diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c
index c51946983bed..22ee313052dc 100644
--- a/drivers/net/dsa/microchip/ksz_spi.c
+++ b/drivers/net/dsa/microchip/ksz_spi.c
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/spi/spi.h>
 
+#include "ksz_9477_reg.h"
 #include "ksz_priv.h"
 
 /* SPI frame opcodes */
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index de66ca8e6201..6eb094d5bb02 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -29,7 +29,7 @@
  *	  (eg, 0x00=port1, 0x02=port3, 0x06=port7)
  */
 
-#define	KSZ_INGRESS_TAG_LEN	2
+#define	KSZ_INGRESS_TAG_LEN	1
 #define	KSZ_EGRESS_TAG_LEN	1
 
 static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -69,8 +69,7 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	tag = skb_put(nskb, KSZ_INGRESS_TAG_LEN);
-	tag[0] = 0;
-	tag[1] = 1 << p->dp->index; /* destination port */
+	tag[0] = 1 << p->dp->index; /* destination port */
 
 	return nskb;
 }

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-27 12:36     ` [PATCH] " Pavel Machek
@ 2017-08-27 13:59       ` Andrew Lunn
  2017-08-27 16:31       ` Andrew Lunn
                         ` (4 subsequent siblings)
  5 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2017-08-27 13:59 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Tristram.Ha

On Sun, Aug 27, 2017 at 02:36:58PM +0200, Pavel Machek wrote:
> Hi!
> 
> So I fought with the driver a bit more, and now I have something that
> kind-of-works.


Thanks for keeping on working on this.
 
> "great great hack" belows worries me.
> 
> Yeah, disabled code needs to be removed before merge.
> 
> No, tag_ksz part probably is not acceptable. Do you see solution
> better than just copying it into tag_ksz1 file?
> 
> Any more comments, etc?

It would help with review if you split this up into multiple patches.
The change to the tagger should be one patch. The mdio emulation would
make a reasonable standalone patch etc.

I will do a more detailed review later.

  Andrew

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-27 12:36     ` [PATCH] " Pavel Machek
  2017-08-27 13:59       ` Andrew Lunn
@ 2017-08-27 16:31       ` Andrew Lunn
  2017-08-28  7:02         ` Pavel Machek
  2017-08-27 16:44       ` Andrew Lunn
                         ` (3 subsequent siblings)
  5 siblings, 1 reply; 35+ messages in thread
From: Andrew Lunn @ 2017-08-27 16:31 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Tristram.Ha

> +/**
> + * sw_r_phy - read data from PHY register
> + * @sw:		The switch instance.
> + * @phy:	PHY address to read.
> + * @reg:	PHY register to read.
> + * @val:	Buffer to store the read data.
> + *
> + * This routine reads data from the PHY register.
> + */
> +static void sw_r_phy(struct ksz_device *sw, u16 phy, u16 reg, u16 *val)
> +{
> +	u8 ctrl;
> +	u8 restart;
> +	u8 link;
> +	u8 speed;
> +	u8 force;
> +	u8 p = phy;
> +	u16 data = 0;
> +
> +	switch (reg) {
> +	case PHY_REG_CTRL:
> +		ksz_pread8(sw, p, P_LOCAL_CTRL, &ctrl);
> +		ksz_pread8(sw, p, P_NEG_RESTART_CTRL, &restart);
> +		ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
> +		ksz_pread8(sw, p, P_FORCE_CTRL, &force);
> +		if (restart & PORT_PHY_LOOPBACK)
> +			data |= PHY_LOOPBACK;
> +		if (force & PORT_FORCE_100_MBIT)
> +			data |= PHY_SPEED_100MBIT;
> +		if (!(force & PORT_AUTO_NEG_DISABLE))
> +			data |= PHY_AUTO_NEG_ENABLE;
> +		if (restart & PORT_POWER_DOWN)
> +			data |= PHY_POWER_DOWN;
> +		if (restart & PORT_AUTO_NEG_RESTART)
> +			data |= PHY_AUTO_NEG_RESTART;
> +		if (force & PORT_FORCE_FULL_DUPLEX)
> +			data |= PHY_FULL_DUPLEX;
> +		if (speed & PORT_HP_MDIX)
> +			data |= PHY_HP_MDIX;
> +		if (restart & PORT_FORCE_MDIX)
> +			data |= PHY_FORCE_MDIX;
> +		if (restart & PORT_AUTO_MDIX_DISABLE)
> +			data |= PHY_AUTO_MDIX_DISABLE;
> +		if (restart & PORT_TX_DISABLE)
> +			data |= PHY_TRANSMIT_DISABLE;
> +		if (restart & PORT_LED_OFF)
> +			data |= PHY_LED_DISABLE;
> +		break;
> +	case PHY_REG_STATUS:
> +		ksz_pread8(sw, p, P_LINK_STATUS, &link);
> +		ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
> +		data = PHY_100BTX_FD_CAPABLE |
> +			PHY_100BTX_CAPABLE |
> +			PHY_10BT_FD_CAPABLE |
> +			PHY_10BT_CAPABLE |
> +			PHY_AUTO_NEG_CAPABLE;
> +		if (link & PORT_AUTO_NEG_COMPLETE)
> +			data |= PHY_AUTO_NEG_ACKNOWLEDGE;
> +		if (link & PORT_STAT_LINK_GOOD)
> +			data |= PHY_LINK_STATUS;
> +		break;
> +	case PHY_REG_ID_1:
> +		data = KSZ8895_ID_HI;
> +		break;
> +	case PHY_REG_ID_2:
> +		data = KSZ8895_ID_LO;
> +		break;

According to the datasheet, the PHY has the normal ID registers,
which have the value 0x0022, 0x1450. So it should be possible to have
a standard PHY driver in drivers/net/phy.

In fact, the IDs suggest it is a micrel phy, and 1430, 1435 are
already supported. So it could be you only need minor modifications to
the micrel.c.

    Andrew

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-27 12:36     ` [PATCH] " Pavel Machek
  2017-08-27 13:59       ` Andrew Lunn
  2017-08-27 16:31       ` Andrew Lunn
@ 2017-08-27 16:44       ` Andrew Lunn
  2017-08-28  6:40         ` Pavel Machek
  2017-08-27 16:56       ` Florian Fainelli
                         ` (2 subsequent siblings)
  5 siblings, 1 reply; 35+ messages in thread
From: Andrew Lunn @ 2017-08-27 16:44 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Tristram.Ha

> No, tag_ksz part probably is not acceptable. Do you see solution
> better than just copying it into tag_ksz1 file?

How about something like this, which needs further work to actually
compile, but should give you the idea.

	 Andrew

index 99e38af85fc5..843e77b7c270 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -49,8 +49,11 @@ const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = {
 #ifdef CONFIG_NET_DSA_TAG_EDSA
        [DSA_TAG_PROTO_EDSA] = &edsa_netdev_ops,
 #endif
-#ifdef CONFIG_NET_DSA_TAG_KSZ
-       [DSA_TAG_PROTO_KSZ] = &ksz_netdev_ops,
+#ifdef CONFIG_NET_DSA_TAG_KSZ_8K
+       [DSA_TAG_PROTO_KSZ8K] = &ksz8k_netdev_ops,
+#endif
+#ifdef CONFIG_NET_DSA_TAG_KSZ_9K
+       [DSA_TAG_PROTO_KSZ9K] = &ksz9k_netdev_ops,
 #endif
 #ifdef CONFIG_NET_DSA_TAG_LAN9303
        [DSA_TAG_PROTO_LAN9303] = &lan9303_netdev_ops,
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index de66ca8e6201..398b833889f1 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -35,6 +35,9 @@
 static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_port *dp = p->dp;
+       struct dsa_switch *ds = dp->ds;
+       struct dsa_switch_tree *dst = ds->dst;
        struct sk_buff *nskb;
        int padlen;
        u8 *tag;
@@ -69,8 +72,14 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        tag = skb_put(nskb, KSZ_INGRESS_TAG_LEN);
-       tag[0] = 0;
-       tag[1] = 1 << p->dp->index; /* destination port */
+       if (dst->tag_ops == ksz8k_netdev_ops) {
+               tag[0] = 1 << p->dp->index; /* destination port */0;
+               tag[1] = 0;
+       }
+
+       if (dst->tag_ops == ksz9k_netdev_ops) {
+               tag[0] = 0;
+               tag[1] = 1 << p->dp->index; /* destination port */
 
        return nskb;
 }
@@ -98,7 +107,12 @@ static struct sk_buff *ksz_rcv(struct sk_buff *skb, struct net_device *dev,
        return skb;
 }
 
-const struct dsa_device_ops ksz_netdev_ops = {
+const struct dsa_device_ops ksz8k_netdev_ops = {
+       .xmit   = ksz_xmit,
+       .rcv    = ksz_rcv,
+};
+
+const struct dsa_device_ops ksz9k_netdev_ops = {
        .xmit   = ksz_xmit,
        .rcv    = ksz_rcv,
 };

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-27 12:36     ` [PATCH] " Pavel Machek
                         ` (2 preceding siblings ...)
  2017-08-27 16:44       ` Andrew Lunn
@ 2017-08-27 16:56       ` Florian Fainelli
  2017-08-28  6:47         ` Pavel Machek
  2017-08-27 22:03       ` Woojung.Huh
  2017-08-29 15:33       ` kbuild test robot
  5 siblings, 1 reply; 35+ messages in thread
From: Florian Fainelli @ 2017-08-27 16:56 UTC (permalink / raw)
  To: Pavel Machek, Woojung.Huh, nathan.leigh.conrad
  Cc: vivien.didelot, netdev, linux-kernel, Tristram.Ha, andrew, pavel

On August 27, 2017 5:36:58 AM PDT, Pavel Machek <pavel@denx.de> wrote:
>Hi!
>
>So I fought with the driver a bit more, and now I have something that
>kind-of-works.
>
>"great great hack" belows worries me.
>
>Yeah, disabled code needs to be removed before merge.
>
>No, tag_ksz part probably is not acceptable. Do you see solution
>better than just copying it into tag_ksz1 file?

You could have all Micrel tag implementations live under net/dsa/tag_ksz.c and have e.g: DSA_TAG_PROTO_KSZ for the current (newer) switches and DSA_TAG_PROTO_KSZ_LEGACY (or any other name) for the older switches and you would provide two sets of function pointers depending on which protocol is requested by the switch.

Considering the minor difference needed in tagging here, it might be acceptable to actually keep the current functions and just have the xmit() call check what get_tag_protocol returns and use word 1 or 0 based on that. Even though that's a fast path it shouldn't hurt performance too much. If it does, we can always copy the tagging protocol into dsa_slave_priv so you have a fast access to it.

>
>Any more comments, etc?

The MII emulation bits are interesting, was it not sufficient if you implemented phy_read and phy_write operations that perform the necessary internal PHY accesses or maybe you don't get access to standard MII registers? b53 does such a thing and we merely just need to do a simple shift to access the MII register number, thus avoiding the translation.

>
>Help would be welcome.

I concur with Andrew, try to get a patch series, even an RFC one together so we can review things individually. 

How functional is your driver so far? I'd say the basic stuff to get working: counters (debugging), link management (auto-negotiation, forced, etc.) and basic bridging: all ports separate by default and working port to port switching when brought together in a bridge. VLAN, FDB, MDB, other ethtool goodies can be added later on.

-- 
Florian

^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: [PATCH] DSA support for Micrel KSZ8895
  2017-08-27 12:36     ` [PATCH] " Pavel Machek
                         ` (3 preceding siblings ...)
  2017-08-27 16:56       ` Florian Fainelli
@ 2017-08-27 22:03       ` Woojung.Huh
  2017-08-29 15:33       ` kbuild test robot
  5 siblings, 0 replies; 35+ messages in thread
From: Woojung.Huh @ 2017-08-27 22:03 UTC (permalink / raw)
  To: pavel, nathan.leigh.conrad
  Cc: vivien.didelot, f.fainelli, netdev, linux-kernel, Tristram.Ha, andrew

Pavel,

Thanks for update and sorry about email format (due to web-access version)
I'll do review when getting back to office later this week.

- Woojung
________________________________________
From: Pavel Machek [pavel@denx.de]
Sent: Sunday, August 27, 2017 8:36 AM
To: Woojung Huh - C21699; nathan.leigh.conrad@gmail.com
Cc: vivien.didelot@savoirfairelinux.com; f.fainelli@gmail.com; netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Tristram.Ha@micrel.com; andrew@lunn.ch; pavel@denx.de
Subject: [PATCH] DSA support for Micrel KSZ8895

Hi!

So I fought with the driver a bit more, and now I have something that
kind-of-works.

"great great hack" belows worries me.

Yeah, disabled code needs to be removed before merge.

No, tag_ksz part probably is not acceptable. Do you see solution
better than just copying it into tag_ksz1 file?

Any more comments, etc?

Help would be welcome.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-27 16:44       ` Andrew Lunn
@ 2017-08-28  6:40         ` Pavel Machek
  0 siblings, 0 replies; 35+ messages in thread
From: Pavel Machek @ 2017-08-28  6:40 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Tristram.Ha

[-- Attachment #1: Type: text/plain, Size: 2959 bytes --]

Hi!

> > No, tag_ksz part probably is not acceptable. Do you see solution
> > better than just copying it into tag_ksz1 file?
> 
> How about something like this, which needs further work to actually
> compile, but should give you the idea.

If that's acceptable, yes, I can do something similar. I don't think
CONFIG_NET_DSA_TAG_KSZ_8K / CONFIG_NET_DSA_TAG_KSZ_9K is suitable
naming (these will probably differ according to number of ports), what
about keeping CONFIG_NET_DSA_TAG_KSZ and adding
CONFIG_NET_DSA_TAG_KSZ_1B (for one byte)?

Thanks,
								Pavel

> 	 Andrew
> 
> index 99e38af85fc5..843e77b7c270 100644
> --- a/net/dsa/dsa.c
> +++ b/net/dsa/dsa.c
> @@ -49,8 +49,11 @@ const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = {
>  #ifdef CONFIG_NET_DSA_TAG_EDSA
>         [DSA_TAG_PROTO_EDSA] = &edsa_netdev_ops,
>  #endif
> -#ifdef CONFIG_NET_DSA_TAG_KSZ
> -       [DSA_TAG_PROTO_KSZ] = &ksz_netdev_ops,
> +#ifdef CONFIG_NET_DSA_TAG_KSZ_8K
> +       [DSA_TAG_PROTO_KSZ8K] = &ksz8k_netdev_ops,
> +#endif
> +#ifdef CONFIG_NET_DSA_TAG_KSZ_9K
> +       [DSA_TAG_PROTO_KSZ9K] = &ksz9k_netdev_ops,
>  #endif
>  #ifdef CONFIG_NET_DSA_TAG_LAN9303
>         [DSA_TAG_PROTO_LAN9303] = &lan9303_netdev_ops,
> diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
> index de66ca8e6201..398b833889f1 100644
> --- a/net/dsa/tag_ksz.c
> +++ b/net/dsa/tag_ksz.c
> @@ -35,6 +35,9 @@
>  static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
>  {
>         struct dsa_slave_priv *p = netdev_priv(dev);
> +       struct dsa_port *dp = p->dp;
> +       struct dsa_switch *ds = dp->ds;
> +       struct dsa_switch_tree *dst = ds->dst;
>         struct sk_buff *nskb;
>         int padlen;
>         u8 *tag;
> @@ -69,8 +72,14 @@ static struct sk_buff *ksz_xmit(struct sk_buff *skb, struct net_device *dev)
>         }
>  
>         tag = skb_put(nskb, KSZ_INGRESS_TAG_LEN);
> -       tag[0] = 0;
> -       tag[1] = 1 << p->dp->index; /* destination port */
> +       if (dst->tag_ops == ksz8k_netdev_ops) {
> +               tag[0] = 1 << p->dp->index; /* destination port */0;
> +               tag[1] = 0;
> +       }
> +
> +       if (dst->tag_ops == ksz9k_netdev_ops) {
> +               tag[0] = 0;
> +               tag[1] = 1 << p->dp->index; /* destination port */
>  
>         return nskb;
>  }
> @@ -98,7 +107,12 @@ static struct sk_buff *ksz_rcv(struct sk_buff *skb, struct net_device *dev,
>         return skb;
>  }
>  
> -const struct dsa_device_ops ksz_netdev_ops = {
> +const struct dsa_device_ops ksz8k_netdev_ops = {
> +       .xmit   = ksz_xmit,
> +       .rcv    = ksz_rcv,
> +};
> +
> +const struct dsa_device_ops ksz9k_netdev_ops = {
>         .xmit   = ksz_xmit,
>         .rcv    = ksz_rcv,
>  };

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-27 16:56       ` Florian Fainelli
@ 2017-08-28  6:47         ` Pavel Machek
  0 siblings, 0 replies; 35+ messages in thread
From: Pavel Machek @ 2017-08-28  6:47 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, netdev,
	linux-kernel, Tristram.Ha, andrew

[-- Attachment #1: Type: text/plain, Size: 2207 bytes --]

Hi!

> >No, tag_ksz part probably is not acceptable. Do you see solution
> >better than just copying it into tag_ksz1 file?
> 
> You could have all Micrel tag implementations live under net/dsa/tag_ksz.c and have e.g: DSA_TAG_PROTO_KSZ for the current (newer) switches and DSA_TAG_PROTO_KSZ_LEGACY (or any other name) for the older switches and you would provide two sets of function pointers depending on which protocol is requested by the switch.
> 
> Considering the minor difference needed in tagging here, it might be acceptable to actually keep the current functions and just have the xmit() call check what get_tag_protocol returns and use word 1 or 0 based on that. Even though that's a fast path it shouldn't hurt performance too much. If it does, we can always copy the tagging protocol into dsa_slave_priv so you have a fast access to it.
> 

Actually I believe I can do optimizer tricks to keep this zero-cost
with clean code, if needed.

> >
> >Any more comments, etc?
> 
> The MII emulation bits are interesting, was it not sufficient if you implemented phy_read and phy_write operations that perform the necessary internal PHY accesses or maybe you don't get access to standard MII registers? b53 does such a thing and we merely just need to do a simple shift to access the MII register number, thus avoiding the translation.
> 

We don't get standard MII registers over SPI bus.

> >Help would be welcome.
> 
> I concur with Andrew, try to get a patch series, even an RFC one together so we can review things individually. 
> 
> How functional is your driver so far? I'd say the basic stuff to get working: counters (debugging), link management (auto-negotiation, forced, etc.) and basic bridging: all ports separate by default and working port to port switching when brought together in a bridge. VLAN, FDB, MDB, other ethtool goodies can be added later on.
>

Which counters are essential? Link management and basic bridging
should work, not sure if I'll have time to do more than that.

Best regards,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-27 16:31       ` Andrew Lunn
@ 2017-08-28  7:02         ` Pavel Machek
  2017-08-28 14:09           ` Andrew Lunn
  0 siblings, 1 reply; 35+ messages in thread
From: Pavel Machek @ 2017-08-28  7:02 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Tristram.Ha

[-- Attachment #1: Type: text/plain, Size: 1784 bytes --]

Hi!

Thanks for review.

> > +	case PHY_REG_STATUS:
> > +		ksz_pread8(sw, p, P_LINK_STATUS, &link);
> > +		ksz_pread8(sw, p, P_SPEED_STATUS, &speed);
> > +		data = PHY_100BTX_FD_CAPABLE |
> > +			PHY_100BTX_CAPABLE |
> > +			PHY_10BT_FD_CAPABLE |
> > +			PHY_10BT_CAPABLE |
> > +			PHY_AUTO_NEG_CAPABLE;
> > +		if (link & PORT_AUTO_NEG_COMPLETE)
> > +			data |= PHY_AUTO_NEG_ACKNOWLEDGE;
> > +		if (link & PORT_STAT_LINK_GOOD)
> > +			data |= PHY_LINK_STATUS;
> > +		break;
> > +	case PHY_REG_ID_1:
> > +		data = KSZ8895_ID_HI;
> > +		break;
> > +	case PHY_REG_ID_2:
> > +		data = KSZ8895_ID_LO;
> > +		break;
> 
> According to the datasheet, the PHY has the normal ID registers,
> which have the value 0x0022, 0x1450. So it should be possible to have
> a standard PHY driver in drivers/net/phy.
> 
> In fact, the IDs suggest it is a micrel phy, and 1430, 1435 are
> already supported. So it could be you only need minor modifications to
> the micrel.c.

I may be confused here, but AFAICT:

1) Yes, it has standard layout when accessed over MDIO. But then
there's no access to the bridging functionality, and MDIO access may
not be available. [I was told not to use it for this design, so I did
not].

2) drivers/net/phy/spi_ks8995.c can be trivially modified to work with
this chip.. but then you don't get the bridge functionality. (And I'm
not sure how it works / who translates layouts in this case.)

I'd like to get rid of this code, or use some existing code instead,
but I don't think it is possible while keeping the SPI accesss. Let me
know if I'm wrong.

Best regards,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: DSA support for Micrel KSZ8895
  2017-08-23 21:48       ` Woojung.Huh
@ 2017-08-28 10:14         ` Pavel Machek
  2017-08-28 13:19           ` Andrew Lunn
  0 siblings, 1 reply; 35+ messages in thread
From: Pavel Machek @ 2017-08-28 10:14 UTC (permalink / raw)
  To: Woojung.Huh
  Cc: nathan.leigh.conrad, vivien.didelot, f.fainelli, netdev,
	linux-kernel, Tristram.Ha, andrew

[-- Attachment #1: Type: text/plain, Size: 832 bytes --]

Hi!

> > > I'll forward your email to our support.
> > > AFAIK, KSZ8895 has different register mapping from KSZ9477,
> > > it will be more than ID changes in current driver.
> > 
> > More than ID changes, indeed. As layout is completely different, it
> > looks like different source file will be needed for support.
> > 
> > I'm not nearly there; but I can ifconfig lanX up, already, and perform
> > some pings.
> > 
> > Any ideas how to do the work in a way to minimize code duplication are
> > welcome...
> 
> Which version do you use to create patch?
> Getting error when applying patch to the latest net-next.

I'm working at 4.13-rc.

Best regards,
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: DSA support for Micrel KSZ8895
  2017-08-28 10:14         ` Pavel Machek
@ 2017-08-28 13:19           ` Andrew Lunn
  0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2017-08-28 13:19 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Tristram.Ha

> I'm working at 4.13-rc.

For network code, it is a good idea to use net-next. That is what you
need to target in order to get patches with new features merged.

     Andrew

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-28  7:02         ` Pavel Machek
@ 2017-08-28 14:09           ` Andrew Lunn
  2017-08-28 14:47             ` Maxim Uvarov
  2017-08-29  7:45             ` Pavel Machek
  0 siblings, 2 replies; 35+ messages in thread
From: Andrew Lunn @ 2017-08-28 14:09 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Tristram.Ha

> I may be confused here, but AFAICT:
> 
> 1) Yes, it has standard layout when accessed over MDIO. 


Section 4.8 of the datasheet says:

	All the registers defined in this section can be also accessed
	via the SPI interface.

Meaning all PHY registers can be access via the SPI interface. So you
should be able to make a standard Linux MDIO bus driver which performs
SPI reads.

    Andrew

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-28 14:09           ` Andrew Lunn
@ 2017-08-28 14:47             ` Maxim Uvarov
  2017-08-29  7:41               ` Pavel Machek
  2017-08-29  7:45             ` Pavel Machek
  1 sibling, 1 reply; 35+ messages in thread
From: Maxim Uvarov @ 2017-08-28 14:47 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Pavel Machek, Woojung.Huh, nathan.leigh.conrad, Vivien Didelot,
	Florian Fainelli, netdev, linux-kernel, Tristram.Ha

Micrel has some drivers on their web site to support some chips. For
that chips they do virtual mdio over spi.
And driver is available on download page:
http://www.microchip.com/wwwproducts/en/KSZ8895

Documentation->Software library.

Both driver and DSA driver. Driver has to work with some minor fixups
related to your kernel version. But I think they are don't care about
up-streaming that code.
So you can take their code as a reference.

2017-08-28 17:09 GMT+03:00 Andrew Lunn <andrew@lunn.ch>:
>> I may be confused here, but AFAICT:
>>
>> 1) Yes, it has standard layout when accessed over MDIO.
>
>
> Section 4.8 of the datasheet says:
>
>         All the registers defined in this section can be also accessed
>         via the SPI interface.
>
> Meaning all PHY registers can be access via the SPI interface. So you
> should be able to make a standard Linux MDIO bus driver which performs
> SPI reads.
>
>     Andrew

Micrel has some drivers on their web site to support some chips. For
that chips they do virtual mdio over spi.
And driver is available on download page:
http://www.microchip.com/wwwproducts/en/KSZ8895

Documentation->Software library.

Both driver and DSA driver. Driver has to work with some minor fixups
related to your kernel version. But I think they are don't care about
up-streaming that code.
So you can take their code as a reference.

-- 
Best regards,
Maxim Uvarov

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-28 14:47             ` Maxim Uvarov
@ 2017-08-29  7:41               ` Pavel Machek
  2017-08-29 12:26                 ` Andrew Lunn
  0 siblings, 1 reply; 35+ messages in thread
From: Pavel Machek @ 2017-08-29  7:41 UTC (permalink / raw)
  To: Maxim Uvarov
  Cc: Andrew Lunn, Woojung.Huh, nathan.leigh.conrad, Vivien Didelot,
	Florian Fainelli, netdev, linux-kernel, Tristram.Ha

[-- Attachment #1: Type: text/plain, Size: 861 bytes --]

Hi!

> Micrel has some drivers on their web site to support some chips. For
> that chips they do virtual mdio over spi.
> And driver is available on download page:
> http://www.microchip.com/wwwproducts/en/KSZ8895
> 
> Documentation->Software library.
> 
> Both driver and DSA driver. Driver has to work with some minor fixups
> related to your kernel version. But I think they are don't care about
> up-streaming that code.
> So you can take their code as a reference.

"Minor fixups". Take a look at the driver.. I wanted to do a "minor
fixups". It turned out it was easier to start from scratch.

But the MDIO emaulation code is from their driver, after lots of
deletions.

								Pavel
								
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-28 14:09           ` Andrew Lunn
  2017-08-28 14:47             ` Maxim Uvarov
@ 2017-08-29  7:45             ` Pavel Machek
  2017-08-30 21:32               ` Tristram.Ha
  1 sibling, 1 reply; 35+ messages in thread
From: Pavel Machek @ 2017-08-29  7:45 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, Tristram.Ha

[-- Attachment #1: Type: text/plain, Size: 909 bytes --]

On Mon 2017-08-28 16:09:27, Andrew Lunn wrote:
> > I may be confused here, but AFAICT:
> > 
> > 1) Yes, it has standard layout when accessed over MDIO. 
> 
> 
> Section 4.8 of the datasheet says:
> 
> 	All the registers defined in this section can be also accessed
> 	via the SPI interface.
> 
> Meaning all PHY registers can be access via the SPI interface. So you
> should be able to make a standard Linux MDIO bus driver which performs
> SPI reads.

As far as I can tell (and their driver confirms) -- yes, all those
registers can be accessed over the SPI, they are just shuffled
around... hence MDIO emulation code. I copied it from their code (see
the copyrights) so no, I don't believe there's nicer solution.

Best regards,

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-29  7:41               ` Pavel Machek
@ 2017-08-29 12:26                 ` Andrew Lunn
  2017-08-29 21:15                   ` Pavel Machek
  0 siblings, 1 reply; 35+ messages in thread
From: Andrew Lunn @ 2017-08-29 12:26 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Maxim Uvarov, Woojung.Huh, nathan.leigh.conrad, Vivien Didelot,
	Florian Fainelli, netdev, linux-kernel, Tristram.Ha

> But the MDIO emaulation code is from their driver, after lots of
> deletions.

Is this driver supposed to run on lots of different OSs? That would
explain why they ignored the Linux MDIO and PHY layers.

If possible, please make use of the Linux infrastructure.

   Andrew

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-27 12:36     ` [PATCH] " Pavel Machek
                         ` (4 preceding siblings ...)
  2017-08-27 22:03       ` Woojung.Huh
@ 2017-08-29 15:33       ` kbuild test robot
  5 siblings, 0 replies; 35+ messages in thread
From: kbuild test robot @ 2017-08-29 15:33 UTC (permalink / raw)
  To: Pavel Machek
  Cc: kbuild-all, Woojung.Huh, nathan.leigh.conrad, vivien.didelot,
	f.fainelli, netdev, linux-kernel, Tristram.Ha, andrew, pavel

[-- Attachment #1: Type: text/plain, Size: 4778 bytes --]

Hi Pavel,

[auto build test ERROR on net-next/master]
[also build test ERROR on v4.13-rc7 next-20170829]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Pavel-Machek/DSA-support-for-Micrel-KSZ8895/20170829-220156
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All error/warnings (new ones prefixed by >>):

   In file included from drivers/net/dsa/microchip/ksz_common.c:31:0:
>> drivers/net/dsa/microchip/ksz_9477_reg.h:19:2: error: #error This is not switch we have
    #error This is not switch we have
     ^
--
   drivers/net/dsa/microchip/ksz_8895.c: In function 'ksz_reset_switch':
   drivers/net/dsa/microchip/ksz_8895.c:109:21: warning: unused variable 'dev' [-Wunused-variable]
     struct ksz_device *dev = ds->priv;
                        ^
   drivers/net/dsa/microchip/ksz_8895.c: In function 'ksz_br_join':
   drivers/net/dsa/microchip/ksz_8895.c:262:21: warning: unused variable 'dev' [-Wunused-variable]
     struct ksz_device *dev = ds->priv;
                        ^
   drivers/net/dsa/microchip/ksz_8895.c: In function 'ksz_br_leave':
   drivers/net/dsa/microchip/ksz_8895.c:270:21: warning: unused variable 'dev' [-Wunused-variable]
     struct ksz_device *dev = ds->priv;
                        ^
   drivers/net/dsa/microchip/ksz_8895.c: At top level:
>> drivers/net/dsa/microchip/ksz_8895.c:469:12: warning: 'struct switchdev_obj_port_fdb' declared inside parameter list
        struct switchdev_trans *trans)
               ^
>> drivers/net/dsa/microchip/ksz_8895.c:469:12: warning: its scope is only this definition or declaration, which is probably not what you want
   drivers/net/dsa/microchip/ksz_8895.c:497:16: warning: 'struct switchdev_obj_port_fdb' declared inside parameter list
            struct switchdev_trans *trans)
                   ^
   drivers/net/dsa/microchip/ksz_8895.c:503:21: warning: 'struct switchdev_obj_port_fdb' declared inside parameter list
           const struct switchdev_obj_port_fdb *fdb)
                        ^
   drivers/net/dsa/microchip/ksz_8895.c:510:9: warning: 'struct switchdev_obj_port_fdb' declared inside parameter list
            switchdev_obj_dump_cb_t *cb)
            ^
>> drivers/net/dsa/microchip/ksz_8895.c:576:2: error: unknown field 'port_vlan_dump' specified in initializer
     .port_vlan_dump  = ksz_port_vlan_dump,
     ^
>> drivers/net/dsa/microchip/ksz_8895.c:576:2: warning: initialization from incompatible pointer type
   drivers/net/dsa/microchip/ksz_8895.c:576:2: warning: (near initialization for 'ksz_switch_ops.port_fdb_add')
>> drivers/net/dsa/microchip/ksz_8895.c:577:2: error: unknown field 'port_fdb_prepare' specified in initializer
     .port_fdb_prepare = ksz_port_fdb_prepare,
     ^
   drivers/net/dsa/microchip/ksz_8895.c:577:2: warning: initialization from incompatible pointer type
   drivers/net/dsa/microchip/ksz_8895.c:577:2: warning: (near initialization for 'ksz_switch_ops.port_fdb_del')
   drivers/net/dsa/microchip/ksz_8895.c:578:2: warning: initialization from incompatible pointer type
     .port_fdb_dump  = ksz_port_fdb_dump,
     ^
   drivers/net/dsa/microchip/ksz_8895.c:578:2: warning: (near initialization for 'ksz_switch_ops.port_fdb_dump')
   drivers/net/dsa/microchip/ksz_8895.c:579:2: warning: initialization from incompatible pointer type
     .port_fdb_add  = ksz_port_fdb_add,
     ^
   drivers/net/dsa/microchip/ksz_8895.c:579:2: warning: (near initialization for 'ksz_switch_ops.port_fdb_add')
   drivers/net/dsa/microchip/ksz_8895.c:580:2: warning: initialization from incompatible pointer type
     .port_fdb_del  = ksz_port_fdb_del,
     ^
   drivers/net/dsa/microchip/ksz_8895.c:580:2: warning: (near initialization for 'ksz_switch_ops.port_fdb_del')
>> drivers/net/dsa/microchip/ksz_8895.c:584:2: error: unknown field 'port_mdb_dump' specified in initializer
     .port_mdb_dump          = ksz_port_mdb_dump,
     ^
   drivers/net/dsa/microchip/ksz_8895.c:584:2: warning: initialization from incompatible pointer type
   drivers/net/dsa/microchip/ksz_8895.c:584:2: warning: (near initialization for 'ksz_switch_ops.get_rxnfc')

vim +19 drivers/net/dsa/microchip/ksz_9477_reg.h

  > 19	#error This is not switch we have
    20	#ifndef __KSZ9477_REGS_H
    21	#define __KSZ9477_REGS_H
    22	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 50969 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-29 12:26                 ` Andrew Lunn
@ 2017-08-29 21:15                   ` Pavel Machek
  2017-08-29 21:23                     ` Florian Fainelli
  0 siblings, 1 reply; 35+ messages in thread
From: Pavel Machek @ 2017-08-29 21:15 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Maxim Uvarov, Woojung.Huh, nathan.leigh.conrad, Vivien Didelot,
	Florian Fainelli, netdev, linux-kernel, Tristram.Ha

[-- Attachment #1: Type: text/plain, Size: 809 bytes --]

On Tue 2017-08-29 14:26:04, Andrew Lunn wrote:
> > But the MDIO emaulation code is from their driver, after lots of
> > deletions.
> 
> Is this driver supposed to run on lots of different OSs? That would
> explain why they ignored the Linux MDIO and PHY layers.

It did not look particulary portable.

> If possible, please make use of the Linux infrastructure.

I did not find any infrastructure I could use instead
ksz_mdio_emulation.

Now, drivers/net/phy/spi_ks8995.c can access the PHY registers, and I
can not see any translation there, so there may be something I'm
missing.

Pointers would be welcome at this point.

Thanks,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-29 21:15                   ` Pavel Machek
@ 2017-08-29 21:23                     ` Florian Fainelli
  2017-08-30 10:06                       ` Maxim Uvarov
  0 siblings, 1 reply; 35+ messages in thread
From: Florian Fainelli @ 2017-08-29 21:23 UTC (permalink / raw)
  To: Pavel Machek, Andrew Lunn, Woojung.Huh
  Cc: Maxim Uvarov, nathan.leigh.conrad, Vivien Didelot, netdev,
	linux-kernel, Tristram.Ha

On 08/29/2017 02:15 PM, Pavel Machek wrote:
> On Tue 2017-08-29 14:26:04, Andrew Lunn wrote:
>>> But the MDIO emaulation code is from their driver, after lots of
>>> deletions.
>>
>> Is this driver supposed to run on lots of different OSs? That would
>> explain why they ignored the Linux MDIO and PHY layers.
> 
> It did not look particulary portable.

Part of the problem is that they need to duplicate the standard MII
definitions, whereas we could re-use those from include/linux/mii.h
and/or mdio.h.

> 
>> If possible, please make use of the Linux infrastructure.
> 
> I did not find any infrastructure I could use instead
> ksz_mdio_emulation.

fixed PHY/swphy.c is as close as it could get, but it is a highly
simplified version of this.

> 
> Now, drivers/net/phy/spi_ks8995.c can access the PHY registers, and I
> can not see any translation there, so there may be something I'm
> missing.

I don't see anything in that driver that seems to access PHY registers
what makes you think it does?

There's got to be a way to perform indirect accesses through SPI,
Woojung, do you know?

> 
> Pointers would be welcome at this point.
> 
> Thanks,
> 									Pavel
> 


-- 
Florian

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-29 21:23                     ` Florian Fainelli
@ 2017-08-30 10:06                       ` Maxim Uvarov
  0 siblings, 0 replies; 35+ messages in thread
From: Maxim Uvarov @ 2017-08-30 10:06 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Pavel Machek, Andrew Lunn, Woojung.Huh, Nathan Conrad,
	Vivien Didelot, netdev, linux-kernel, Tristram.Ha

2017-08-30 0:23 GMT+03:00 Florian Fainelli <f.fainelli@gmail.com>:
> On 08/29/2017 02:15 PM, Pavel Machek wrote:
>> On Tue 2017-08-29 14:26:04, Andrew Lunn wrote:
>>>> But the MDIO emaulation code is from their driver, after lots of
>>>> deletions.
>>>
>>> Is this driver supposed to run on lots of different OSs? That would
>>> explain why they ignored the Linux MDIO and PHY layers.
>>
>> It did not look particulary portable.
>
> Part of the problem is that they need to duplicate the standard MII
> definitions, whereas we could re-use those from include/linux/mii.h
> and/or mdio.h.
>
>>
>>> If possible, please make use of the Linux infrastructure.
>>
>> I did not find any infrastructure I could use instead
>> ksz_mdio_emulation.
>
> fixed PHY/swphy.c is as close as it could get, but it is a highly
> simplified version of this.
>
>>
>> Now, drivers/net/phy/spi_ks8995.c can access the PHY registers, and I
>> can not see any translation there, so there may be something I'm
>> missing.
>
> I don't see anything in that driver that seems to access PHY registers
> what makes you think it does?
>
> There's got to be a way to perform indirect accesses through SPI,
> Woojung, do you know?
>

As I understand they just attach phy on spi bus with generic driver:

        phy_addr = 0;
        phy_mode = PHY_INTERFACE_MODE_MII;
        snprintf(bus_id, MII_BUS_ID_SIZE, "sw.%d", sw_device_present);
        snprintf(phy_id, MII_BUS_ID_SIZE, PHY_ID_FMT, bus_id, phy_addr);
        phydev = phy_attach(netdev, phy_id, 0, phy_mode);
        if (!IS_ERR(phydev)) {
                phydev->adjust_link = sw_adjust_link;
                return phydev;
        }

Where is bus is:
bus = mdiobus_alloc();
bus->read = ksz_mii_read; (spi read function)
bus->write = ksz_mii_write;

Then just generic reads:
    .config_aneg    = genphy_config_aneg,
    .read_status    = genphy_read_status,


Maxim.

>>
>> Pointers would be welcome at this point.
>>
>> Thanks,
>>                                                                       Pavel
>>
>
>
> --
> Florian



-- 
Best regards,
Maxim Uvarov

^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: [PATCH] DSA support for Micrel KSZ8895
  2017-08-29  7:45             ` Pavel Machek
@ 2017-08-30 21:32               ` Tristram.Ha
  2017-08-30 22:00                 ` Andrew Lunn
                                   ` (2 more replies)
  0 siblings, 3 replies; 35+ messages in thread
From: Tristram.Ha @ 2017-08-30 21:32 UTC (permalink / raw)
  To: pavel
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, andrew

> On Mon 2017-08-28 16:09:27, Andrew Lunn wrote:
> > > I may be confused here, but AFAICT:
> > >
> > > 1) Yes, it has standard layout when accessed over MDIO.
> >
> >
> > Section 4.8 of the datasheet says:
> >
> > 	All the registers defined in this section can be also accessed
> > 	via the SPI interface.
> >
> > Meaning all PHY registers can be access via the SPI interface. So you
> > should be able to make a standard Linux MDIO bus driver which performs
> > SPI reads.
> 
> As far as I can tell (and their driver confirms) -- yes, all those registers can be
> accessed over the SPI, they are just shuffled around... hence MDIO
> emulation code. I copied it from their code (see the copyrights) so no, I don't
> believe there's nicer solution.
> 
> Best regards,
> 
> 									Pavel

Can you hold on your developing work on KSZ8895 driver?  I am afraid your effort may be in vain.  We at Microchip are planning to release DSA drivers for all KSZ switches, starting at KSZ8795, then KSZ8895, and KSZ8863.

The driver files all follow the structures of the current KSZ9477 DSA driver, and the file tag_ksz.c will be updated to handle the tail tag of different chips, which requires including the ksz_priv.h header.  That is required nevertheless to support using the offload_fwd_mark indication.

The KSZ8795 driver will be submitted after Labor Day (9/4) if testing reveals no problem.  The KSZ8895 driver will be submitted right after that.  You should have no problem using the driver right away.

Tristram Ha
Principal Software Engineer
Microchip Technology Inc.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-30 21:32               ` Tristram.Ha
@ 2017-08-30 22:00                 ` Andrew Lunn
  2017-09-01 12:15                 ` Pavel Machek
  2017-09-06  9:14                 ` Maxim Uvarov
  2 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2017-08-30 22:00 UTC (permalink / raw)
  To: Tristram.Ha
  Cc: pavel, Woojung.Huh, nathan.leigh.conrad, vivien.didelot,
	f.fainelli, netdev, linux-kernel

> The KSZ8795 driver will be submitted after Labor Day (9/4) if
> testing reveals no problem.  The KSZ8895 driver will be submitted
> right after that.  You should have no problem using the driver right
> away.

Hi Tristram

Release early, release often. It stops people wasting time....

Also, we are likely to give you feedback, asking you to make
changes. Testing is important, but you are probably going to have to
do it a number of times. So it is not everything passes now, don't
worry, you will have time to fix things up as you go through review
cycles.

    Andrew

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-30 21:32               ` Tristram.Ha
  2017-08-30 22:00                 ` Andrew Lunn
@ 2017-09-01 12:15                 ` Pavel Machek
  2017-09-01 22:18                   ` Florian Fainelli
  2017-09-06  9:14                 ` Maxim Uvarov
  2 siblings, 1 reply; 35+ messages in thread
From: Pavel Machek @ 2017-09-01 12:15 UTC (permalink / raw)
  To: Tristram.Ha
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, f.fainelli,
	netdev, linux-kernel, andrew

[-- Attachment #1: Type: text/plain, Size: 2295 bytes --]

Hi!

On Wed 2017-08-30 21:32:07, Tristram.Ha@microchip.com wrote:
> > On Mon 2017-08-28 16:09:27, Andrew Lunn wrote:
> > > > I may be confused here, but AFAICT:
> > > >
> > > > 1) Yes, it has standard layout when accessed over MDIO.
> > >
> > >
> > > Section 4.8 of the datasheet says:
> > >
> > > 	All the registers defined in this section can be also accessed
> > > 	via the SPI interface.
> > >
> > > Meaning all PHY registers can be access via the SPI interface. So you
> > > should be able to make a standard Linux MDIO bus driver which performs
> > > SPI reads.
> > 
> > As far as I can tell (and their driver confirms) -- yes, all those registers can be
> > accessed over the SPI, they are just shuffled around... hence MDIO
> > emulation code. I copied it from their code (see the copyrights) so no, I don't
> > believe there's nicer solution.
> > 
> > Best regards,
> 
> Can you hold on your developing work on KSZ8895 driver?  I am afraid your effort may be in vain.  We at Microchip are planning to release DSA drivers for all KSZ switches, starting at KSZ8795, then KSZ8895, and KSZ8863.
>

Well, thanks for heads up... but its too late to stop now. I already
have working code, without the advanced features.

I don't know how far away you are with the development. You may want
to start from my driver (but its probably too late now).

> The driver files all follow the structures of the current KSZ9477 DSA driver, and the file tag_ksz.c will be updated to handle the tail tag of different chips, which requires including the ksz_priv.h header.  That is required nevertheless to support using the offload_fwd_mark indication.
> 
> The KSZ8795 driver will be submitted after Labor Day (9/4) if
> testing reveals no problem.  The KSZ8895 driver will be submitted
> right after that.  You should have no problem using the driver right
> away.

Well, normally world can help with the testing, too. It would be nice
to see the code, as [RFC]. There's great chance that you'll have to
modify the code to adress review feedback, which is why seeing code
soon is useful.

Best regards,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-09-01 12:15                 ` Pavel Machek
@ 2017-09-01 22:18                   ` Florian Fainelli
  2017-09-02 15:40                     ` Pavel Machek
  0 siblings, 1 reply; 35+ messages in thread
From: Florian Fainelli @ 2017-09-01 22:18 UTC (permalink / raw)
  To: Pavel Machek, Tristram.Ha
  Cc: Woojung.Huh, nathan.leigh.conrad, vivien.didelot, netdev,
	linux-kernel, andrew

On 09/01/2017 05:15 AM, Pavel Machek wrote:
> Hi!
> 
> On Wed 2017-08-30 21:32:07, Tristram.Ha@microchip.com wrote:
>>> On Mon 2017-08-28 16:09:27, Andrew Lunn wrote:
>>>>> I may be confused here, but AFAICT:
>>>>>
>>>>> 1) Yes, it has standard layout when accessed over MDIO.
>>>>
>>>>
>>>> Section 4.8 of the datasheet says:
>>>>
>>>> 	All the registers defined in this section can be also accessed
>>>> 	via the SPI interface.
>>>>
>>>> Meaning all PHY registers can be access via the SPI interface. So you
>>>> should be able to make a standard Linux MDIO bus driver which performs
>>>> SPI reads.
>>>
>>> As far as I can tell (and their driver confirms) -- yes, all those registers can be
>>> accessed over the SPI, they are just shuffled around... hence MDIO
>>> emulation code. I copied it from their code (see the copyrights) so no, I don't
>>> believe there's nicer solution.
>>>
>>> Best regards,
>>
>> Can you hold on your developing work on KSZ8895 driver?  I am afraid your effort may be in vain.  We at Microchip are planning to release DSA drivers for all KSZ switches, starting at KSZ8795, then KSZ8895, and KSZ8863.
>>
> 
> Well, thanks for heads up... but its too late to stop now. I already
> have working code, without the advanced features.

No driver has landed yet nor has any driver been posted in a proper form
or shape, so at this point neither of you are able to make any claims as
to which one should be chosen.

> 
> I don't know how far away you are with the development. You may want
> to start from my driver (but its probably too late now).

I would tend to favor Tristram's submission when we see it because he
claims support for more devices and it is likely to be backed and
maintained by Microchip in the future.

I am sure there will be opportunity for you to contribute a lot to this
driver. Of course, this all depends on the code quality and timing, but
having two people work on the same things in parallel is just a complete
waste of each other's time so we might as well wait for Tristram to post
the said driver and define a plan of action from there?
-- 
Florian

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-09-01 22:18                   ` Florian Fainelli
@ 2017-09-02 15:40                     ` Pavel Machek
  0 siblings, 0 replies; 35+ messages in thread
From: Pavel Machek @ 2017-09-02 15:40 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Tristram.Ha, Woojung.Huh, nathan.leigh.conrad, vivien.didelot,
	netdev, linux-kernel, andrew

[-- Attachment #1: Type: text/plain, Size: 2475 bytes --]

Hi!

> >>>> Section 4.8 of the datasheet says:
> >>>>
> >>>> 	All the registers defined in this section can be also accessed
> >>>> 	via the SPI interface.
> >>>>
> >>>> Meaning all PHY registers can be access via the SPI interface. So you
> >>>> should be able to make a standard Linux MDIO bus driver which performs
> >>>> SPI reads.
> >>>
> >>> As far as I can tell (and their driver confirms) -- yes, all those registers can be
> >>> accessed over the SPI, they are just shuffled around... hence MDIO
> >>> emulation code. I copied it from their code (see the copyrights) so no, I don't
> >>> believe there's nicer solution.
> >>>
> >>> Best regards,
> >>
> >> Can you hold on your developing work on KSZ8895 driver?  I am afraid your effort may be in vain.  We at Microchip are planning to release DSA drivers for all KSZ switches, starting at KSZ8795, then KSZ8895, and KSZ8863.
> >>
> > 
> > Well, thanks for heads up... but its too late to stop now. I already
> > have working code, without the advanced features.
> 
> No driver has landed yet nor has any driver been posted in a proper form
> or shape, so at this point neither of you are able to make any claims as
> to which one should be chosen.

I certainly do not want to make any claims. Tristram's driver is
likely to support all (most?) features of the chip, which is not my
goal.

> > I don't know how far away you are with the development. You may want
> > to start from my driver (but its probably too late now).
> 
> I would tend to favor Tristram's submission when we see it because he
> claims support for more devices and it is likely to be backed and
> maintained by Microchip in the future.

Well, I guess we decide when we see the code, that's how it works, right?

> I am sure there will be opportunity for you to contribute a lot to this
> driver. Of course, this all depends on the code quality and timing, but
> having two people work on the same things in parallel is just a complete
> waste of each other's time so we might as well wait for Tristram to post
> the said driver and define a plan of action from there?

Well, it would be good to see the code, so we can judge the
quality. Normally, code is posted before testing, so this kind of
problems does not arise.

Best regards,

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-08-30 21:32               ` Tristram.Ha
  2017-08-30 22:00                 ` Andrew Lunn
  2017-09-01 12:15                 ` Pavel Machek
@ 2017-09-06  9:14                 ` Maxim Uvarov
  2017-09-06 16:47                   ` Tristram.Ha
  2 siblings, 1 reply; 35+ messages in thread
From: Maxim Uvarov @ 2017-09-06  9:14 UTC (permalink / raw)
  To: Tristram.Ha
  Cc: Pavel Machek, Woojung.Huh, Nathan Conrad, Vivien Didelot,
	Florian Fainelli, netdev, linux-kernel, Andrew Lunn

2017-08-31 0:32 GMT+03:00  <Tristram.Ha@microchip.com>:
>> On Mon 2017-08-28 16:09:27, Andrew Lunn wrote:
>> > > I may be confused here, but AFAICT:
>> > >
>> > > 1) Yes, it has standard layout when accessed over MDIO.
>> >
>> >
>> > Section 4.8 of the datasheet says:
>> >
>> >     All the registers defined in this section can be also accessed
>> >     via the SPI interface.
>> >
>> > Meaning all PHY registers can be access via the SPI interface. So you
>> > should be able to make a standard Linux MDIO bus driver which performs
>> > SPI reads.
>>
>> As far as I can tell (and their driver confirms) -- yes, all those registers can be
>> accessed over the SPI, they are just shuffled around... hence MDIO
>> emulation code. I copied it from their code (see the copyrights) so no, I don't
>> believe there's nicer solution.
>>
>> Best regards,
>>
>>                                                                       Pavel
>
> Can you hold on your developing work on KSZ8895 driver?  I am afraid your effort may be in vain.  We at Microchip are planning to release DSA drivers for all KSZ switches, starting at KSZ8795, then KSZ8895, and KSZ8863.
>
> The driver files all follow the structures of the current KSZ9477 DSA driver, and the file tag_ksz.c will be updated to handle the tail tag of different chips, which requires including the ksz_priv.h header.  That is required nevertheless to support using the offload_fwd_mark indication.
>
> The KSZ8795 driver will be submitted after Labor Day (9/4) if testing reveals no problem.  The KSZ8895 driver will be submitted right after that.  You should have no problem using the driver right away.
>

Hello Tristram, is there any update for that driver?

Maxim.


> Tristram Ha
> Principal Software Engineer
> Microchip Technology Inc.
>



-- 
Best regards,
Maxim Uvarov

^ permalink raw reply	[flat|nested] 35+ messages in thread

* RE: [PATCH] DSA support for Micrel KSZ8895
  2017-09-06  9:14                 ` Maxim Uvarov
@ 2017-09-06 16:47                   ` Tristram.Ha
  2017-09-06 17:09                     ` Andrew Lunn
  0 siblings, 1 reply; 35+ messages in thread
From: Tristram.Ha @ 2017-09-06 16:47 UTC (permalink / raw)
  To: muvarov
  Cc: pavel, Woojung.Huh, nathan.leigh.conrad, vivien.didelot,
	f.fainelli, netdev, linux-kernel, andrew

> -----Original Message-----
> From: Maxim Uvarov [mailto:muvarov@gmail.com]
> Sent: Wednesday, September 06, 2017 2:15 AM
> To: Tristram Ha - C24268
> Cc: Pavel Machek; Woojung Huh - C21699; Nathan Conrad; Vivien Didelot;
> Florian Fainelli; netdev; linux-kernel@vger.kernel.org; Andrew Lunn
> Subject: Re: [PATCH] DSA support for Micrel KSZ8895
> 
> 2017-08-31 0:32 GMT+03:00  <Tristram.Ha@microchip.com>:
> >> On Mon 2017-08-28 16:09:27, Andrew Lunn wrote:
> >> > > I may be confused here, but AFAICT:
> >> > >
> >> > > 1) Yes, it has standard layout when accessed over MDIO.
> >> >
> >> >
> >> > Section 4.8 of the datasheet says:
> >> >
> >> >     All the registers defined in this section can be also accessed
> >> >     via the SPI interface.
> >> >
> >> > Meaning all PHY registers can be access via the SPI interface. So
> >> > you should be able to make a standard Linux MDIO bus driver which
> >> > performs SPI reads.
> >>
> >> As far as I can tell (and their driver confirms) -- yes, all those
> >> registers can be accessed over the SPI, they are just shuffled
> >> around... hence MDIO emulation code. I copied it from their code (see
> >> the copyrights) so no, I don't believe there's nicer solution.
> >>
> >> Best regards,
> >>
> >>
> >> Pavel
> >
> > Can you hold on your developing work on KSZ8895 driver?  I am afraid your
> effort may be in vain.  We at Microchip are planning to release DSA drivers
> for all KSZ switches, starting at KSZ8795, then KSZ8895, and KSZ8863.
> >
> > The driver files all follow the structures of the current KSZ9477 DSA driver,
> and the file tag_ksz.c will be updated to handle the tail tag of different chips,
> which requires including the ksz_priv.h header.  That is required
> nevertheless to support using the offload_fwd_mark indication.
> >
> > The KSZ8795 driver will be submitted after Labor Day (9/4) if testing reveals
> no problem.  The KSZ8895 driver will be submitted right after that.  You
> should have no problem using the driver right away.
> >
> 
> Hello Tristram, is there any update for that driver?
> 
> Maxim.
> 

The patches are under review internally and will need to be updated and approved by Woojung before formal submission.  Problem is although KSZ8795 and KSZ8895 drivers are new code and will be submitted as RFC, they depend on the change of KSZ9477 driver currently in the kernel, which require more rigorous review.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] DSA support for Micrel KSZ8895
  2017-09-06 16:47                   ` Tristram.Ha
@ 2017-09-06 17:09                     ` Andrew Lunn
  0 siblings, 0 replies; 35+ messages in thread
From: Andrew Lunn @ 2017-09-06 17:09 UTC (permalink / raw)
  To: Tristram.Ha
  Cc: muvarov, pavel, Woojung.Huh, nathan.leigh.conrad, vivien.didelot,
	f.fainelli, netdev, linux-kernel

> The patches are under review internally and will need to be updated
> and approved by Woojung before formal submission.  Problem is
> although KSZ8795 and KSZ8895 drivers are new code and will be
> submitted as RFC, they depend on the change of KSZ9477 driver
> currently in the kernel, which require more rigorous review.

Please be aware that they will also go though review when you post
them. This can be anything from great, nice job, to throw them away
and start again. Since you are submitting RFCs we understand it is
early code, issues still to be solved, and we can make suggestions how
to solve those issues.

Post early, post often...

     Andrew

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2017-09-06 17:09 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-16  7:55 DSA support for Micrel KSZ8895 Pavel Machek
2017-08-16 14:04 ` Andrew Lunn
2017-08-16 14:25   ` Woojung.Huh
2017-08-23  9:09     ` Pavel Machek
2017-08-23 12:42       ` Andrew Lunn
2017-08-23 21:48       ` Woojung.Huh
2017-08-28 10:14         ` Pavel Machek
2017-08-28 13:19           ` Andrew Lunn
2017-08-27 12:36     ` [PATCH] " Pavel Machek
2017-08-27 13:59       ` Andrew Lunn
2017-08-27 16:31       ` Andrew Lunn
2017-08-28  7:02         ` Pavel Machek
2017-08-28 14:09           ` Andrew Lunn
2017-08-28 14:47             ` Maxim Uvarov
2017-08-29  7:41               ` Pavel Machek
2017-08-29 12:26                 ` Andrew Lunn
2017-08-29 21:15                   ` Pavel Machek
2017-08-29 21:23                     ` Florian Fainelli
2017-08-30 10:06                       ` Maxim Uvarov
2017-08-29  7:45             ` Pavel Machek
2017-08-30 21:32               ` Tristram.Ha
2017-08-30 22:00                 ` Andrew Lunn
2017-09-01 12:15                 ` Pavel Machek
2017-09-01 22:18                   ` Florian Fainelli
2017-09-02 15:40                     ` Pavel Machek
2017-09-06  9:14                 ` Maxim Uvarov
2017-09-06 16:47                   ` Tristram.Ha
2017-09-06 17:09                     ` Andrew Lunn
2017-08-27 16:44       ` Andrew Lunn
2017-08-28  6:40         ` Pavel Machek
2017-08-27 16:56       ` Florian Fainelli
2017-08-28  6:47         ` Pavel Machek
2017-08-27 22:03       ` Woojung.Huh
2017-08-29 15:33       ` kbuild test robot
2017-08-16 18:32   ` Pavel Machek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.