* [PATCH][net-next] net: hinic: make functions set_ctrl0 and set_ctrl1 static
From: Colin King @ 2017-08-23 9:59 UTC (permalink / raw)
To: Aviad Krawczyk, netdev; +Cc: kernel-janitors, linux-kernel
From: Colin Ian King <colin.king@canonical.com>
The functions set_ctrl0 and set_ctrl1 are local to the source and do
not need to be in global scope, so make them static.
Cleans up sparse warnings:
symbol 'set_ctrl0' was not declared. Should it be static?
symbol 'set_ctrl1' was not declared. Should it be static?
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
index cd09e6ef3aea..7cb8b9b94726 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
@@ -423,7 +423,7 @@ static irqreturn_t ceq_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-void set_ctrl0(struct hinic_eq *eq)
+static void set_ctrl0(struct hinic_eq *eq)
{
struct msix_entry *msix_entry = &eq->msix_entry;
enum hinic_eq_type type = eq->type;
@@ -474,7 +474,7 @@ void set_ctrl0(struct hinic_eq *eq)
}
}
-void set_ctrl1(struct hinic_eq *eq)
+static void set_ctrl1(struct hinic_eq *eq)
{
enum hinic_eq_type type = eq->type;
u32 page_size_val, elem_size;
--
2.14.1
^ permalink raw reply related
* [PATCH 2/3] net: rsi: mac80211: constify ieee80211_ops
From: Arvind Yadav @ 2017-08-23 9:59 UTC (permalink / raw)
To: davem, Larry.Finger, chaoming_li, kvalo, jon.maloy, ying.xue
Cc: linux-kernel, linux-wireless, netdev
In-Reply-To: <1503482375-19983-1-git-send-email-arvind.yadav.cs@gmail.com>
ieee80211_ops are not supposed to change at runtime. All functions
working with ieee80211_ops provided by <net/mac80211.h> work with
const ieee80211_ops. So mark the non-const structs as const.
Signed-off-by: Arvind Yadav <arvind.yadav.cs@gmail.com>
---
drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 021e5ac..67532fb 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -1177,7 +1177,7 @@ static void rsi_reg_notify(struct wiphy *wiphy,
adapter->dfs_region = request->dfs_region;
}
-static struct ieee80211_ops mac80211_ops = {
+static const struct ieee80211_ops mac80211_ops = {
.tx = rsi_mac80211_tx,
.start = rsi_mac80211_start,
.stop = rsi_mac80211_stop,
--
1.9.1
^ permalink raw reply related
* [PATCH 1/3] net: rtlwifi: constify rate_control_ops
From: Arvind Yadav @ 2017-08-23 9:59 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q, Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ,
chaoming_li-kXabqFNEczNtrwSWzY7KCg, kvalo-sgV2jX0FEOL9JmXXK+q4OQ,
jon.maloy-IzeFyvvaP7pWk0Htik3J/w, ying.xue-CWA4WttNNZF54TAoqtyWWQ
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1503482375-19983-1-git-send-email-arvind.yadav.cs-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
rate_control_ops are not supposed to change at runtime. All functions
working with rate_control_ops provided by <net/mac80211.h> work with
const rate_control_ops. So mark the non-const structs as const.
Signed-off-by: Arvind Yadav <arvind.yadav.cs-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/net/wireless/realtek/rtlwifi/rc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtlwifi/rc.c b/drivers/net/wireless/realtek/rtlwifi/rc.c
index 951d257..02811ed 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rc.c
@@ -283,7 +283,7 @@ static void rtl_rate_free_sta(void *rtlpriv,
kfree(rate_priv);
}
-static struct rate_control_ops rtl_rate_ops = {
+static const struct rate_control_ops rtl_rate_ops = {
.name = "rtl_rc",
.alloc = rtl_rate_alloc,
.free = rtl_rate_free,
--
1.9.1
^ permalink raw reply related
* Re: [PATCH V8 net-next 00/22] Huawei HiNIC Ethernet Driver
From: Aviad Krawczyk @ 2017-08-23 9:31 UTC (permalink / raw)
To: Arnd Bergmann
Cc: David Miller, Linux Kernel Mailing List, Networking, bc.y,
victor.gissin, zhaochen6, tony.qu
In-Reply-To: <CAK8P3a3sWBZKZTz8YM2DfNwsLSWZpaS_e-Uh1VVKuCL6q+si3g@mail.gmail.com>
Hi Arnd,
This is Huawei's PCIE HiNIC card.
I am not familiar with the HiSilicon product and I don't see how
Huawei's PCIE HiNIC card is connected to the HiSilicon drivers on Linux Tree.
I don't see how it can be shared: different product and different code.
Thanks,
Aviad
On 8/23/2017 10:37 AM, Arnd Bergmann wrote:
> On Mon, Aug 21, 2017 at 5:55 PM, Aviad Krawczyk
> <aviad.krawczyk@huawei.com> wrote:
>> The patch-set contains the support of the HiNIC Ethernet driver for
>> hinic family of PCIE Network Interface Cards.
>>
>> The Huawei's PCIE HiNIC card is a new Ethernet card and hence there was
>> a need of a new driver.
>>
>> The current driver is meant to be used for the Physical Function and there
>> would soon be a support for Virtual Function and more features once the
>> basic PF driver has been accepted.
>
> Sorry I didn't comment before it got merged, but once it appeared in
> linux-next I saw it and wondered why this is grouped under huawei
> unlike the network drivers for the parts integrated into the hip0x
> SoCs from hisilicon. Both appear to be made by Huawei's HiSilicon
> subsidiary.
>
> I did not check whether the two devices are related at all or could
> share some of the source code as well, but it might be good to
> move this one into the existing directory to spare confusion later.
>
> Arnd
>
> .
>
^ permalink raw reply
* Re: [PATCH V8 net-next 00/22] Huawei HiNIC Ethernet Driver
From: Aviad Krawczyk @ 2017-08-23 9:14 UTC (permalink / raw)
To: David Miller
Cc: linux-kernel, netdev, bc.y, victor.gissin, zhaochen6, tony.qu
In-Reply-To: <20170822.105806.1619462776317978185.davem@davemloft.net>
Thanks, David!
Thanks to all the reviewers!
On 8/22/2017 8:58 PM, David Miller wrote:
> From: Aviad Krawczyk <aviad.krawczyk@huawei.com>
> Date: Mon, 21 Aug 2017 23:55:46 +0800
>
>> The patch-set contains the support of the HiNIC Ethernet driver for
>> hinic family of PCIE Network Interface Cards.
>
> Series applied, thanks.
>
> .
>
^ permalink raw reply
* Re: DSA support for Micrel KSZ8895
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
In-Reply-To: <9235D6609DB808459E95D78E17F2E43D40AFF8C1@CHN-SV-EXMX02.mchp-main.com>
[-- 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(®num, &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(®num, &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
* Re: XDP redirect measurements, gotchas and tracepoints
From: Jesper Dangaard Brouer @ 2017-08-23 8:56 UTC (permalink / raw)
To: John Fastabend
Cc: Alexei Starovoitov, xdp-newbies@vger.kernel.org, Daniel Borkmann,
Andy Gospodarek, netdev@vger.kernel.org, Paweł Staszewski,
brouer
In-Reply-To: <599C6747.8010005@gmail.com>
On Tue, 22 Aug 2017 10:17:59 -0700
John Fastabend <john.fastabend@gmail.com> wrote:
> On 08/22/2017 10:09 AM, Alexei Starovoitov wrote:
> > On Tue, Aug 22, 2017 at 08:37:10AM +0200, Jesper Dangaard Brouer wrote:
> >>
> >>
> >>> Once tx-ing netdev added to devmap we can enable xdp on it automatically?
> >>
> >> I think you are referring to Gotcha-2 here:
> >
> > oops. yes :)
> >
> >>
> >> Second gotcha(2): you cannot TX out a device, unless it also have a
> >> xdp bpf program attached. (This is an implicit dependency, as the
> >> driver code need to setup XDP resources before it can ndo_xdp_xmit).
> >>
> >> Yes, we should work on improving this situation. Auto enabling XDP
> >> when a netdev is added to a devmap is a good solution. Currently this
> >> is tied to loading an XDP bpf_prog. Do you propose loading a dummy
> >> bpf_prog on the netdev? (then we need to handle 1. not replacing
> >> existing bpf_prog, 2. on take-down don't remove "later" loaded
> >> bpf_prog).
> >
> > right. these things need to be taken care of.
> > Technically for ndo_xdp_xmit to work the program doesn't need
> > to be attached, but the device needs to be in xdp mode with
> > configured xdp tx rings.
> > The easiest, of course, is just to document it :)
> > and may be add some sort of warning that if netdev is added
> > to devmap and it's not in xdp mode, return warning or error.
> >
>
> When I wrote this I assumed some user space piece could
> load the "dummy" nop program on devices as needed. It seemed
> easier than putting semi-complex logic in the kernel to load
> programs on update_elem, but only if the user hasn't already
> loaded a program and then unload it but again only if some
> criteria is met. Then we would have one more kernel path into
> load/unload BPF programs and would need all the tests and what
> not.
I agree, it is not good to add this kind of logic to the kernel. We
would create too many funny race conditions with userspace.
> +1 for documenting and userland usability patches.
We still don't have a good place for XDP documentation. My own[1]
attempt have gotten out-of-sync, and I need to restructure the
rst-docs, before I want to propose it for the kernel.
[1] https://prototype-kernel.readthedocs.io/en/latest/networking/XDP/index.html
I want to create some samples/examples with XDP_REDIRECT, that
highlight this property. Maybe the samples/bpf/xdp_redirect{,_map}
should automatically attach a XDP bpf_prog to the egress device?
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Principal Kernel Engineer at Red Hat
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply
* Re: [PATCH net-next 5/5] xdp: get tracepoints xdp_exception and xdp_redirect in sync
From: Daniel Borkmann @ 2017-08-23 8:54 UTC (permalink / raw)
To: Jesper Dangaard Brouer; +Cc: netdev, John Fastabend
In-Reply-To: <20170823094118.38010b86@redhat.com>
On 08/23/2017 09:41 AM, Jesper Dangaard Brouer wrote:
> On Tue, 22 Aug 2017 23:30:21 +0200
> Daniel Borkmann <daniel@iogearbox.net> wrote:
>> On 08/22/2017 10:47 PM, Jesper Dangaard Brouer wrote:
>>> Remove the net_device string name from the xdp_exception tracepoint,
>>> like the xdp_redirect tracepoint.
>>>
>>> Align the TP_STRUCT to have common entries between these two
>>> tracepoint.
>>>
>>> Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
>>> ---
>>> include/trace/events/xdp.h | 24 ++++++++++++------------
>>> 1 file changed, 12 insertions(+), 12 deletions(-)
>>>
>>> diff --git a/include/trace/events/xdp.h b/include/trace/events/xdp.h
>>> index 7511bed80558..6495b0d9d5c7 100644
>>> --- a/include/trace/events/xdp.h
>>> +++ b/include/trace/events/xdp.h
>>> @@ -31,22 +31,22 @@ TRACE_EVENT(xdp_exception,
>>> TP_ARGS(dev, xdp, act),
>>>
>>> TP_STRUCT__entry(
>>> - __string(name, dev->name)
>>> __array(u8, prog_tag, 8)
>>> __field(u32, act)
>>> + __field(int, ifindex)
>>> ),
>>>
>>> TP_fast_assign(
>>> BUILD_BUG_ON(sizeof(__entry->prog_tag) != sizeof(xdp->tag));
>>> memcpy(__entry->prog_tag, xdp->tag, sizeof(xdp->tag));
>>> - __assign_str(name, dev->name);
>>> - __entry->act = act;
>>> + __entry->act = act;
>>> + __entry->ifindex = dev->ifindex;
>>> ),
>>>
>> [...]
>>> TRACE_EVENT(xdp_redirect,
>>> @@ -57,26 +57,26 @@ TRACE_EVENT(xdp_redirect,
>>> TP_ARGS(from_index, to_index, xdp, act, err),
>>>
>>> TP_STRUCT__entry(
>>> - __field(int, from_index)
>>> - __field(int, to_index)
>>> __array(u8, prog_tag, 8)
>>> __field(u32, act)
>>> + __field(int, from_index)
>>> + __field(int, to_index)
>>> __field(int, err)
>>> ),
>>>
>>> TP_fast_assign(
>>> BUILD_BUG_ON(sizeof(__entry->prog_tag) != sizeof(xdp->tag));
>>> memcpy(__entry->prog_tag, xdp->tag, sizeof(xdp->tag));
>>> + __entry->act = act;
>>> __entry->from_index = from_index;
>>> __entry->to_index = to_index;
>>> - __entry->act = act;
>>
>> If you already get them in sync, could you also make it consistent
>> that for both tracepoints in TP_ARGS() we use either ifindex
>> directly or device pointer and extract it from TP_fast_assign().
>> Right now, it's mixed.
>
> I did this because, in the (bpf_redirect)_map case, I was hoping that
> "from_index" could be come the index from the map. Looking closer at
> the devmap design, I cannot see how we can ever know what (the bpf_prog
> thinks) is the corresponding map-ingress/from_index.
>
> Based on that, I think we can/should use the device pointer as arg (as
> you suggested). And then rename "from_index" to "ifindex", where
> ifindex is the XDP ifindex the xdp_buff arrived on.
>
> I guess we can keep the "to_index". We also need to extend the
> tracepoint args with a "map", to let the trace user tell whether the
> "to_index" is an ifindex or a map-index.
Yeah, makes sense, right now we cannot differentiate between that.
> I'll code this up and submit at V2.
Thanks!
^ permalink raw reply
* [PATCH v3] net: stmmac: Delete dead code for MDIO registration
From: Romain Perier @ 2017-08-23 8:50 UTC (permalink / raw)
To: Giuseppe Cavallaro, Alexandre Torgue, Andrew Lunn,
Florian Fainelli
Cc: netdev, linux-kernel, Romain Perier
This code is no longer used, the logging function was changed by commit
fbca164776e4 ("net: stmmac: Use the right logging functi"). It was
previously showing information about the type if the IRQ, if it's polled,
ignored or a normal interrupt. As we don't want information loss, I have
moved this code to phy_attached_print().
Fixes: fbca164776e4 ("net: stmmac: Use the right logging functi")
Signed-off-by: Romain Perier <romain.perier@collabora.com>
---
Hello,
This is the continuity of "[PATCH v2 0/2] net: stmmac: phy logging fixes",
see https://lkml.org/lkml/2017/8/21/288
Changes in v3:
- Removed patch 2/2: "net: phy: Don't use drv when it is NULL in phy_attached_print",
fixed upstream by fcd03e362b1c
("net: phy: Deal with unbound PHY driver in phy_attached_print()")
- Moved this code to phy_attached_print(), so we have more informations
about the IRQ (poll, ignore or normal irq) and no information are loss.
- Re-worded commit message
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 16 ----------------
drivers/net/phy/phy_device.c | 21 ++++++++++++++++++---
2 files changed, 18 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 72ec711fcba2..f5f37bfa1d58 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -248,9 +248,6 @@ int stmmac_mdio_register(struct net_device *ndev)
found = 0;
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);
- int act = 0;
- char irq_num[4];
- char *irq_str;
if (!phydev)
continue;
@@ -273,19 +270,6 @@ int stmmac_mdio_register(struct net_device *ndev)
if (priv->plat->phy_addr == -1)
priv->plat->phy_addr = addr;
- act = (priv->plat->phy_addr == addr);
- switch (phydev->irq) {
- case PHY_POLL:
- irq_str = "POLL";
- break;
- case PHY_IGNORE_INTERRUPT:
- irq_str = "IGNORE";
- break;
- default:
- sprintf(irq_num, "%d", phydev->irq);
- irq_str = irq_num;
- break;
- }
phy_attached_info(phydev);
found = 1;
}
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 810f6fd2f639..a3ba51808b1a 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -874,21 +874,36 @@ void phy_attached_info(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_attached_info);
-#define ATTACHED_FMT "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)"
+#define ATTACHED_FMT "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%s)"
void phy_attached_print(struct phy_device *phydev, const char *fmt, ...)
{
const char *drv_name = phydev->drv ? phydev->drv->name : "unbound";
+ char *irq_str;
+ char irq_num[4];
+
+ switch(phydev->irq) {
+ case PHY_POLL:
+ irq_str = "POLL";
+ break;
+ case PHY_IGNORE_INTERRUPT:
+ irq_str = "IGNORE";
+ break;
+ default:
+ snprintf(irq_num, sizeof(irq_str), "%d", phydev->irq);
+ irq_str = irq_num;
+ break;
+ }
if (!fmt) {
dev_info(&phydev->mdio.dev, ATTACHED_FMT "\n",
drv_name, phydev_name(phydev),
- phydev->irq);
+ irq_str);
} else {
va_list ap;
dev_info(&phydev->mdio.dev, ATTACHED_FMT,
drv_name, phydev_name(phydev),
- phydev->irq);
+ irq_str);
va_start(ap, fmt);
vprintk(fmt, ap);
--
2.11.0
^ permalink raw reply related
* Re: XDP redirect measurements, gotchas and tracepoints
From: Jesper Dangaard Brouer @ 2017-08-23 8:29 UTC (permalink / raw)
To: Michael Chan
Cc: Alexander Duyck, Duyck, Alexander H, john.fastabend@gmail.com,
pstaszewski@itcare.pl, netdev@vger.kernel.org,
xdp-newbies@vger.kernel.org, andy@greyhouse.net,
borkmann@iogearbox.net, brouer
In-Reply-To: <CACKFLinJ0N7b8Xhq4ZoHdB80uXp_MU_vVyzZa7Dq11XrXsvDbw@mail.gmail.com>
On Tue, 22 Aug 2017 23:59:05 -0700
Michael Chan <michael.chan@broadcom.com> wrote:
> On Tue, Aug 22, 2017 at 6:06 PM, Alexander Duyck
> <alexander.duyck@gmail.com> wrote:
> > On Tue, Aug 22, 2017 at 1:04 PM, Michael Chan <michael.chan@broadcom.com> wrote:
> >>
> >> Right, but it's conceivable to add an API to "return" the buffer to
> >> the input device, right?
Yes, I would really like to see an API like this.
> >
> > You could, it is just added complexity. "just free the buffer" in
> > ixgbe usually just amounts to one atomic operation to decrement the
> > total page count since page recycling is already implemented in the
> > driver. You still would have to unmap the buffer regardless of if you
> > were recycling it or not so all you would save is 1.000015259 atomic
> > operations per packet. The fraction is because once every 64K uses we
> > have to bulk update the count on the page.
> >
>
> If the buffer is returned to the input device, the input device can
> keep the DMA mapping. All it needs to do is to dma_sync it back to
> the input device when the buffer is returned.
Yes, exactly, return to the input device. I really think we should
work on a solution where we can keep the DMA mapping around. We have
an opportunity here to make ndo_xdp_xmit TX queues use a specialized
page return call, to achieve this. (I imagine other arch's have a high
DMA overhead than Intel)
I'm not sure how the API should look. The ixgbe recycle mechanism and
splitting the page (into two packets) actually complicates things, and
tie us into a page-refcnt based model. We could get around this by
each driver implementing a page-return-callback, that allow us to
return the page to the input device? Then, drivers implementing the
1-packet-per-page can simply check/read the page-refcnt, and if it is
"1" DMA-sync and reuse it in the RX queue.
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Principal Kernel Engineer at Red Hat
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply
* Re: [PATCH net-next 10/18] net: mvpp2: use the GoP interrupt for link status changes
From: Antoine Tenart @ 2017-08-23 8:25 UTC (permalink / raw)
To: Andrew Lunn
Cc: Antoine Tenart, davem, jason, gregory.clement,
sebastian.hesselbarth, thomas.petazzoni, nadavh, linux, mw,
stefanc, netdev, linux-arm-kernel
In-Reply-To: <20170726162648.GK12049@lunn.ch>
[-- Attachment #1: Type: text/plain, Size: 1309 bytes --]
Hi Andrew, Russell,
On Wed, Jul 26, 2017 at 06:26:48PM +0200, Andrew Lunn wrote:
> On Mon, Jul 24, 2017 at 03:48:40PM +0200, Antoine Tenart wrote:
> > This patch adds the GoP link interrupt support for when a port isn't
> > connected to a PHY. Because of this the phylib callback is never called
> > and the link status management isn't done. This patch use the GoP link
> > interrupt in such cases to still have a minimal link management. Without
> > this patch ports not connected to a PHY cannot work.
>
> When is a GoP link interrupt signalled? When is a port without a PHY
> actually up/down?
When the cable is connected (there is signal) and the serdes is in sync
and AN succeeded.
> With SFF/SFP ports, you generally need a gpio line the fibre module
> can use to indicate if it has link. Fixed-phy has such support, and
> your link_change function will get called when the link changes.
So that would work when using SFP modules but I wonder if the GoP irq
isn't needed when using passive cable, in which case this patch would
still be needed (and of course we should support the new Russell phylib
capabilities).
What's your thoughts on this?
Thanks!
Antoine
--
Antoine Ténart, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH net] net: xfrm: don't double-hold dst when sk_policy in use.
From: Lorenzo Colitti @ 2017-08-23 8:14 UTC (permalink / raw)
To: netdev; +Cc: weiwan, davem, steffen.klassert, misterikkit, Lorenzo Colitti
While removing dst_entry garbage collection, commit 52df157f17e5
("xfrm: take refcnt of dst when creating struct xfrm_dst bundle")
changed xfrm_resolve_and_create_bundle so it returns an xdst with
a refcount of 1 instead of 0.
However, it did not delete the dst_hold performed by xfrm_lookup
when a per-socket policy is in use. This means that when a
socket policy is in use, dst entries returned by xfrm_lookup have
a refcount of 2, and are not freed when no longer in use.
Cc: Wei Wang <weiwan@google.com>
Fixes: 52df157f17 ("xfrm: take refcnt of dst when creating struct xfrm_dst bundle")
Tested: https://android-review.googlesource.com/417481
Tested: https://android-review.googlesource.com/418659
Tested: https://android-review.googlesource.com/424463
Tested: https://android-review.googlesource.com/452776 passes on net-next
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
---
net/xfrm/xfrm_policy.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 6f5a0dad50..69b16ee327 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2226,7 +2226,6 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
goto no_transform;
}
- dst_hold(&xdst->u.dst);
route = xdst->route;
}
}
--
2.14.1.480.gb18f417b89-goog
^ permalink raw reply related
* Re: [PATCH net-next v2 10/10] arm64: dts: marvell: mcbin: enable more networking ports
From: Antoine Tenart @ 2017-08-23 8:11 UTC (permalink / raw)
To: Baruch Siach
Cc: Antoine Tenart, davem, jason, andrew, gregory.clement,
sebastian.hesselbarth, thomas.petazzoni, netdev, linux, nadavh,
stefanc, mw, linux-arm-kernel
In-Reply-To: <20170823072842.ibk6gqtswhamvppy@sapphire.tkos.co.il>
[-- Attachment #1: Type: text/plain, Size: 1338 bytes --]
Hi Baruch,
On Wed, Aug 23, 2017 at 10:28:42AM +0300, Baruch Siach wrote:
> On Tue, Aug 22, 2017 at 07:08:30PM +0200, Antoine Tenart wrote:
> > This patch enables the two GE/SFP ports. They are configured in 10GKR
> > mode by default. To do this the cpm_xdmio is enabled as well, and two
> > phy descriptions are added.
> >
> > Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
> > Tested-by: Marcin Wojtas <mw@semihalf.com>
> > ---
> > arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts | 30 +++++++++++++++++++++++
> > 1 file changed, 30 insertions(+)
> >
> > diff --git a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
> > index abd39d1c1739..6cb4b000e1ac 100644
> > --- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
> > +++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
> > @@ -127,6 +127,30 @@
> > };
> > };
> >
> > +&cpm_xmdio {
> > + status = "okay";
> > +
> > + phy0: ethernet-phy@0 {
> > + compatible = "ethernet-phy-ieee802.3-c45";
> > + reg = <0>;
> > + };
> > +
> > + phy1: ethernet-phy@1 {
>
> Should be named 'ethernet-phy@8' to match the 'reg' property.
That's right.
Thanks!
Antoine
--
Antoine Ténart, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [patch net-next 5/5] mlxsw: spectrum_flower: Offload goto_chain termination action
From: Jiri Pirko @ 2017-08-23 8:08 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, jhs, xiyou.wangcong
In-Reply-To: <20170823080652.14847-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
If action is gact goto_chain, offload it to HW by jumping to another
ruleset.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
.../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 23 ++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
index 34872aa..8aace9a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
@@ -45,7 +45,7 @@
#include "core_acl_flex_keys.h"
static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
- struct net_device *dev,
+ struct net_device *dev, bool ingress,
struct mlxsw_sp_acl_rule_info *rulei,
struct tcf_exts *exts)
{
@@ -71,6 +71,20 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
err = mlxsw_sp_acl_rulei_act_trap(rulei);
if (err)
return err;
+ } else if (is_tcf_gact_goto_chain(a)) {
+ u32 chain_index = tcf_gact_goto_chain_index(a);
+ struct mlxsw_sp_acl_ruleset *ruleset;
+ u16 group_id;
+
+ ruleset = mlxsw_sp_acl_ruleset_lookup(mlxsw_sp, dev,
+ ingress,
+ chain_index,
+ MLXSW_SP_ACL_PROFILE_FLOWER);
+ if (IS_ERR(ruleset))
+ return PTR_ERR(ruleset);
+
+ group_id = mlxsw_sp_acl_ruleset_group_id(ruleset);
+ mlxsw_sp_acl_rulei_act_jump(rulei, group_id);
} else if (is_tcf_mirred_egress_redirect(a)) {
int ifindex = tcf_mirred_ifindex(a);
struct net_device *out_dev;
@@ -246,7 +260,7 @@ static int mlxsw_sp_flower_parse_ip(struct mlxsw_sp *mlxsw_sp,
}
static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
- struct net_device *dev,
+ struct net_device *dev, bool ingress,
struct mlxsw_sp_acl_rule_info *rulei,
struct tc_cls_flower_offload *f)
{
@@ -364,7 +378,8 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
if (err)
return err;
- return mlxsw_sp_flower_parse_actions(mlxsw_sp, dev, rulei, f->exts);
+ return mlxsw_sp_flower_parse_actions(mlxsw_sp, dev, ingress,
+ rulei, f->exts);
}
int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
@@ -390,7 +405,7 @@ int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
}
rulei = mlxsw_sp_acl_rule_rulei(rule);
- err = mlxsw_sp_flower_parse(mlxsw_sp, dev, rulei, f);
+ err = mlxsw_sp_flower_parse(mlxsw_sp, dev, ingress, rulei, f);
if (err)
goto err_flower_parse;
--
2.9.3
^ permalink raw reply related
* [patch net-next 4/5] mlxsw: spectrum_acl: Provide helper to lookup ruleset
From: Jiri Pirko @ 2017-08-23 8:08 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, jhs, xiyou.wangcong
In-Reply-To: <20170823080652.14847-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
We need to lookup ruleset in order to offload goto_chain termination
action. This patch adds it.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 4 ++
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 45 ++++++++++++++++++----
2 files changed, 41 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 1866f69..f8c7f7e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -441,6 +441,10 @@ struct mlxsw_sp_acl_ruleset;
/* spectrum_acl.c */
struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl);
struct mlxsw_sp_acl_ruleset *
+mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
+ bool ingress, u32 chain_index,
+ enum mlxsw_sp_acl_profile profile);
+struct mlxsw_sp_acl_ruleset *
mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
bool ingress, u32 chain_index,
enum mlxsw_sp_acl_profile profile);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
index ef86f04..4b2455e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -221,6 +221,41 @@ static void mlxsw_sp_acl_ruleset_ref_dec(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_acl_ruleset_destroy(mlxsw_sp, ruleset);
}
+static struct mlxsw_sp_acl_ruleset *
+__mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp_acl *acl, struct net_device *dev,
+ bool ingress, u32 chain_index,
+ const struct mlxsw_sp_acl_profile_ops *ops)
+{
+ struct mlxsw_sp_acl_ruleset_ht_key ht_key;
+
+ memset(&ht_key, 0, sizeof(ht_key));
+ ht_key.dev = dev;
+ ht_key.ingress = ingress;
+ ht_key.chain_index = chain_index;
+ ht_key.ops = ops;
+ return rhashtable_lookup_fast(&acl->ruleset_ht, &ht_key,
+ mlxsw_sp_acl_ruleset_ht_params);
+}
+
+struct mlxsw_sp_acl_ruleset *
+mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
+ bool ingress, u32 chain_index,
+ enum mlxsw_sp_acl_profile profile)
+{
+ const struct mlxsw_sp_acl_profile_ops *ops;
+ struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
+ struct mlxsw_sp_acl_ruleset *ruleset;
+
+ ops = acl->ops->profile_ops(mlxsw_sp, profile);
+ if (!ops)
+ return ERR_PTR(-EINVAL);
+ ruleset = __mlxsw_sp_acl_ruleset_lookup(acl, dev, ingress,
+ chain_index, ops);
+ if (!ruleset)
+ return ERR_PTR(-ENOENT);
+ return ruleset;
+}
+
struct mlxsw_sp_acl_ruleset *
mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
bool ingress, u32 chain_index,
@@ -228,7 +263,6 @@ mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
{
const struct mlxsw_sp_acl_profile_ops *ops;
struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
- struct mlxsw_sp_acl_ruleset_ht_key ht_key;
struct mlxsw_sp_acl_ruleset *ruleset;
int err;
@@ -236,13 +270,8 @@ mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
if (!ops)
return ERR_PTR(-EINVAL);
- memset(&ht_key, 0, sizeof(ht_key));
- ht_key.dev = dev;
- ht_key.ingress = ingress;
- ht_key.chain_index = chain_index;
- ht_key.ops = ops;
- ruleset = rhashtable_lookup_fast(&acl->ruleset_ht, &ht_key,
- mlxsw_sp_acl_ruleset_ht_params);
+ ruleset = __mlxsw_sp_acl_ruleset_lookup(acl, dev, ingress,
+ chain_index, ops);
if (ruleset) {
mlxsw_sp_acl_ruleset_ref_inc(ruleset);
return ruleset;
--
2.9.3
^ permalink raw reply related
* [patch net-next 3/5] mlxsw: spectrum_acl: Allow to get group_id value for a ruleset
From: Jiri Pirko @ 2017-08-23 8:08 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, jhs, xiyou.wangcong
In-Reply-To: <20170823080652.14847-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
For goto_chain action we need to know group_id of a ruleset to jump to.
Provide infrastructure in order to get it.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 ++
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 7 +++++++
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 15 +++++++++++++++
3 files changed, 24 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index de3aef9..1866f69 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -417,6 +417,7 @@ struct mlxsw_sp_acl_profile_ops {
int (*ruleset_bind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv,
struct net_device *dev, bool ingress);
void (*ruleset_unbind)(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv);
+ u16 (*ruleset_group_id)(void *ruleset_priv);
size_t rule_priv_size;
int (*rule_add)(struct mlxsw_sp *mlxsw_sp,
void *ruleset_priv, void *rule_priv,
@@ -445,6 +446,7 @@ mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
enum mlxsw_sp_acl_profile profile);
void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_ruleset *ruleset);
+u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset);
struct mlxsw_sp_acl_rule_info *
mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
index 8ab331b..ef86f04 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -267,6 +267,13 @@ void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset);
}
+u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset)
+{
+ const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
+
+ return ops->ruleset_group_id(ruleset->priv);
+}
+
static int
mlxsw_sp_acl_rulei_counter_alloc(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index bc5173f..50b40de 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -295,6 +295,12 @@ mlxsw_sp_acl_tcam_group_unbind(struct mlxsw_sp *mlxsw_sp,
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ppbt), ppbt_pl);
}
+static u16
+mlxsw_sp_acl_tcam_group_id(struct mlxsw_sp_acl_tcam_group *group)
+{
+ return group->id;
+}
+
static unsigned int
mlxsw_sp_acl_tcam_region_prio(struct mlxsw_sp_acl_tcam_region *region)
{
@@ -1063,6 +1069,14 @@ mlxsw_sp_acl_tcam_flower_ruleset_unbind(struct mlxsw_sp *mlxsw_sp,
mlxsw_sp_acl_tcam_group_unbind(mlxsw_sp, &ruleset->group);
}
+static u16
+mlxsw_sp_acl_tcam_flower_ruleset_group_id(void *ruleset_priv)
+{
+ struct mlxsw_sp_acl_tcam_flower_ruleset *ruleset = ruleset_priv;
+
+ return mlxsw_sp_acl_tcam_group_id(&ruleset->group);
+}
+
static int
mlxsw_sp_acl_tcam_flower_rule_add(struct mlxsw_sp *mlxsw_sp,
void *ruleset_priv, void *rule_priv,
@@ -1099,6 +1113,7 @@ static const struct mlxsw_sp_acl_profile_ops mlxsw_sp_acl_tcam_flower_ops = {
.ruleset_del = mlxsw_sp_acl_tcam_flower_ruleset_del,
.ruleset_bind = mlxsw_sp_acl_tcam_flower_ruleset_bind,
.ruleset_unbind = mlxsw_sp_acl_tcam_flower_ruleset_unbind,
+ .ruleset_group_id = mlxsw_sp_acl_tcam_flower_ruleset_group_id,
.rule_priv_size = sizeof(struct mlxsw_sp_acl_tcam_flower_rule),
.rule_add = mlxsw_sp_acl_tcam_flower_rule_add,
.rule_del = mlxsw_sp_acl_tcam_flower_rule_del,
--
2.9.3
^ permalink raw reply related
* [patch net-next 2/5] net: sched: add couple of goto_chain helpers
From: Jiri Pirko @ 2017-08-23 8:08 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, jhs, xiyou.wangcong
In-Reply-To: <20170823080652.14847-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Add helpers to find out if a gact instance is goto_chain termination
action and to get chain index.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/tc_act/tc_gact.h | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/include/net/tc_act/tc_gact.h b/include/net/tc_act/tc_gact.h
index d576374..41afe1c 100644
--- a/include/net/tc_act/tc_gact.h
+++ b/include/net/tc_act/tc_gact.h
@@ -15,7 +15,8 @@ struct tcf_gact {
};
#define to_gact(a) ((struct tcf_gact *)a)
-static inline bool __is_tcf_gact_act(const struct tc_action *a, int act)
+static inline bool __is_tcf_gact_act(const struct tc_action *a, int act,
+ bool is_ext)
{
#ifdef CONFIG_NET_CLS_ACT
struct tcf_gact *gact;
@@ -24,7 +25,8 @@ static inline bool __is_tcf_gact_act(const struct tc_action *a, int act)
return false;
gact = to_gact(a);
- if (gact->tcf_action == act)
+ if ((!is_ext && gact->tcf_action == act) ||
+ (is_ext && TC_ACT_EXT_CMP(gact->tcf_action, act)))
return true;
#endif
@@ -33,12 +35,22 @@ static inline bool __is_tcf_gact_act(const struct tc_action *a, int act)
static inline bool is_tcf_gact_shot(const struct tc_action *a)
{
- return __is_tcf_gact_act(a, TC_ACT_SHOT);
+ return __is_tcf_gact_act(a, TC_ACT_SHOT, false);
}
static inline bool is_tcf_gact_trap(const struct tc_action *a)
{
- return __is_tcf_gact_act(a, TC_ACT_TRAP);
+ return __is_tcf_gact_act(a, TC_ACT_TRAP, false);
+}
+
+static inline bool is_tcf_gact_goto_chain(const struct tc_action *a)
+{
+ return __is_tcf_gact_act(a, TC_ACT_GOTO_CHAIN, true);
+}
+
+static inline u32 tcf_gact_goto_chain_index(const struct tc_action *a)
+{
+ return a->goto_chain->index;
}
#endif /* __NET_TC_GACT_H */
--
2.9.3
^ permalink raw reply related
* [patch net-next 1/5] mlxsw: spectrum: Offload multichain TC rules
From: Jiri Pirko @ 2017-08-23 8:08 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, jhs, xiyou.wangcong
In-Reply-To: <20170823080652.14847-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Reflect chain index coming down from TC core and create a ruleset per
chain. Note that only chain 0, being the implicit chain, is bound to the
device for processing. The rest of chains have to be "jumped-to" by
actions.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 3 ---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 4 ++--
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 28 +++++++++++++++-------
.../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 5 ++--
4 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 90a95cd..6e641db 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1733,9 +1733,6 @@ mlxsw_sp_setup_tc_cls_flower(struct mlxsw_sp_port *mlxsw_sp_port,
else
return -EOPNOTSUPP;
- if (f->common.chain_index)
- return -EOPNOTSUPP;
-
switch (f->command) {
case TC_CLSFLOWER_REPLACE:
return mlxsw_sp_flower_replace(mlxsw_sp_port, ingress, f);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 8452d1d..de3aef9 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -440,8 +440,8 @@ struct mlxsw_sp_acl_ruleset;
/* spectrum_acl.c */
struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl);
struct mlxsw_sp_acl_ruleset *
-mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp,
- struct net_device *dev, bool ingress,
+mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
+ bool ingress, u32 chain_index,
enum mlxsw_sp_acl_profile profile);
void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_ruleset *ruleset);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
index 508b5fc..8ab331b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -74,6 +74,7 @@ struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl)
struct mlxsw_sp_acl_ruleset_ht_key {
struct net_device *dev; /* dev this ruleset is bound to */
bool ingress;
+ u32 chain_index;
const struct mlxsw_sp_acl_profile_ops *ops;
};
@@ -163,7 +164,8 @@ static void mlxsw_sp_acl_ruleset_destroy(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_acl_ruleset_bind(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_ruleset *ruleset,
- struct net_device *dev, bool ingress)
+ struct net_device *dev, bool ingress,
+ u32 chain_index)
{
const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
@@ -171,13 +173,20 @@ static int mlxsw_sp_acl_ruleset_bind(struct mlxsw_sp *mlxsw_sp,
ruleset->ht_key.dev = dev;
ruleset->ht_key.ingress = ingress;
+ ruleset->ht_key.chain_index = chain_index;
err = rhashtable_insert_fast(&acl->ruleset_ht, &ruleset->ht_node,
mlxsw_sp_acl_ruleset_ht_params);
if (err)
return err;
- err = ops->ruleset_bind(mlxsw_sp, ruleset->priv, dev, ingress);
- if (err)
- goto err_ops_ruleset_bind;
+ if (!ruleset->ht_key.chain_index) {
+ /* We only need ruleset with chain index 0, the implicit one,
+ * to be directly bound to device. The rest of the rulesets
+ * are bound by "Goto action set".
+ */
+ err = ops->ruleset_bind(mlxsw_sp, ruleset->priv, dev, ingress);
+ if (err)
+ goto err_ops_ruleset_bind;
+ }
return 0;
err_ops_ruleset_bind:
@@ -192,7 +201,8 @@ static void mlxsw_sp_acl_ruleset_unbind(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
- ops->ruleset_unbind(mlxsw_sp, ruleset->priv);
+ if (!ruleset->ht_key.chain_index)
+ ops->ruleset_unbind(mlxsw_sp, ruleset->priv);
rhashtable_remove_fast(&acl->ruleset_ht, &ruleset->ht_node,
mlxsw_sp_acl_ruleset_ht_params);
}
@@ -212,8 +222,8 @@ static void mlxsw_sp_acl_ruleset_ref_dec(struct mlxsw_sp *mlxsw_sp,
}
struct mlxsw_sp_acl_ruleset *
-mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp,
- struct net_device *dev, bool ingress,
+mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp, struct net_device *dev,
+ bool ingress, u32 chain_index,
enum mlxsw_sp_acl_profile profile)
{
const struct mlxsw_sp_acl_profile_ops *ops;
@@ -229,6 +239,7 @@ mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp,
memset(&ht_key, 0, sizeof(ht_key));
ht_key.dev = dev;
ht_key.ingress = ingress;
+ ht_key.chain_index = chain_index;
ht_key.ops = ops;
ruleset = rhashtable_lookup_fast(&acl->ruleset_ht, &ht_key,
mlxsw_sp_acl_ruleset_ht_params);
@@ -239,7 +250,8 @@ mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp,
ruleset = mlxsw_sp_acl_ruleset_create(mlxsw_sp, ops);
if (IS_ERR(ruleset))
return ruleset;
- err = mlxsw_sp_acl_ruleset_bind(mlxsw_sp, ruleset, dev, ingress);
+ err = mlxsw_sp_acl_ruleset_bind(mlxsw_sp, ruleset, dev,
+ ingress, chain_index);
if (err)
goto err_ruleset_bind;
return ruleset;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
index 95428b4..34872aa 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
@@ -378,6 +378,7 @@ int mlxsw_sp_flower_replace(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
int err;
ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, dev, ingress,
+ f->common.chain_index,
MLXSW_SP_ACL_PROFILE_FLOWER);
if (IS_ERR(ruleset))
return PTR_ERR(ruleset);
@@ -421,7 +422,7 @@ void mlxsw_sp_flower_destroy(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
struct mlxsw_sp_acl_rule *rule;
ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, mlxsw_sp_port->dev,
- ingress,
+ ingress, f->common.chain_index,
MLXSW_SP_ACL_PROFILE_FLOWER);
if (IS_ERR(ruleset))
return;
@@ -447,7 +448,7 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
int err;
ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, mlxsw_sp_port->dev,
- ingress,
+ ingress, f->common.chain_index,
MLXSW_SP_ACL_PROFILE_FLOWER);
if (WARN_ON(IS_ERR(ruleset)))
return -EINVAL;
--
2.9.3
^ permalink raw reply related
* [patch net-next 0/5] mlxsw: spectrum: Introduce multichain TC offload
From: Jiri Pirko @ 2017-08-23 8:06 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw, jhs, xiyou.wangcong
From: Jiri Pirko <jiri@mellanox.com>
This patchset introduces offloading of rules added to chain with
non-zero index, which was previously forbidden. Also, goto_chain
termination action is offloaded allowing to jump to processing
of desired chain.
Jiri Pirko (5):
mlxsw: spectrum: Offload multichain TC rules
net: sched: add couple of goto_chain helpers
mlxsw: spectrum_acl: Allow to get group_id value for a ruleset
mlxsw: spectrum_acl: Provide helper to lookup ruleset
mlxsw: spectrum_flower: Offload goto_chain termination action
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 3 -
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 10 ++-
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 78 +++++++++++++++++-----
.../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 15 +++++
.../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 28 ++++++--
include/net/tc_act/tc_gact.h | 20 ++++--
6 files changed, 124 insertions(+), 30 deletions(-)
--
2.9.3
^ permalink raw reply
* [PATCH net-next v3 4/4] ipv6: Use multipath hash from flow info if available
From: Jakub Sitnicki @ 2017-08-23 7:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Hannes Frederic Sowa, Nikolay Aleksandrov,
Tom Herbert
In-Reply-To: <20170823075831.27031-1-jkbs@redhat.com>
Allow our callers to influence the choice of ECMP link by honoring the
hash passed together with the flow info. This allows for special
treatment of ICMP errors which we would like to route over the same path
as the IPv6 datagram that triggered the error.
Also go through rt6_multipath_hash(), in the usual case when we aren't
dealing with an ICMP error, so that there is one central place where
multipath hash is computed.
Signed-off-by: Jakub Sitnicki <jkbs@redhat.com>
---
net/ipv6/route.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 246e7d7..4d02734 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -452,7 +452,13 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
struct rt6_info *sibling, *next_sibling;
int route_choosen;
- route_choosen = get_hash_from_flowi6(fl6) % (match->rt6i_nsiblings + 1);
+ /* We might have already computed the hash for ICMPv6 errors. In such
+ * case it will always be non-zero. Otherwise now is the time to do it.
+ */
+ if (!fl6->mp_hash)
+ fl6->mp_hash = rt6_multipath_hash(fl6, NULL);
+
+ route_choosen = fl6->mp_hash % (match->rt6i_nsiblings + 1);
/* Don't change the route, if route_choosen == 0
* (siblings does not include ourself)
*/
--
2.9.4
^ permalink raw reply related
* [PATCH net-next v3 3/4] ipv6: Fold rt6_info_hash_nhsfn() into its only caller
From: Jakub Sitnicki @ 2017-08-23 7:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Hannes Frederic Sowa, Nikolay Aleksandrov,
Tom Herbert
In-Reply-To: <20170823075831.27031-1-jkbs@redhat.com>
Commit 644d0e656958 ("ipv6 Use get_hash_from_flowi6 for rt6 hash") has
turned rt6_info_hash_nhsfn() into a one-liner, so it no longer makes
sense to keep it around. Also remove the accompanying comment that has
become outdated.
Signed-off-by: Jakub Sitnicki <jkbs@redhat.com>
---
net/ipv6/route.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 6c4dd57..246e7d7 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -445,16 +445,6 @@ static bool rt6_check_expired(const struct rt6_info *rt)
return false;
}
-/* Multipath route selection:
- * Hash based function using packet header and flowlabel.
- * Adapted from fib_info_hashfn()
- */
-static int rt6_info_hash_nhsfn(unsigned int candidate_count,
- const struct flowi6 *fl6)
-{
- return get_hash_from_flowi6(fl6) % candidate_count;
-}
-
static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
struct flowi6 *fl6, int oif,
int strict)
@@ -462,7 +452,7 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
struct rt6_info *sibling, *next_sibling;
int route_choosen;
- route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
+ route_choosen = get_hash_from_flowi6(fl6) % (match->rt6i_nsiblings + 1);
/* Don't change the route, if route_choosen == 0
* (siblings does not include ourself)
*/
--
2.9.4
^ permalink raw reply related
* [PATCH net-next v3 2/4] ipv6: Compute multipath hash for ICMP errors from offending packet
From: Jakub Sitnicki @ 2017-08-23 7:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Hannes Frederic Sowa, Nikolay Aleksandrov,
Tom Herbert
In-Reply-To: <20170823075831.27031-1-jkbs@redhat.com>
When forwarding or sending out an ICMPv6 error, look at the embedded
packet that triggered the error and compute a flow hash over its
headers.
This let's us route the ICMP error together with the flow it belongs to
when multipath (ECMP) routing is in use, which in turn makes Path MTU
Discovery work in ECMP load-balanced or anycast setups (RFC 7690).
Granted, end-hosts behind the ECMP router (aka servers) need to reflect
the IPv6 Flow Label for PMTUD to work.
The code is organized to be in parallel with ipv4 stack:
ip_multipath_l3_keys -> ip6_multipath_l3_keys
fib_multipath_hash -> rt6_multipath_hash
Signed-off-by: Jakub Sitnicki <jkbs@redhat.com>
---
include/net/ip6_route.h | 1 +
net/ipv6/icmp.c | 1 +
net/ipv6/route.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 52 insertions(+)
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 907d39a..882bc3c 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -115,6 +115,7 @@ static inline int ip6_route_get_saddr(struct net *net, struct rt6_info *rt,
struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
const struct in6_addr *saddr, int oif, int flags);
+u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb);
struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct flowi6 *fl6);
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 4f82830..dd7608c 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -519,6 +519,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
fl6.fl6_icmp_type = type;
fl6.fl6_icmp_code = code;
fl6.flowi6_uid = sock_net_uid(net, NULL);
+ fl6.mp_hash = rt6_multipath_hash(&fl6, skb);
security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
sk = icmpv6_xmit_lock(net);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 9b02064..6c4dd57 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1214,6 +1214,54 @@ struct dst_entry *ip6_route_input_lookup(struct net *net,
}
EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
+static void ip6_multipath_l3_keys(const struct sk_buff *skb,
+ struct flow_keys *keys)
+{
+ const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
+ const struct ipv6hdr *key_iph = outer_iph;
+ const struct ipv6hdr *inner_iph;
+ const struct icmp6hdr *icmph;
+ struct ipv6hdr _inner_iph;
+
+ if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
+ goto out;
+
+ icmph = icmp6_hdr(skb);
+ if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
+ icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
+ icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
+ icmph->icmp6_type != ICMPV6_PARAMPROB)
+ goto out;
+
+ inner_iph = skb_header_pointer(skb,
+ skb_transport_offset(skb) + sizeof(*icmph),
+ sizeof(_inner_iph), &_inner_iph);
+ if (!inner_iph)
+ goto out;
+
+ key_iph = inner_iph;
+out:
+ memset(keys, 0, sizeof(*keys));
+ keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+ keys->addrs.v6addrs.src = key_iph->saddr;
+ keys->addrs.v6addrs.dst = key_iph->daddr;
+ keys->tags.flow_label = ip6_flowinfo(key_iph);
+ keys->basic.ip_proto = key_iph->nexthdr;
+}
+
+/* if skb is set it will be used and fl6 can be NULL */
+u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb)
+{
+ struct flow_keys hash_keys;
+
+ if (skb) {
+ ip6_multipath_l3_keys(skb, &hash_keys);
+ return flow_hash_from_keys(&hash_keys);
+ }
+
+ return get_hash_from_flowi6(fl6);
+}
+
void ip6_route_input(struct sk_buff *skb)
{
const struct ipv6hdr *iph = ipv6_hdr(skb);
@@ -1232,6 +1280,8 @@ void ip6_route_input(struct sk_buff *skb)
tun_info = skb_tunnel_info(skb);
if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
+ if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
+ fl6.mp_hash = rt6_multipath_hash(&fl6, skb);
skb_dst_drop(skb);
skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
}
--
2.9.4
^ permalink raw reply related
* [PATCH net-next v3 1/4] net: Extend struct flowi6 with multipath hash
From: Jakub Sitnicki @ 2017-08-23 7:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Hannes Frederic Sowa, Nikolay Aleksandrov,
Tom Herbert
In-Reply-To: <20170823075831.27031-1-jkbs@redhat.com>
Allow for functions that fill out the IPv6 flow info to also pass a hash
computed over the skb contents. The hash value will drive the multipath
routing decisions.
This is intended for special treatment of ICMPv6 errors, where we would
like to make a routing decision based on the flow identifying the
offending IPv6 datagram that triggered the error, rather than the flow
of the ICMP error itself.
Signed-off-by: Jakub Sitnicki <jkbs@redhat.com>
---
include/net/flow.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/net/flow.h b/include/net/flow.h
index f3dc61b..eb60cee3 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -149,6 +149,7 @@ struct flowi6 {
#define fl6_ipsec_spi uli.spi
#define fl6_mh_type uli.mht.type
#define fl6_gre_key uli.gre_key
+ __u32 mp_hash;
} __attribute__((__aligned__(BITS_PER_LONG/8)));
struct flowidn {
--
2.9.4
^ permalink raw reply related
* [PATCH net-next v3 0/4] Route ICMPv6 errors with the flow when ECMP in use
From: Jakub Sitnicki @ 2017-08-23 7:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Hannes Frederic Sowa, Nikolay Aleksandrov,
Tom Herbert
This patch set is another take at making Path MTU Discovery work when
server nodes are behind a router employing multipath routing in a
load-balance or anycast setup (that is, when not every end-node can be
reached by every path). The problem has been well described in RFC 7690
[1], but in short - in such setups ICMPv6 PTB errors are not guaranteed
to be routed back to the server node that sent a reply that exceeds path
MTU.
The proposed solution is two-fold:
(1) on the server side - reflect the Flow Label [2]. This can be done
without modifying the application using a new per-netns sysctl knob
that has been proposed independently of this patchset in the patch
entitled "ipv6: Add sysctl for per namespace flow label
reflection" [3].
(2) on the ECMP router - make the ipv6 routing subsystem look into the
ICMPv6 error packets and compute the flow-hash from its payload,
i.e. the offending packet that triggered the error. This is the
same behavior as ipv4 stack has already.
With both parts in place Path MTU Discovery can work past the ECMP
router when using IPv6.
[1] https://tools.ietf.org/html/rfc7690
[2] https://tools.ietf.org/html/draft-wang-6man-flow-label-reflection-01
[3] http://patchwork.ozlabs.org/patch/804870/
v1 -> v2:
- don't use "extern" in external function declaration in header file
- style change, put as many arguments as possible on the first line of
a function call, and align consecutive lines to the first argument
- expand the cover letter based on the feedback
v2 -> v3:
- switch to computing flow-hash using flow dissector to align with
recent changes to multipath routing in ipv4 stack
- add a sysctl knob for enabling flow label reflection per netns
---
Testing has covered multipath routing of ICMPv6 PTB errors in forward
and local output path in a simple use-case of an HTTP server sending a
reply which is over the path MTU size [3]. I have also checked if the
flows get evenly spread over multiple paths (i.e. if there are no
regressions) [4].
[3] https://github.com/jsitnicki/tools/tree/master/net/tests/ecmp/pmtud
[4] https://github.com/jsitnicki/tools/tree/master/net/tests/ecmp/load-balance
Jakub Sitnicki (4):
net: Extend struct flowi6 with multipath hash
ipv6: Compute multipath hash for ICMP errors from offending packet
ipv6: Fold rt6_info_hash_nhsfn() into its only caller
ipv6: Use multipath hash from flow info if available
include/net/flow.h | 1 +
include/net/ip6_route.h | 1 +
net/ipv6/icmp.c | 1 +
net/ipv6/route.c | 68 +++++++++++++++++++++++++++++++++++++++++--------
4 files changed, 60 insertions(+), 11 deletions(-)
--
2.9.4
^ permalink raw reply
* [PATCH net-next] ipv6: Add sysctl for per namespace flow label reflection
From: Jakub Sitnicki @ 2017-08-23 7:55 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Hannes Frederic Sowa, Nikolay Aleksandrov,
Tom Herbert
Reflecting IPv6 Flow Label at server nodes is useful in environments
that employ multipath routing to load balance the requests. As "IPv6
Flow Label Reflection" standard draft [1] points out - ICMPv6 PTB error
messages generated in response to a downstream packets from the server
can be routed by a load balancer back to the original server without
looking at transport headers, if the server applies the flow label
reflection. This enables the Path MTU Discovery past the ECMP router in
load-balance or anycast environments where each server node is reachable
by only one path.
Introduce a sysctl to enable flow label reflection per net namespace for
all newly created sockets. Same could be earlier achieved only per
socket by setting the IPV6_FL_F_REFLECT flag for the IPV6_FLOWLABEL_MGR
socket option.
[1] https://tools.ietf.org/html/draft-wang-6man-flow-label-reflection-01
Signed-off-by: Jakub Sitnicki <jkbs@redhat.com>
---
Documentation/networking/ip-sysctl.txt | 9 +++++++++
include/net/netns/ipv6.h | 1 +
net/ipv6/af_inet6.c | 1 +
net/ipv6/sysctl_net_ipv6.c | 8 ++++++++
4 files changed, 19 insertions(+)
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 84c9b8c..6b0bc0f 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1350,6 +1350,15 @@ flowlabel_state_ranges - BOOLEAN
FALSE: disabled
Default: true
+flowlabel_reflect - BOOLEAN
+ Automatically reflect the flow label. Needed for Path MTU
+ Discovery to work with Equal Cost Multipath Routing in anycast
+ environments. See RFC 7690 and:
+ https://tools.ietf.org/html/draft-wang-6man-flow-label-reflection-01
+ TRUE: enabled
+ FALSE: disabled
+ Default: FALSE
+
anycast_src_echo_reply - BOOLEAN
Controls the use of anycast addresses as source addresses for ICMPv6
echo reply
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 0e50bf3..2544f97 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -36,6 +36,7 @@ struct netns_sysctl_ipv6 {
int idgen_retries;
int idgen_delay;
int flowlabel_state_ranges;
+ int flowlabel_reflect;
};
struct netns_ipv6 {
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 3b58ee7..fe5262f 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -211,6 +211,7 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
np->mc_loop = 1;
np->pmtudisc = IPV6_PMTUDISC_WANT;
np->autoflowlabel = ip6_default_np_autolabel(net);
+ np->repflow = net->ipv6.sysctl.flowlabel_reflect;
sk->sk_ipv6only = net->ipv6.sysctl.bindv6only;
/* Init the ipv4 part of the socket since we can have sockets
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 69c50e7..6fbf8ae 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -90,6 +90,13 @@ static struct ctl_table ipv6_table_template[] = {
.mode = 0644,
.proc_handler = proc_dointvec
},
+ {
+ .procname = "flowlabel_reflect",
+ .data = &init_net.ipv6.sysctl.flowlabel_reflect,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
{ }
};
@@ -149,6 +156,7 @@ static int __net_init ipv6_sysctl_net_init(struct net *net)
ipv6_table[6].data = &net->ipv6.sysctl.idgen_delay;
ipv6_table[7].data = &net->ipv6.sysctl.flowlabel_state_ranges;
ipv6_table[8].data = &net->ipv6.sysctl.ip_nonlocal_bind;
+ ipv6_table[9].data = &net->ipv6.sysctl.flowlabel_reflect;
ipv6_route_table = ipv6_route_sysctl_init(net);
if (!ipv6_route_table)
--
2.9.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox