* [patch net-next 11/16] mlxsw: switchx2: Add Infiniband switch partition
From: Jiri Pirko @ 2016-10-28 19:35 UTC (permalink / raw)
To: netdev; +Cc: davem, eladr, idosch, yotamg, nogahf, ogerlitz
In-Reply-To: <1477683361-8011-1-git-send-email-jiri@resnulli.us>
From: Elad Raz <eladr@mellanox.com>
In order to put a port in Infiniband fabric it should be assigned
to separate swid (Switch partition) that initialized as IB swid.
Signed-off-by: Elad Raz <eladr@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/port.h | 1 +
drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 6 +++++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/port.h b/drivers/net/ethernet/mellanox/mlxsw/port.h
index af371a8..7296071 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/port.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/port.h
@@ -44,6 +44,7 @@
#define MLXSW_PORT_SWID_DISABLED_PORT 255
#define MLXSW_PORT_SWID_ALL_SWIDS 254
+#define MLXSW_PORT_SWID_TYPE_IB 1
#define MLXSW_PORT_SWID_TYPE_ETH 2
#define MLXSW_PORT_MID 0xd000
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
index 8eac26f..a905589 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
@@ -1590,13 +1590,17 @@ static struct mlxsw_config_profile mlxsw_sx_config_profile = {
.used_flood_mode = 1,
.flood_mode = 3,
.used_max_ib_mc = 1,
- .max_ib_mc = 0,
+ .max_ib_mc = 6,
.used_max_pkey = 1,
.max_pkey = 0,
.swid_config = {
{
.used_type = 1,
.type = MLXSW_PORT_SWID_TYPE_ETH,
+ },
+ {
+ .used_type = 1,
+ .type = MLXSW_PORT_SWID_TYPE_IB,
}
},
.resource_query_enable = 0,
--
2.5.5
^ permalink raw reply related
* [patch net-next 12/16] mlxsw: core: Add "eth" prefix to mlxsw_core_port_set
From: Jiri Pirko @ 2016-10-28 19:35 UTC (permalink / raw)
To: netdev; +Cc: davem, eladr, idosch, yotamg, nogahf, ogerlitz
In-Reply-To: <1477683361-8011-1-git-send-email-jiri@resnulli.us>
From: Elad Raz <eladr@mellanox.com>
Since we are about to introduce IB port APIs, we will add prefixes to
existing APIs.
Signed-off-by: Elad Raz <eladr@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/core.c | 8 ++++----
drivers/net/ethernet/mellanox/mlxsw/core.h | 6 +++---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 5 +++--
drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 4 ++--
4 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index b50acb1..dcd7202 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -1705,9 +1705,9 @@ void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port)
}
EXPORT_SYMBOL(mlxsw_core_port_fini);
-void mlxsw_core_port_set(struct mlxsw_core *mlxsw_core, u8 local_port,
- void *port_driver_priv, struct net_device *dev,
- bool split, u32 split_group)
+void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
+ void *port_driver_priv, struct net_device *dev,
+ bool split, u32 split_group)
{
struct mlxsw_core_port *mlxsw_core_port =
&mlxsw_core->ports[local_port];
@@ -1718,7 +1718,7 @@ void mlxsw_core_port_set(struct mlxsw_core *mlxsw_core, u8 local_port,
devlink_port_split_set(devlink_port, split_group);
devlink_port_type_eth_set(devlink_port, dev);
}
-EXPORT_SYMBOL(mlxsw_core_port_set);
+EXPORT_SYMBOL(mlxsw_core_port_eth_set);
void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u8 local_port,
void *port_driver_priv)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index f4bbbd4..82866d5 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -145,9 +145,9 @@ void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core,
void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port);
int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port);
void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port);
-void mlxsw_core_port_set(struct mlxsw_core *mlxsw_core, u8 local_port,
- void *port_driver_priv, struct net_device *dev,
- bool split, u32 split_group);
+void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
+ void *port_driver_priv, struct net_device *dev,
+ bool split, u32 split_group);
void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u8 local_port,
void *port_driver_priv);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index ad4ff27..8bca020 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -2358,8 +2358,9 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
goto err_register_netdev;
}
- mlxsw_core_port_set(mlxsw_sp->core, mlxsw_sp_port->local_port,
- mlxsw_sp_port, dev, mlxsw_sp_port->split, module);
+ mlxsw_core_port_eth_set(mlxsw_sp->core, mlxsw_sp_port->local_port,
+ mlxsw_sp_port, dev, mlxsw_sp_port->split,
+ module);
mlxsw_core_schedule_dw(&mlxsw_sp_port->hw_stats.update_dw, 0);
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
index a905589..d110e3f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
@@ -1098,8 +1098,8 @@ static int __mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
goto err_register_netdev;
}
- mlxsw_core_port_set(mlxsw_sx->core, mlxsw_sx_port->local_port,
- mlxsw_sx_port, dev, false, 0);
+ mlxsw_core_port_eth_set(mlxsw_sx->core, mlxsw_sx_port->local_port,
+ mlxsw_sx_port, dev, false, 0);
mlxsw_sx->ports[local_port] = mlxsw_sx_port;
return 0;
--
2.5.5
^ permalink raw reply related
* [patch net-next 13/16] mlxsw: core: Add port type (Eth/IB) set API
From: Jiri Pirko @ 2016-10-28 19:35 UTC (permalink / raw)
To: netdev; +Cc: davem, eladr, idosch, yotamg, nogahf, ogerlitz
In-Reply-To: <1477683361-8011-1-git-send-email-jiri@resnulli.us>
From: Elad Raz <eladr@mellanox.com>
Add "port_type_set" API to mlxsw core. The core layer send the change type
callback to the port along with it's private information.
Signed-off-by: Elad Raz <eladr@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/core.c | 41 ++++++++++++++++++++++++++++++
drivers/net/ethernet/mellanox/mlxsw/core.h | 6 +++++
2 files changed, 47 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index dcd7202..6004817 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -93,6 +93,7 @@ struct mlxsw_core_pcpu_stats {
struct mlxsw_core_port {
struct devlink_port devlink_port;
void *port_driver_priv;
+ u8 local_port;
};
void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port)
@@ -937,6 +938,21 @@ static void *__dl_port(struct devlink_port *devlink_port)
return container_of(devlink_port, struct mlxsw_core_port, devlink_port);
}
+static int mlxsw_devlink_port_type_set(struct devlink_port *devlink_port,
+ enum devlink_port_type port_type)
+{
+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink);
+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver;
+ struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port);
+
+ if (!mlxsw_driver->port_type_set)
+ return -EOPNOTSUPP;
+
+ return mlxsw_driver->port_type_set(mlxsw_core,
+ mlxsw_core_port->local_port,
+ port_type);
+}
+
static int mlxsw_devlink_sb_port_pool_get(struct devlink_port *devlink_port,
unsigned int sb_index, u16 pool_index,
u32 *p_threshold)
@@ -1060,6 +1076,7 @@ mlxsw_devlink_sb_occ_tc_port_bind_get(struct devlink_port *devlink_port,
}
static const struct devlink_ops mlxsw_devlink_ops = {
+ .port_type_set = mlxsw_devlink_port_type_set,
.port_split = mlxsw_devlink_port_split,
.port_unsplit = mlxsw_devlink_port_unsplit,
.sb_pool_get = mlxsw_devlink_sb_pool_get,
@@ -1687,6 +1704,7 @@ int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port)
struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
int err;
+ mlxsw_core_port->local_port = local_port;
err = devlink_port_register(devlink, devlink_port, local_port);
if (err)
memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port));
@@ -1720,6 +1738,18 @@ void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
}
EXPORT_SYMBOL(mlxsw_core_port_eth_set);
+void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u8 local_port,
+ void *port_driver_priv)
+{
+ struct mlxsw_core_port *mlxsw_core_port =
+ &mlxsw_core->ports[local_port];
+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
+
+ mlxsw_core_port->port_driver_priv = port_driver_priv;
+ devlink_port_type_ib_set(devlink_port, NULL);
+}
+EXPORT_SYMBOL(mlxsw_core_port_ib_set);
+
void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u8 local_port,
void *port_driver_priv)
{
@@ -1732,6 +1762,17 @@ void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u8 local_port,
}
EXPORT_SYMBOL(mlxsw_core_port_clear);
+enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core,
+ u8 local_port)
+{
+ struct mlxsw_core_port *mlxsw_core_port =
+ &mlxsw_core->ports[local_port];
+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port;
+
+ return devlink_port->type;
+}
+EXPORT_SYMBOL(mlxsw_core_port_type_get);
+
static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core,
const char *buf, size_t size)
{
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index 82866d5..c0acc1b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -148,8 +148,12 @@ void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port);
void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port,
void *port_driver_priv, struct net_device *dev,
bool split, u32 split_group);
+void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u8 local_port,
+ void *port_driver_priv);
void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u8 local_port,
void *port_driver_priv);
+enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core,
+ u8 local_port);
int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay);
@@ -210,6 +214,8 @@ struct mlxsw_driver {
int (*init)(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info);
void (*fini)(struct mlxsw_core *mlxsw_core);
+ int (*port_type_set)(struct mlxsw_core *mlxsw_core, u8 local_port,
+ enum devlink_port_type new_type);
int (*port_split)(struct mlxsw_core *mlxsw_core, u8 local_port,
unsigned int count);
int (*port_unsplit)(struct mlxsw_core *mlxsw_core, u8 local_port);
--
2.5.5
^ permalink raw reply related
* [patch net-next 14/16] mlxsw: switchx2: Add eth prefix to port create and remove
From: Jiri Pirko @ 2016-10-28 19:35 UTC (permalink / raw)
To: netdev; +Cc: davem, eladr, idosch, yotamg, nogahf, ogerlitz
In-Reply-To: <1477683361-8011-1-git-send-email-jiri@resnulli.us>
From: Elad Raz <eladr@mellanox.com>
Since we are about to add Infiniband port remove and create we will add
"eth" prefix to port create and remove APIs.
Signed-off-by: Elad Raz <eladr@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
index d110e3f..3aa0948 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
@@ -994,8 +994,8 @@ mlxsw_sx_port_mac_learning_mode_set(struct mlxsw_sx_port *mlxsw_sx_port,
return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(spmlr), spmlr_pl);
}
-static int __mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
- u8 module, u8 width)
+static int __mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
+ u8 module, u8 width)
{
struct mlxsw_sx_port *mlxsw_sx_port;
struct net_device *dev;
@@ -1119,8 +1119,8 @@ static int __mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
return err;
}
-static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
- u8 module, u8 width)
+static int mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
+ u8 module, u8 width)
{
int err;
@@ -1130,7 +1130,7 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
local_port);
return err;
}
- err = __mlxsw_sx_port_create(mlxsw_sx, local_port, module, width);
+ err = __mlxsw_sx_port_eth_create(mlxsw_sx, local_port, module, width);
if (err)
goto err_port_create;
@@ -1141,7 +1141,7 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
return err;
}
-static void __mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
+static void __mlxsw_sx_port_eth_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
{
struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port];
@@ -1153,9 +1153,9 @@ static void __mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
free_netdev(mlxsw_sx_port->dev);
}
-static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
+static void mlxsw_sx_port_eth_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
{
- __mlxsw_sx_port_remove(mlxsw_sx, local_port);
+ __mlxsw_sx_port_eth_remove(mlxsw_sx, local_port);
mlxsw_core_port_fini(mlxsw_sx->core, local_port);
}
@@ -1170,7 +1170,7 @@ static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx)
for (i = 1; i < MLXSW_PORT_MAX_PORTS; i++)
if (mlxsw_sx_port_created(mlxsw_sx, i))
- mlxsw_sx_port_remove(mlxsw_sx, i);
+ mlxsw_sx_port_eth_remove(mlxsw_sx, i);
kfree(mlxsw_sx->ports);
}
@@ -1193,7 +1193,7 @@ static int mlxsw_sx_ports_create(struct mlxsw_sx *mlxsw_sx)
goto err_port_module_info_get;
if (!width)
continue;
- err = mlxsw_sx_port_create(mlxsw_sx, i, module, width);
+ err = mlxsw_sx_port_eth_create(mlxsw_sx, i, module, width);
if (err)
goto err_port_create;
}
@@ -1203,7 +1203,7 @@ static int mlxsw_sx_ports_create(struct mlxsw_sx *mlxsw_sx)
err_port_module_info_get:
for (i--; i >= 1; i--)
if (mlxsw_sx_port_created(mlxsw_sx, i))
- mlxsw_sx_port_remove(mlxsw_sx, i);
+ mlxsw_sx_port_eth_remove(mlxsw_sx, i);
kfree(mlxsw_sx->ports);
return err;
}
--
2.5.5
^ permalink raw reply related
* [patch net-next 15/16] mlxsw: switchx2: Add IB port support
From: Jiri Pirko @ 2016-10-28 19:36 UTC (permalink / raw)
To: netdev; +Cc: davem, eladr, idosch, yotamg, nogahf, ogerlitz
In-Reply-To: <1477683361-8011-1-git-send-email-jiri@resnulli.us>
From: Elad Raz <eladr@mellanox.com>
SwitchX-2 is IB capable device. This patch add a support to change the
port type between Ethernet and Infiniband.
When the port is set to IB, the FW implements the Subnet Management Agent
(SMA) manage the port. All port attributes can be control remotely by
the SM.
Usage:
$ devlink port show
pci/0000:03:00.0/1: type eth netdev eth0
pci/0000:03:00.0/3: type eth netdev eth1
pci/0000:03:00.0/5: type eth netdev eth2
pci/0000:03:00.0/6: type eth netdev eth3
pci/0000:03:00.0/8: type eth netdev eth4
$ devlink port set pci/0000:03:00.0/1 type ib
$ devlink port show
pci/0000:03:00.0/1: type ib
Signed-off-by: Elad Raz <eladr@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/ib.h | 39 +++++
drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 229 +++++++++++++++++++++++--
2 files changed, 249 insertions(+), 19 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlxsw/ib.h
diff --git a/drivers/net/ethernet/mellanox/mlxsw/ib.h b/drivers/net/ethernet/mellanox/mlxsw/ib.h
new file mode 100644
index 0000000..ce313aa
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/ib.h
@@ -0,0 +1,39 @@
+/*
+ * drivers/net/ethernet/mellanox/mlxsw/ib.h
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Elad Raz <eladr@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _MLXSW_IB_H
+#define _MLXSW_IB_H
+
+#define MLXSW_IB_DEFAULT_MTU 4096
+
+#endif /* _MLXSW_IB_H */
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
index 3aa0948..5208764 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c
@@ -3,7 +3,7 @@
* Copyright (c) 2015 Mellanox Technologies. All rights reserved.
* Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
* Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com>
- * Copyright (c) 2015 Elad Raz <eladr@mellanox.com>
+ * Copyright (c) 2015-2016 Elad Raz <eladr@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -53,6 +53,7 @@
#include "port.h"
#include "trap.h"
#include "txheader.h"
+#include "ib.h"
static const char mlxsw_sx_driver_name[] = "mlxsw_switchx2";
static const char mlxsw_sx_driver_version[] = "1.0";
@@ -218,14 +219,14 @@ static int mlxsw_sx_port_oper_status_get(struct mlxsw_sx_port *mlxsw_sx_port,
return 0;
}
-static int mlxsw_sx_port_mtu_set(struct mlxsw_sx_port *mlxsw_sx_port, u16 mtu)
+static int __mlxsw_sx_port_mtu_set(struct mlxsw_sx_port *mlxsw_sx_port,
+ u16 mtu)
{
struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
char pmtu_pl[MLXSW_REG_PMTU_LEN];
int max_mtu;
int err;
- mtu += MLXSW_TXHDR_LEN + ETH_HLEN;
mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sx_port->local_port, 0);
err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(pmtu), pmtu_pl);
if (err)
@@ -239,6 +240,32 @@ static int mlxsw_sx_port_mtu_set(struct mlxsw_sx_port *mlxsw_sx_port, u16 mtu)
return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pmtu), pmtu_pl);
}
+static int mlxsw_sx_port_mtu_eth_set(struct mlxsw_sx_port *mlxsw_sx_port,
+ u16 mtu)
+{
+ mtu += MLXSW_TXHDR_LEN + ETH_HLEN;
+ return __mlxsw_sx_port_mtu_set(mlxsw_sx_port, mtu);
+}
+
+static int mlxsw_sx_port_mtu_ib_set(struct mlxsw_sx_port *mlxsw_sx_port,
+ u16 mtu)
+{
+ return __mlxsw_sx_port_mtu_set(mlxsw_sx_port, mtu);
+}
+
+static int mlxsw_sx_port_ib_port_set(struct mlxsw_sx_port *mlxsw_sx_port,
+ u8 ib_port)
+{
+ struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
+ char plib_pl[MLXSW_REG_PLIB_LEN] = {0};
+ int err;
+
+ mlxsw_reg_plib_local_port_set(plib_pl, mlxsw_sx_port->local_port);
+ mlxsw_reg_plib_ib_port_set(plib_pl, ib_port);
+ err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(plib), plib_pl);
+ return err;
+}
+
static int mlxsw_sx_port_swid_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 swid)
{
struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
@@ -348,7 +375,7 @@ static int mlxsw_sx_port_change_mtu(struct net_device *dev, int mtu)
struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev);
int err;
- err = mlxsw_sx_port_mtu_set(mlxsw_sx_port, mtu);
+ err = mlxsw_sx_port_mtu_eth_set(mlxsw_sx_port, mtu);
if (err)
return err;
dev->mtu = mtu;
@@ -969,6 +996,17 @@ static int mlxsw_sx_port_stp_state_set(struct mlxsw_sx_port *mlxsw_sx_port,
return err;
}
+static int mlxsw_sx_port_ib_speed_set(struct mlxsw_sx_port *mlxsw_sx_port,
+ u16 speed, u16 width)
+{
+ struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
+ char ptys_pl[MLXSW_REG_PTYS_LEN];
+
+ mlxsw_reg_ptys_ib_pack(ptys_pl, mlxsw_sx_port->local_port, speed,
+ width);
+ return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl);
+}
+
static int
mlxsw_sx_port_speed_by_width_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 width)
{
@@ -1063,7 +1101,7 @@ static int __mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
goto err_port_speed_set;
}
- err = mlxsw_sx_port_mtu_set(mlxsw_sx_port, ETH_DATA_LEN);
+ err = mlxsw_sx_port_mtu_eth_set(mlxsw_sx_port, ETH_DATA_LEN);
if (err) {
dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MTU\n",
mlxsw_sx_port->local_port);
@@ -1153,15 +1191,118 @@ static void __mlxsw_sx_port_eth_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
free_netdev(mlxsw_sx_port->dev);
}
-static void mlxsw_sx_port_eth_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
+static bool mlxsw_sx_port_created(struct mlxsw_sx *mlxsw_sx, u8 local_port)
{
- __mlxsw_sx_port_eth_remove(mlxsw_sx, local_port);
- mlxsw_core_port_fini(mlxsw_sx->core, local_port);
+ return mlxsw_sx->ports[local_port] != NULL;
}
-static bool mlxsw_sx_port_created(struct mlxsw_sx *mlxsw_sx, u8 local_port)
+static int __mlxsw_sx_port_ib_create(struct mlxsw_sx *mlxsw_sx, u8 local_port,
+ u8 module, u8 width)
{
- return mlxsw_sx->ports[local_port] != NULL;
+ struct mlxsw_sx_port *mlxsw_sx_port;
+ int err;
+
+ mlxsw_sx_port = kzalloc(sizeof(*mlxsw_sx_port), GFP_KERNEL);
+ if (!mlxsw_sx_port)
+ return -ENOMEM;
+ mlxsw_sx_port->mlxsw_sx = mlxsw_sx;
+ mlxsw_sx_port->local_port = local_port;
+ mlxsw_sx_port->mapping.module = module;
+
+ err = mlxsw_sx_port_system_port_mapping_set(mlxsw_sx_port);
+ if (err) {
+ dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set system port mapping\n",
+ mlxsw_sx_port->local_port);
+ goto err_port_system_port_mapping_set;
+ }
+
+ /* Adding port to Infiniband swid (1) */
+ err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 1);
+ if (err) {
+ dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set SWID\n",
+ mlxsw_sx_port->local_port);
+ goto err_port_swid_set;
+ }
+
+ /* Expose the IB port number as it's front panel name */
+ err = mlxsw_sx_port_ib_port_set(mlxsw_sx_port, module + 1);
+ if (err) {
+ dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set IB port\n",
+ mlxsw_sx_port->local_port);
+ goto err_port_ib_set;
+ }
+
+ /* Supports all speeds from SDR to FDR (bitmask) and support bus width
+ * of 1x, 2x and 4x (3 bits bitmask)
+ */
+ err = mlxsw_sx_port_ib_speed_set(mlxsw_sx_port,
+ MLXSW_REG_PTYS_IB_SPEED_EDR - 1,
+ BIT(3) - 1);
+ if (err) {
+ dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set speed\n",
+ mlxsw_sx_port->local_port);
+ goto err_port_speed_set;
+ }
+
+ /* Change to the maximum MTU the device supports, the SMA will take
+ * care of the active MTU
+ */
+ err = mlxsw_sx_port_mtu_ib_set(mlxsw_sx_port, MLXSW_IB_DEFAULT_MTU);
+ if (err) {
+ dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MTU\n",
+ mlxsw_sx_port->local_port);
+ goto err_port_mtu_set;
+ }
+
+ err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, true);
+ if (err) {
+ dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to change admin state to UP\n",
+ mlxsw_sx_port->local_port);
+ goto err_port_admin_set;
+ }
+
+ mlxsw_core_port_ib_set(mlxsw_sx->core, mlxsw_sx_port->local_port,
+ mlxsw_sx_port);
+ mlxsw_sx->ports[local_port] = mlxsw_sx_port;
+ return 0;
+
+err_port_admin_set:
+err_port_mtu_set:
+err_port_speed_set:
+err_port_ib_set:
+ mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
+err_port_swid_set:
+err_port_system_port_mapping_set:
+ kfree(mlxsw_sx_port);
+ return err;
+}
+
+static void __mlxsw_sx_port_ib_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
+{
+ struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port];
+
+ mlxsw_core_port_clear(mlxsw_sx->core, local_port, mlxsw_sx);
+ mlxsw_sx->ports[local_port] = NULL;
+ mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false);
+ mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
+ kfree(mlxsw_sx_port);
+}
+
+static void __mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
+{
+ enum devlink_port_type port_type =
+ mlxsw_core_port_type_get(mlxsw_sx->core, local_port);
+
+ if (port_type == DEVLINK_PORT_TYPE_ETH)
+ __mlxsw_sx_port_eth_remove(mlxsw_sx, local_port);
+ else if (port_type == DEVLINK_PORT_TYPE_IB)
+ __mlxsw_sx_port_ib_remove(mlxsw_sx, local_port);
+}
+
+static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
+{
+ __mlxsw_sx_port_remove(mlxsw_sx, local_port);
+ mlxsw_core_port_fini(mlxsw_sx->core, local_port);
}
static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx)
@@ -1170,7 +1311,7 @@ static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx)
for (i = 1; i < MLXSW_PORT_MAX_PORTS; i++)
if (mlxsw_sx_port_created(mlxsw_sx, i))
- mlxsw_sx_port_eth_remove(mlxsw_sx, i);
+ mlxsw_sx_port_remove(mlxsw_sx, i);
kfree(mlxsw_sx->ports);
}
@@ -1203,17 +1344,41 @@ static int mlxsw_sx_ports_create(struct mlxsw_sx *mlxsw_sx)
err_port_module_info_get:
for (i--; i >= 1; i--)
if (mlxsw_sx_port_created(mlxsw_sx, i))
- mlxsw_sx_port_eth_remove(mlxsw_sx, i);
+ mlxsw_sx_port_remove(mlxsw_sx, i);
kfree(mlxsw_sx->ports);
return err;
}
+static void mlxsw_sx_pude_eth_event_func(struct mlxsw_sx_port *mlxsw_sx_port,
+ enum mlxsw_reg_pude_oper_status status)
+{
+ if (status == MLXSW_PORT_OPER_STATUS_UP) {
+ netdev_info(mlxsw_sx_port->dev, "link up\n");
+ netif_carrier_on(mlxsw_sx_port->dev);
+ } else {
+ netdev_info(mlxsw_sx_port->dev, "link down\n");
+ netif_carrier_off(mlxsw_sx_port->dev);
+ }
+}
+
+static void mlxsw_sx_pude_ib_event_func(struct mlxsw_sx_port *mlxsw_sx_port,
+ enum mlxsw_reg_pude_oper_status status)
+{
+ if (status == MLXSW_PORT_OPER_STATUS_UP)
+ pr_info("ib link for port %d - up\n",
+ mlxsw_sx_port->mapping.module + 1);
+ else
+ pr_info("ib link for port %d - down\n",
+ mlxsw_sx_port->mapping.module + 1);
+}
+
static void mlxsw_sx_pude_event_func(const struct mlxsw_reg_info *reg,
char *pude_pl, void *priv)
{
struct mlxsw_sx *mlxsw_sx = priv;
struct mlxsw_sx_port *mlxsw_sx_port;
enum mlxsw_reg_pude_oper_status status;
+ enum devlink_port_type port_type;
u8 local_port;
local_port = mlxsw_reg_pude_local_port_get(pude_pl);
@@ -1225,13 +1390,11 @@ static void mlxsw_sx_pude_event_func(const struct mlxsw_reg_info *reg,
}
status = mlxsw_reg_pude_oper_status_get(pude_pl);
- if (status == MLXSW_PORT_OPER_STATUS_UP) {
- netdev_info(mlxsw_sx_port->dev, "link up\n");
- netif_carrier_on(mlxsw_sx_port->dev);
- } else {
- netdev_info(mlxsw_sx_port->dev, "link down\n");
- netif_carrier_off(mlxsw_sx_port->dev);
- }
+ port_type = mlxsw_core_port_type_get(mlxsw_sx->core, local_port);
+ if (port_type == DEVLINK_PORT_TYPE_ETH)
+ mlxsw_sx_pude_eth_event_func(mlxsw_sx_port, status);
+ else if (port_type == DEVLINK_PORT_TYPE_IB)
+ mlxsw_sx_pude_ib_event_func(mlxsw_sx_port, status);
}
static struct mlxsw_event_listener mlxsw_sx_pude_event = {
@@ -1305,6 +1468,33 @@ static void mlxsw_sx_rx_listener_func(struct sk_buff *skb, u8 local_port,
netif_receive_skb(skb);
}
+static int mlxsw_sx_port_type_set(struct mlxsw_core *mlxsw_core, u8 local_port,
+ enum devlink_port_type new_type)
+{
+ struct mlxsw_sx *mlxsw_sx = mlxsw_core_driver_priv(mlxsw_core);
+ u8 module, width;
+ int err;
+
+ if (new_type == DEVLINK_PORT_TYPE_AUTO)
+ return -EOPNOTSUPP;
+
+ __mlxsw_sx_port_remove(mlxsw_sx, local_port);
+ err = mlxsw_sx_port_module_info_get(mlxsw_sx, local_port, &module,
+ &width);
+ if (err)
+ goto err_port_module_info_get;
+
+ if (new_type == DEVLINK_PORT_TYPE_ETH)
+ err = __mlxsw_sx_port_eth_create(mlxsw_sx, local_port, module,
+ width);
+ else if (new_type == DEVLINK_PORT_TYPE_IB)
+ err = __mlxsw_sx_port_ib_create(mlxsw_sx, local_port, module,
+ width);
+
+err_port_module_info_get:
+ return err;
+}
+
static const struct mlxsw_rx_listener mlxsw_sx_rx_listener[] = {
{
.func = mlxsw_sx_rx_listener_func,
@@ -1614,6 +1804,7 @@ static struct mlxsw_driver mlxsw_sx_driver = {
.txhdr_construct = mlxsw_sx_txhdr_construct,
.txhdr_len = MLXSW_TXHDR_LEN,
.profile = &mlxsw_sx_config_profile,
+ .port_type_set = mlxsw_sx_port_type_set,
};
static const struct pci_device_id mlxsw_sx_pci_id_table[] = {
--
2.5.5
^ permalink raw reply related
* [patch net-next 16/16] mlxsw: switchib: Introduce SwitchIB and SwitchIB silicon driver
From: Jiri Pirko @ 2016-10-28 19:36 UTC (permalink / raw)
To: netdev; +Cc: davem, eladr, idosch, yotamg, nogahf, ogerlitz
In-Reply-To: <1477683361-8011-1-git-send-email-jiri@resnulli.us>
From: Elad Raz <eladr@mellanox.com>
SwitchIB and SwitchIB-2 are Infiniband switches with up to 36 ports. This
driver initialize the hardware and Firmware which implements the IB
management and connection with the SM.
Signed-off-by: Elad Raz <eladr@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/Kconfig | 11 +
drivers/net/ethernet/mellanox/mlxsw/Makefile | 2 +
drivers/net/ethernet/mellanox/mlxsw/pci.h | 2 +
drivers/net/ethernet/mellanox/mlxsw/port.h | 3 +
drivers/net/ethernet/mellanox/mlxsw/switchib.c | 598 +++++++++++++++++++++++++
5 files changed, 616 insertions(+)
create mode 100644 drivers/net/ethernet/mellanox/mlxsw/switchib.c
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
index d0bcf59..bac2e5e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
@@ -29,6 +29,17 @@ config MLXSW_PCI
To compile this driver as a module, choose M here: the
module will be called mlxsw_pci.
+config MLXSW_SWITCHIB
+ tristate "Mellanox Technologies SwitchIB and SwitchIB-2 support"
+ depends on MLXSW_CORE && NET_SWITCHDEV
+ default m
+ ---help---
+ This driver supports Mellanox Technologies SwitchIB and SwitchIB-2
+ Infiniband Switch ASICs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mlxsw_switchib.
+
config MLXSW_SWITCHX2
tristate "Mellanox Technologies SwitchX-2 support"
depends on MLXSW_CORE && MLXSW_PCI && NET_SWITCHDEV
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile
index d20ae18..badef87 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile
@@ -3,6 +3,8 @@ mlxsw_core-objs := core.o
mlxsw_core-$(CONFIG_MLXSW_CORE_HWMON) += core_hwmon.o
obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o
mlxsw_pci-objs := pci.o
+obj-$(CONFIG_MLXSW_SWITCHIB) += mlxsw_switchib.o
+mlxsw_switchib-objs := switchib.o
obj-$(CONFIG_MLXSW_SWITCHX2) += mlxsw_switchx2.o
mlxsw_switchx2-objs := switchx2.o
obj-$(CONFIG_MLXSW_SPECTRUM) += mlxsw_spectrum.o
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.h b/drivers/net/ethernet/mellanox/mlxsw/pci.h
index 35a0011..d655823 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.h
@@ -39,6 +39,8 @@
#define PCI_DEVICE_ID_MELLANOX_SWITCHX2 0xc738
#define PCI_DEVICE_ID_MELLANOX_SPECTRUM 0xcb84
+#define PCI_DEVICE_ID_MELLANOX_SWITCHIB 0xcb20
+#define PCI_DEVICE_ID_MELLANOX_SWITCHIB2 0xcf08
#if IS_ENABLED(CONFIG_MLXSW_PCI)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/port.h b/drivers/net/ethernet/mellanox/mlxsw/port.h
index 7296071..3d42146 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/port.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/port.h
@@ -52,6 +52,9 @@
#define MLXSW_PORT_MAX_PHY_PORTS 0x40
#define MLXSW_PORT_MAX_PORTS (MLXSW_PORT_MAX_PHY_PORTS + 1)
+#define MLXSW_PORT_MAX_IB_PHY_PORTS 36
+#define MLXSW_PORT_MAX_IB_PORTS (MLXSW_PORT_MAX_IB_PHY_PORTS + 1)
+
#define MLXSW_PORT_DEVID_BITS_OFFSET 10
#define MLXSW_PORT_PHY_BITS_OFFSET 4
#define MLXSW_PORT_PHY_BITS_MASK (MLXSW_PORT_MAX_PHY_PORTS - 1)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchib.c b/drivers/net/ethernet/mellanox/mlxsw/switchib.c
new file mode 100644
index 0000000..ec0b27e
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/switchib.c
@@ -0,0 +1,598 @@
+/*
+ * drivers/net/ethernet/mellanox/mlxsw/switchib.c
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Elad Raz <eladr@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/skbuff.h>
+#include <linux/if_vlan.h>
+#include <net/switchdev.h>
+#include <generated/utsrelease.h>
+
+#include "pci.h"
+#include "core.h"
+#include "reg.h"
+#include "port.h"
+#include "trap.h"
+#include "txheader.h"
+#include "ib.h"
+
+static const char mlxsw_sib_driver_name[] = "mlxsw_switchib";
+static const char mlxsw_sib2_driver_name[] = "mlxsw_switchib2";
+
+struct mlxsw_sib_port;
+
+struct mlxsw_sib {
+ struct mlxsw_sib_port **ports;
+ struct mlxsw_core *core;
+ const struct mlxsw_bus_info *bus_info;
+};
+
+struct mlxsw_sib_port {
+ struct mlxsw_sib *mlxsw_sib;
+ u8 local_port;
+ struct {
+ u8 module;
+ } mapping;
+};
+
+/* tx_v1_hdr_version
+ * Tx header version.
+ * Must be set to 1.
+ */
+MLXSW_ITEM32(tx_v1, hdr, version, 0x00, 28, 4);
+
+/* tx_v1_hdr_ctl
+ * Packet control type.
+ * 0 - Ethernet control (e.g. EMADs, LACP)
+ * 1 - Ethernet data
+ */
+MLXSW_ITEM32(tx_v1, hdr, ctl, 0x00, 26, 2);
+
+/* tx_v1_hdr_proto
+ * Packet protocol type. Must be set to 1 (Ethernet).
+ */
+MLXSW_ITEM32(tx_v1, hdr, proto, 0x00, 21, 3);
+
+/* tx_v1_hdr_swid
+ * Switch partition ID. Must be set to 0.
+ */
+MLXSW_ITEM32(tx_v1, hdr, swid, 0x00, 12, 3);
+
+/* tx_v1_hdr_control_tclass
+ * Indicates if the packet should use the control TClass and not one
+ * of the data TClasses.
+ */
+MLXSW_ITEM32(tx_v1, hdr, control_tclass, 0x00, 6, 1);
+
+/* tx_v1_hdr_port_mid
+ * Destination local port for unicast packets.
+ * Destination multicast ID for multicast packets.
+ *
+ * Control packets are directed to a specific egress port, while data
+ * packets are transmitted through the CPU port (0) into the switch partition,
+ * where forwarding rules are applied.
+ */
+MLXSW_ITEM32(tx_v1, hdr, port_mid, 0x04, 16, 16);
+
+/* tx_v1_hdr_type
+ * 0 - Data packets
+ * 6 - Control packets
+ */
+MLXSW_ITEM32(tx_v1, hdr, type, 0x0C, 0, 4);
+
+static void
+mlxsw_sib_tx_v1_hdr_construct(struct sk_buff *skb,
+ const struct mlxsw_tx_info *tx_info)
+{
+ char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
+
+ memset(txhdr, 0, MLXSW_TXHDR_LEN);
+
+ mlxsw_tx_v1_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);
+ mlxsw_tx_v1_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL);
+ mlxsw_tx_v1_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
+ mlxsw_tx_v1_hdr_swid_set(txhdr, 0);
+ mlxsw_tx_v1_hdr_control_tclass_set(txhdr, 1);
+ mlxsw_tx_v1_hdr_port_mid_set(txhdr, tx_info->local_port);
+ mlxsw_tx_v1_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);
+}
+
+static int
+mlxsw_sib_port_admin_status_set(struct mlxsw_sib_port *mlxsw_sib_port,
+ bool is_up)
+{
+ struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
+ char paos_pl[MLXSW_REG_PAOS_LEN];
+
+ mlxsw_reg_paos_pack(paos_pl, mlxsw_sib_port->local_port,
+ is_up ? MLXSW_PORT_ADMIN_STATUS_UP :
+ MLXSW_PORT_ADMIN_STATUS_DOWN);
+ return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(paos), paos_pl);
+}
+
+static int mlxsw_sib_port_mtu_set(struct mlxsw_sib_port *mlxsw_sib_port,
+ u16 mtu)
+{
+ struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
+ char pmtu_pl[MLXSW_REG_PMTU_LEN];
+ int max_mtu;
+ int err;
+
+ mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, 0);
+ err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl);
+ if (err)
+ return err;
+ max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
+
+ if (mtu > max_mtu)
+ return -EINVAL;
+
+ mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sib_port->local_port, mtu);
+ return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pmtu), pmtu_pl);
+}
+
+static int mlxsw_sib_port_set(struct mlxsw_sib_port *mlxsw_sib_port, u8 port)
+{
+ struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
+ char plib_pl[MLXSW_REG_PLIB_LEN] = {0};
+ int err;
+
+ mlxsw_reg_plib_local_port_set(plib_pl, mlxsw_sib_port->local_port);
+ mlxsw_reg_plib_ib_port_set(plib_pl, port);
+ err = mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(plib), plib_pl);
+ return err;
+}
+
+static int mlxsw_sib_port_swid_set(struct mlxsw_sib_port *mlxsw_sib_port,
+ u8 swid)
+{
+ struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
+ char pspa_pl[MLXSW_REG_PSPA_LEN];
+
+ mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sib_port->local_port);
+ return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(pspa), pspa_pl);
+}
+
+static int mlxsw_sib_port_module_info_get(struct mlxsw_sib *mlxsw_sib,
+ u8 local_port, u8 *p_module,
+ u8 *p_width)
+{
+ char pmlp_pl[MLXSW_REG_PMLP_LEN];
+ int err;
+
+ mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
+ err = mlxsw_reg_query(mlxsw_sib->core, MLXSW_REG(pmlp), pmlp_pl);
+ if (err)
+ return err;
+ *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
+ *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
+ return 0;
+}
+
+static int mlxsw_sib_port_speed_set(struct mlxsw_sib_port *mlxsw_sib_port,
+ u16 speed, u16 width)
+{
+ struct mlxsw_sib *mlxsw_sib = mlxsw_sib_port->mlxsw_sib;
+ char ptys_pl[MLXSW_REG_PTYS_LEN];
+
+ mlxsw_reg_ptys_ib_pack(ptys_pl, mlxsw_sib_port->local_port, speed,
+ width);
+ return mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(ptys), ptys_pl);
+}
+
+static bool mlxsw_sib_port_created(struct mlxsw_sib *mlxsw_sib, u8 local_port)
+{
+ return mlxsw_sib->ports[local_port] != NULL;
+}
+
+static int __mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port,
+ u8 module, u8 width)
+{
+ struct mlxsw_sib_port *mlxsw_sib_port;
+ int err;
+
+ mlxsw_sib_port = kzalloc(sizeof(*mlxsw_sib_port), GFP_KERNEL);
+ if (!mlxsw_sib_port)
+ return -ENOMEM;
+ mlxsw_sib_port->mlxsw_sib = mlxsw_sib;
+ mlxsw_sib_port->local_port = local_port;
+ mlxsw_sib_port->mapping.module = module;
+
+ err = mlxsw_sib_port_swid_set(mlxsw_sib_port, 0);
+ if (err) {
+ dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set SWID\n",
+ mlxsw_sib_port->local_port);
+ goto err_port_swid_set;
+ }
+
+ /* Expose the IB port number as it's front panel name */
+ err = mlxsw_sib_port_set(mlxsw_sib_port, module + 1);
+ if (err) {
+ dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set IB port\n",
+ mlxsw_sib_port->local_port);
+ goto err_port_ib_set;
+ }
+
+ /* Supports all speeds from SDR to FDR (bitmask) and support bus width
+ * of 1x, 2x and 4x (3 bits bitmask)
+ */
+ err = mlxsw_sib_port_speed_set(mlxsw_sib_port,
+ MLXSW_REG_PTYS_IB_SPEED_EDR - 1,
+ BIT(3) - 1);
+ if (err) {
+ dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set speed\n",
+ mlxsw_sib_port->local_port);
+ goto err_port_speed_set;
+ }
+
+ /* Change to the maximum MTU the device supports, the SMA will take
+ * care of the active MTU
+ */
+ err = mlxsw_sib_port_mtu_set(mlxsw_sib_port, MLXSW_IB_DEFAULT_MTU);
+ if (err) {
+ dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to set MTU\n",
+ mlxsw_sib_port->local_port);
+ goto err_port_mtu_set;
+ }
+
+ err = mlxsw_sib_port_admin_status_set(mlxsw_sib_port, true);
+ if (err) {
+ dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to change admin state to UP\n",
+ mlxsw_sib_port->local_port);
+ goto err_port_admin_set;
+ }
+
+ mlxsw_core_port_ib_set(mlxsw_sib->core, mlxsw_sib_port->local_port,
+ mlxsw_sib_port);
+ mlxsw_sib->ports[local_port] = mlxsw_sib_port;
+ return 0;
+
+err_port_admin_set:
+err_port_mtu_set:
+err_port_speed_set:
+err_port_ib_set:
+ mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT);
+err_port_swid_set:
+ kfree(mlxsw_sib_port);
+ return err;
+}
+
+static int mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port,
+ u8 module, u8 width)
+{
+ int err;
+
+ err = mlxsw_core_port_init(mlxsw_sib->core, local_port);
+ if (err) {
+ dev_err(mlxsw_sib->bus_info->dev, "Port %d: Failed to init core port\n",
+ local_port);
+ return err;
+ }
+ err = __mlxsw_sib_port_create(mlxsw_sib, local_port, module, width);
+ if (err)
+ goto err_port_create;
+
+ return 0;
+
+err_port_create:
+ mlxsw_core_port_fini(mlxsw_sib->core, local_port);
+ return err;
+}
+
+static void __mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port)
+{
+ struct mlxsw_sib_port *mlxsw_sib_port = mlxsw_sib->ports[local_port];
+
+ mlxsw_core_port_clear(mlxsw_sib->core, local_port, mlxsw_sib);
+ mlxsw_sib->ports[local_port] = NULL;
+ mlxsw_sib_port_admin_status_set(mlxsw_sib_port, false);
+ mlxsw_sib_port_swid_set(mlxsw_sib_port, MLXSW_PORT_SWID_DISABLED_PORT);
+ kfree(mlxsw_sib_port);
+}
+
+static void mlxsw_sib_port_remove(struct mlxsw_sib *mlxsw_sib, u8 local_port)
+{
+ __mlxsw_sib_port_remove(mlxsw_sib, local_port);
+ mlxsw_core_port_fini(mlxsw_sib->core, local_port);
+}
+
+static void mlxsw_sib_ports_remove(struct mlxsw_sib *mlxsw_sib)
+{
+ int i;
+
+ for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++)
+ if (mlxsw_sib_port_created(mlxsw_sib, i))
+ mlxsw_sib_port_remove(mlxsw_sib, i);
+ kfree(mlxsw_sib->ports);
+}
+
+static int mlxsw_sib_ports_create(struct mlxsw_sib *mlxsw_sib)
+{
+ size_t alloc_size;
+ u8 module, width;
+ int i;
+ int err;
+
+ alloc_size = sizeof(struct mlxsw_sib_port *) * MLXSW_PORT_MAX_IB_PORTS;
+ mlxsw_sib->ports = kzalloc(alloc_size, GFP_KERNEL);
+ if (!mlxsw_sib->ports)
+ return -ENOMEM;
+
+ for (i = 1; i < MLXSW_PORT_MAX_IB_PORTS; i++) {
+ err = mlxsw_sib_port_module_info_get(mlxsw_sib, i, &module,
+ &width);
+ if (err)
+ goto err_port_module_info_get;
+ if (!width)
+ continue;
+ err = mlxsw_sib_port_create(mlxsw_sib, i, module, width);
+ if (err)
+ goto err_port_create;
+ }
+ return 0;
+
+err_port_create:
+err_port_module_info_get:
+ for (i--; i >= 1; i--)
+ if (mlxsw_sib_port_created(mlxsw_sib, i))
+ mlxsw_sib_port_remove(mlxsw_sib, i);
+ kfree(mlxsw_sib->ports);
+ return err;
+}
+
+static void
+mlxsw_sib_pude_ib_event_func(struct mlxsw_sib_port *mlxsw_sib_port,
+ enum mlxsw_reg_pude_oper_status status)
+{
+ if (status == MLXSW_PORT_OPER_STATUS_UP)
+ pr_info("ib link for port %d - up\n",
+ mlxsw_sib_port->mapping.module + 1);
+ else
+ pr_info("ib link for port %d - down\n",
+ mlxsw_sib_port->mapping.module + 1);
+}
+
+static void mlxsw_sib_pude_event_func(const struct mlxsw_reg_info *reg,
+ char *pude_pl, void *priv)
+{
+ struct mlxsw_sib *mlxsw_sib = priv;
+ struct mlxsw_sib_port *mlxsw_sib_port;
+ enum mlxsw_reg_pude_oper_status status;
+ u8 local_port;
+
+ local_port = mlxsw_reg_pude_local_port_get(pude_pl);
+ mlxsw_sib_port = mlxsw_sib->ports[local_port];
+ if (!mlxsw_sib_port) {
+ dev_warn(mlxsw_sib->bus_info->dev, "Port %d: Link event received for non-existent port\n",
+ local_port);
+ return;
+ }
+
+ status = mlxsw_reg_pude_oper_status_get(pude_pl);
+ mlxsw_sib_pude_ib_event_func(mlxsw_sib_port, status);
+}
+
+static struct mlxsw_event_listener mlxsw_sib_pude_event = {
+ .func = mlxsw_sib_pude_event_func,
+ .trap_id = MLXSW_TRAP_ID_PUDE,
+};
+
+static int mlxsw_sib_event_register(struct mlxsw_sib *mlxsw_sib,
+ enum mlxsw_event_trap_id trap_id)
+{
+ struct mlxsw_event_listener *el;
+ char hpkt_pl[MLXSW_REG_HPKT_LEN];
+ int err;
+
+ switch (trap_id) {
+ case MLXSW_TRAP_ID_PUDE:
+ el = &mlxsw_sib_pude_event;
+ break;
+ }
+ err = mlxsw_core_event_listener_register(mlxsw_sib->core, el,
+ mlxsw_sib);
+ if (err)
+ return err;
+
+ mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_FORWARD, trap_id);
+ err = mlxsw_reg_write(mlxsw_sib->core, MLXSW_REG(hpkt), hpkt_pl);
+ if (err)
+ goto err_event_trap_set;
+
+ return 0;
+
+err_event_trap_set:
+ mlxsw_core_event_listener_unregister(mlxsw_sib->core, el, mlxsw_sib);
+ return err;
+}
+
+static void mlxsw_sib_event_unregister(struct mlxsw_sib *mlxsw_sib,
+ enum mlxsw_event_trap_id trap_id)
+{
+ struct mlxsw_event_listener *el;
+
+ switch (trap_id) {
+ case MLXSW_TRAP_ID_PUDE:
+ el = &mlxsw_sib_pude_event;
+ break;
+ }
+ mlxsw_core_event_listener_unregister(mlxsw_sib->core, el, mlxsw_sib);
+}
+
+static int mlxsw_sib_init(struct mlxsw_core *mlxsw_core,
+ const struct mlxsw_bus_info *mlxsw_bus_info)
+{
+ struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core);
+ int err;
+
+ mlxsw_sib->core = mlxsw_core;
+ mlxsw_sib->bus_info = mlxsw_bus_info;
+
+ err = mlxsw_sib_ports_create(mlxsw_sib);
+ if (err) {
+ dev_err(mlxsw_sib->bus_info->dev, "Failed to create ports\n");
+ return err;
+ }
+
+ err = mlxsw_sib_event_register(mlxsw_sib, MLXSW_TRAP_ID_PUDE);
+ if (err) {
+ dev_err(mlxsw_sib->bus_info->dev, "Failed to register for PUDE events\n");
+ goto err_event_register;
+ }
+
+ return 0;
+
+err_event_register:
+ mlxsw_sib_ports_remove(mlxsw_sib);
+ return err;
+}
+
+static void mlxsw_sib_fini(struct mlxsw_core *mlxsw_core)
+{
+ struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core);
+
+ mlxsw_sib_event_unregister(mlxsw_sib, MLXSW_TRAP_ID_PUDE);
+ mlxsw_sib_ports_remove(mlxsw_sib);
+}
+
+static struct mlxsw_config_profile mlxsw_sib_config_profile = {
+ .used_max_system_port = 1,
+ .max_system_port = 48000,
+ .used_max_ib_mc = 1,
+ .max_ib_mc = 27,
+ .used_max_pkey = 1,
+ .max_pkey = 32,
+ .swid_config = {
+ {
+ .used_type = 1,
+ .type = MLXSW_PORT_SWID_TYPE_IB,
+ }
+ },
+ .resource_query_enable = 0,
+};
+
+static struct mlxsw_driver mlxsw_sib_driver = {
+ .kind = mlxsw_sib_driver_name,
+ .priv_size = sizeof(struct mlxsw_sib),
+ .init = mlxsw_sib_init,
+ .fini = mlxsw_sib_fini,
+ .txhdr_construct = mlxsw_sib_tx_v1_hdr_construct,
+ .txhdr_len = MLXSW_TXHDR_LEN,
+ .profile = &mlxsw_sib_config_profile,
+};
+
+static struct mlxsw_driver mlxsw_sib2_driver = {
+ .kind = mlxsw_sib2_driver_name,
+ .priv_size = sizeof(struct mlxsw_sib),
+ .init = mlxsw_sib_init,
+ .fini = mlxsw_sib_fini,
+ .txhdr_construct = mlxsw_sib_tx_v1_hdr_construct,
+ .txhdr_len = MLXSW_TXHDR_LEN,
+ .profile = &mlxsw_sib_config_profile,
+};
+
+static const struct pci_device_id mlxsw_sib_pci_id_table[] = {
+ {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB), 0},
+ {0, },
+};
+
+static struct pci_driver mlxsw_sib_pci_driver = {
+ .name = mlxsw_sib_driver_name,
+ .id_table = mlxsw_sib_pci_id_table,
+};
+
+static const struct pci_device_id mlxsw_sib2_pci_id_table[] = {
+ {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHIB2), 0},
+ {0, },
+};
+
+static struct pci_driver mlxsw_sib2_pci_driver = {
+ .name = mlxsw_sib2_driver_name,
+ .id_table = mlxsw_sib2_pci_id_table,
+};
+
+static int __init mlxsw_sib_module_init(void)
+{
+ int err;
+
+ err = mlxsw_core_driver_register(&mlxsw_sib_driver);
+ if (err)
+ return err;
+
+ err = mlxsw_core_driver_register(&mlxsw_sib2_driver);
+ if (err)
+ goto err_sib2_driver_register;
+
+ err = mlxsw_pci_driver_register(&mlxsw_sib_pci_driver);
+ if (err)
+ goto err_sib_pci_driver_register;
+
+ err = mlxsw_pci_driver_register(&mlxsw_sib2_pci_driver);
+ if (err)
+ goto err_sib2_pci_driver_register;
+
+ return 0;
+
+err_sib2_pci_driver_register:
+ mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver);
+err_sib_pci_driver_register:
+ mlxsw_core_driver_unregister(&mlxsw_sib2_driver);
+err_sib2_driver_register:
+ mlxsw_core_driver_unregister(&mlxsw_sib_driver);
+ return err;
+}
+
+static void __exit mlxsw_sib_module_exit(void)
+{
+ mlxsw_pci_driver_unregister(&mlxsw_sib2_pci_driver);
+ mlxsw_pci_driver_unregister(&mlxsw_sib_pci_driver);
+ mlxsw_core_driver_unregister(&mlxsw_sib2_driver);
+ mlxsw_core_driver_unregister(&mlxsw_sib_driver);
+}
+
+module_init(mlxsw_sib_module_init);
+module_exit(mlxsw_sib_module_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Elad Raz <eladr@@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox SwitchIB and SwitchIB-2 driver");
+MODULE_ALIAS("mlxsw_switchib2");
+MODULE_DEVICE_TABLE(pci, mlxsw_sib_pci_id_table);
+MODULE_DEVICE_TABLE(pci, mlxsw_sib2_pci_id_table);
--
2.5.5
^ permalink raw reply related
* Re: [PATCH net 3/3] sctp: hold transport instead of assoc when lookup assoc in rx path
From: Marcelo Ricardo Leitner @ 2016-10-28 19:57 UTC (permalink / raw)
To: Xin Long; +Cc: network dev, linux-sctp, davem, Vlad Yasevich, daniel
In-Reply-To: <e97fc745a330a6be78b13e1f499381f9d1647b40.1477649076.git.lucien.xin@gmail.com>
On Fri, Oct 28, 2016 at 06:10:54PM +0800, Xin Long wrote:
> Prior to this patch, in rx path, before calling lock_sock, it needed to
> hold assoc when got it by __sctp_lookup_association, in case other place
> would free/put assoc.
>
> But in __sctp_lookup_association, it lookup and hold transport, then got
> assoc by transport->assoc, then hold assoc and put transport. It means
> it didn't hold transport, yet it was returned and later on directly
> assigned to chunk->transport.
>
> Without the protection of sock lock, the transport may be freed/put by
> other places, which would cause a use-after-free issue.
>
> This patch is to fix this issue by holding transport instead of assoc.
> As holding transport can make sure to access assoc is also safe, and
> actually it looks up assoc by searching transport rhashtable, to hold
> transport here makes more sense.
>
> Note that the function will be renamed later on on another patch.
>
> Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> ---
> include/net/sctp/sctp.h | 2 +-
> net/sctp/input.c | 32 ++++++++++++++++----------------
> net/sctp/ipv6.c | 2 +-
> 3 files changed, 18 insertions(+), 18 deletions(-)
>
> diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
> index 87a7f42..31acc3f 100644
> --- a/include/net/sctp/sctp.h
> +++ b/include/net/sctp/sctp.h
> @@ -152,7 +152,7 @@ void sctp_unhash_endpoint(struct sctp_endpoint *);
> struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
> struct sctphdr *, struct sctp_association **,
> struct sctp_transport **);
> -void sctp_err_finish(struct sock *, struct sctp_association *);
> +void sctp_err_finish(struct sock *, struct sctp_transport *);
> void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
> struct sctp_transport *t, __u32 pmtu);
> void sctp_icmp_redirect(struct sock *, struct sctp_transport *,
> diff --git a/net/sctp/input.c b/net/sctp/input.c
> index 8e0bc58..a01a56e 100644
> --- a/net/sctp/input.c
> +++ b/net/sctp/input.c
> @@ -181,9 +181,10 @@ int sctp_rcv(struct sk_buff *skb)
> * bound to another interface, via SO_BINDTODEVICE, treat it as OOTB
> */
> if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) {
> - if (asoc) {
> - sctp_association_put(asoc);
> + if (transport) {
> + sctp_transport_put(transport);
> asoc = NULL;
> + transport = NULL;
> } else {
> sctp_endpoint_put(ep);
> ep = NULL;
> @@ -269,8 +270,8 @@ int sctp_rcv(struct sk_buff *skb)
> bh_unlock_sock(sk);
>
> /* Release the asoc/ep ref we took in the lookup calls. */
> - if (asoc)
> - sctp_association_put(asoc);
> + if (transport)
> + sctp_transport_put(transport);
> else
> sctp_endpoint_put(ep);
>
> @@ -283,8 +284,8 @@ int sctp_rcv(struct sk_buff *skb)
>
> discard_release:
> /* Release the asoc/ep ref we took in the lookup calls. */
> - if (asoc)
> - sctp_association_put(asoc);
> + if (transport)
> + sctp_transport_put(transport);
> else
> sctp_endpoint_put(ep);
>
> @@ -300,6 +301,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
> {
> struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
> struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
> + struct sctp_transport *t = chunk->transport;
> struct sctp_ep_common *rcvr = NULL;
> int backloged = 0;
>
> @@ -351,7 +353,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
> done:
> /* Release the refs we took in sctp_add_backlog */
> if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
> - sctp_association_put(sctp_assoc(rcvr));
> + sctp_transport_put(t);
> else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
> sctp_endpoint_put(sctp_ep(rcvr));
> else
> @@ -363,6 +365,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
> static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
> {
> struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
> + struct sctp_transport *t = chunk->transport;
> struct sctp_ep_common *rcvr = chunk->rcvr;
> int ret;
>
> @@ -373,7 +376,7 @@ static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)
> * from us
> */
> if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
> - sctp_association_hold(sctp_assoc(rcvr));
> + sctp_transport_hold(t);
> else if (SCTP_EP_TYPE_SOCKET == rcvr->type)
> sctp_endpoint_hold(sctp_ep(rcvr));
> else
> @@ -537,15 +540,15 @@ struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,
> return sk;
>
> out:
> - sctp_association_put(asoc);
> + sctp_transport_put(transport);
> return NULL;
> }
>
> /* Common cleanup code for icmp/icmpv6 error handler. */
> -void sctp_err_finish(struct sock *sk, struct sctp_association *asoc)
> +void sctp_err_finish(struct sock *sk, struct sctp_transport *t)
> {
> bh_unlock_sock(sk);
> - sctp_association_put(asoc);
> + sctp_transport_put(t);
> }
>
> /*
> @@ -641,7 +644,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
> }
>
> out_unlock:
> - sctp_err_finish(sk, asoc);
> + sctp_err_finish(sk, transport);
> }
>
> /*
> @@ -952,11 +955,8 @@ static struct sctp_association *__sctp_lookup_association(
> goto out;
>
> asoc = t->asoc;
> - sctp_association_hold(asoc);
> *pt = t;
>
> - sctp_transport_put(t);
> -
> out:
> return asoc;
> }
> @@ -986,7 +986,7 @@ int sctp_has_association(struct net *net,
> struct sctp_transport *transport;
>
> if ((asoc = sctp_lookup_association(net, laddr, paddr, &transport))) {
> - sctp_association_put(asoc);
> + sctp_transport_put(transport);
> return 1;
> }
>
> diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
> index f473779..176af30 100644
> --- a/net/sctp/ipv6.c
> +++ b/net/sctp/ipv6.c
> @@ -198,7 +198,7 @@ static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
> }
>
> out_unlock:
> - sctp_err_finish(sk, asoc);
> + sctp_err_finish(sk, transport);
> out:
> if (likely(idev != NULL))
> in6_dev_put(idev);
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH] net: phy: at803x: the Atheros 8031 supports pause frames
From: Timur Tabi @ 2016-10-28 20:06 UTC (permalink / raw)
To: Florian Fainelli, netdev, zefir.kurtisi, scampbel, alokc,
shankerd, andrew
In-Reply-To: <9b817af9-a519-9010-e57b-8de8972088b8@gmail.com>
Florian Fainelli wrote:
> On 10/27/2016 03:24 PM, Timur Tabi wrote:
>> Florian Fainelli wrote:
>>
>>> Hu? In my experience that should not come from supporting Pause frames
>>> or not, but rather properly configuring a (RG)MII delay, but your
>>> mileage may vary.
>>
>> I can assure you, I'm more confused than you. I've been working in this
>> for almost two weeks, and not only does this patch align with other phy
>> drivers, but it does fix my bug. Without this patch, phylib does not
>> set the pause frame bits (10 and 11) in MII_ADVERTISE.
>
> And that's expected, but if your MAC does not act upon phydev->pause and
> phydev->asym_pause, then chances are that you can indeed lose packets
> every once in a while.
Can you give me more details on that? I'm not really an expert on our
MAC, so I'm not sure how it's supposed to work. The MAC supports the
concept of "flow control". The non-upstream version of my driver reads
PHY register 0x11, which apparently is a PHY-specific status register
that says whether or not "transmit pause" and "receive pause" is
enabled. (The AT8031 datasheet is here, if you'd like to read it:
http://www.datasheet-pdf.com/datasheet/AtherosCommunications/734720/AR8031.pdf.html).
If both are enabled in the PHY, then the driver enables the same
features in the MAC. Unfortunately, I don't have any documentation that
explains that that really means. I've tried enabling and disabling this
feature in the MAC, and it makes no difference. You would think that if
the feature is disabled in both the MAC and the PHY, then no packets
would be lost, but that's not the case.
> The part that is totally crappy about Pause frames and PHYLIB is that we
> need some information about whether this should be supported or not,
> such that we can change MII_ADVERTISE accordingly to reflect that, and
> what best way to do this than use one of these SUPPORTED_* bits to set
> that, except, that unlike speed (which is both a MAC and PHY property),
> Pause is exclusively MAC, yet, it transpires in PHYLIB.
Then what do those bits in register 0x11 do? If I don't set them, I
lose packets, no matter how my MAC is programmed.
It's like that joke, "Doctor, if I hold my arm like this, then it
hurts!", "Well, then don't hold your arm like that." If I don't program
those PHY register bits, then my hardware doesn't work.
> MACs that I work with for instance need to be told to ignore pause
> frames, or not ignore them, it all depends on what you want to
> advertise/support.
That's the problem, I don't know what I "want", except that I want my
hardware to work. :-) 99% of my knowledge of the hardware comes from
scanning the source code of the internal version of the driver that 1)
does not support phylib, and 2) is hard-coded to initialize the Atheros
8031 PHY.
>>> It does not, support for Pause frames is a MAC-level feature, yet,
>>> PHYLIB (and that's been on my todo for a while now) insists on reporting
>>> the confusing phydev->pause and phydev->asym_pause, which really is what
>>> has been determined from auto-negotiating with your partner, as opposed
>>> to being a supported thing or not. The PHY has absolutely not business
>>> in that.
>>
>> But there are pause frame bits in the MII_ADVERTISE register, and this
>> setting directly impacts whether those bits are set. I don't see how
>> this is a MAC-level feature.
>
> This is a MAC level feature, that needs to be auto-negotiated with your
> link partner, which is why there is room for this in MII_ADVERTISE, but
> the PHY absolutely does not participate in Pause frames, other than
> passing them through the MAC, like normal frames. Whether your MAC acts
> upon that or not is a MAC dependent feature.
Ok, to me that means that the PHY driver must tell phylib whether or not
it supports pause frames. The question becomes:
1) Is my patch correct?
2) Is my patch necessary?
3) Is my patch sufficient?
1) I believe my patch is correct, because many other PHY drivers do the
same thing for the same reason. If the PHY supports register 4 bits 10
and 11, then those SUPPORTED_xxx bits should be set.
2) I don't know why my patch appears to be necessary, because I don't
understand why a 1Gb NIC on a 2Ghz processor drops frames. I suspect
the program is not performance but rather a mis-programming.
4) Is my patch sufficient? The internal driver always enables pause
frame support in the PHY if the PHY says that pause frames are enabled.
In fact, I can't even turn off flow control in the internal driver:
$ sudo ethtool -A eth1 tx off rx off
$ sudo ethtool -a eth1
Pause parameters for eth1:
Autonegotiate: on
RX: on
TX: on
The driver insists on leaving flow control enabled if autonegotiation is
enabled.
> Yes I am sure you should set these bits, the documentation is not
> necessarily the authoritative source here (although it should). What
> this probably meant to be written is something like: don't set any bits
> that are not defined in ethtool.h, i.e: do not use this to store
> persistent states.
So when I do that, it works. I force those bits on in my driver, and
pause frames are enabled and everything works correctly.
I still would like to know what those bits in register 4 really are for.
My understanding is that pause frames are an extension to the 802.3
standard, and not every PHY supports them, so not even PHY supports
setting bits 10 and 11 in register 4. That's why the PHY driver should
be setting them, not the MAC.
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH] [v2 netfilter-next] netfilter: nf_tables: fib warnings
From: Arnd Bergmann @ 2016-10-28 20:17 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: Arnd Bergmann, Patrick McHardy, Jozsef Kadlecsik, David S. Miller,
Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Florian Westphal, netfilter-devel, coreteam, netdev, linux-kernel
The newly added nft fib code produces two warnings:
net/ipv4/netfilter/nft_fib_ipv4.c: In function 'nft_fib4_eval':
net/ipv4/netfilter/nft_fib_ipv4.c:80:6: error: unused variable 'i' [-Werror=unused-variable]
net/ipv4/netfilter/nft_fib_ipv4.c: In function ‘nft_fib4_eval’:
net/ipv4/netfilter/nft_fib_ipv4.c:137:6: error: ‘oif’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
The first one is obvious as the only user of that variable is
inside of an #ifdef
The second one is a bit trickier. It's clear that oif is in fact
uninitialized when it gets used when neither NFTA_FIB_F_IIF nor
NFTA_FIB_F_OIF are set, and just setting it to NULL won't work
as it may later get dereferenced.
However, there is no need to search the result list if it is
NULL, as Florian pointed out. This integrates his (untested)
change to do so. I have confirmed that the combined patch
solves both warnings, but as I don't fully understand Florian's
change, I can't tell if it's correct.
Suggested-by: Florian Westphal <fw@strlen.de>
Fixes: 84f5eedb983e ("netfilter: nf_tables: add fib expression")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
v2: integrate changes that Florian suggested
---
net/ipv4/netfilter/nft_fib_ipv4.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/net/ipv4/netfilter/nft_fib_ipv4.c b/net/ipv4/netfilter/nft_fib_ipv4.c
index 6787c563cfc9..db91fd42db67 100644
--- a/net/ipv4/netfilter/nft_fib_ipv4.c
+++ b/net/ipv4/netfilter/nft_fib_ipv4.c
@@ -77,7 +77,9 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
};
const struct net_device *oif;
struct net_device *found;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
int i;
+#endif
/*
* Do not set flowi4_oif, it restricts results (for example, asking
@@ -90,6 +92,8 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
oif = pkt->out;
else if (priv->flags & NFTA_FIB_F_IIF)
oif = pkt->in;
+ else
+ oif = NULL;
if (pkt->hook == NF_INET_PRE_ROUTING && fib4_is_local(pkt->skb)) {
nft_fib_store_result(dest, priv->result, pkt, LOOPBACK_IFINDEX);
@@ -130,6 +134,11 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
break;
}
+ if (!oif) {
+ found = FIB_RES_DEV(res);
+ goto ok;
+ }
+
#ifdef CONFIG_IP_ROUTE_MULTIPATH
for (i = 0; i < res.fi->fib_nhs; i++) {
struct fib_nh *nh = &res.fi->fib_nh[i];
@@ -139,16 +148,12 @@ void nft_fib4_eval(const struct nft_expr *expr, struct nft_regs *regs,
goto ok;
}
}
-#endif
- if (priv->flags & NFTA_FIB_F_OIF) {
- found = FIB_RES_DEV(res);
- if (found == oif)
- goto ok;
- return;
- }
-
- *dest = FIB_RES_DEV(res)->ifindex;
return;
+#else
+ found = FIB_RES_DEV(res);
+ if (found != oif)
+ return;
+#endif
ok:
switch (priv->result) {
case NFT_FIB_RESULT_OIF:
--
2.9.0
^ permalink raw reply related
* Re: [PATCH] [rfc, netfilter-next] netfilter: nf_tables: fib warnings
From: Arnd Bergmann @ 2016-10-28 20:23 UTC (permalink / raw)
To: Florian Westphal
Cc: Pablo Neira Ayuso, Patrick McHardy, Jozsef Kadlecsik,
David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, netfilter-devel, coreteam, netdev,
linux-kernel
In-Reply-To: <20161028162149.GA23891@breakpoint.cc>
On Friday, October 28, 2016 6:21:49 PM CEST Florian Westphal wrote:
> Good point. In case oif is NULL we don't have to search the result
> list for a match anyway, so we could do this (not even build tested):
>
It didn't apply cleanly, but I've integrated it with the change to
initialize oif to NULL and the added #ifdef I had in my first version
and got a clean build.
I sent out a v2 now, but didn't try hard to understand your changes.
Arnd
^ permalink raw reply
* Re: [PATCH net-next RFC WIP] Patch for XDP support for virtio_net
From: Alexander Duyck @ 2016-10-28 20:35 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Jakub Kicinski, John Fastabend, David Miller, Michael S. Tsirkin,
Jesper Dangaard Brouer, shrijeet, Tom Herbert, Netdev,
Shrijeet Mukherjee, roopa, nikolay
In-Reply-To: <20161028182223.GA53930@ast-mbp.thefacebook.com>
On Fri, Oct 28, 2016 at 11:22 AM, Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
> On Fri, Oct 28, 2016 at 05:18:12PM +0100, Jakub Kicinski wrote:
>> On Fri, 28 Oct 2016 08:56:35 -0700, John Fastabend wrote:
>> > On 16-10-27 07:10 PM, David Miller wrote:
>> > > From: Alexander Duyck <alexander.duyck@gmail.com>
>> > > Date: Thu, 27 Oct 2016 18:43:59 -0700
>> > >
>> > >> On Thu, Oct 27, 2016 at 6:35 PM, David Miller <davem@davemloft.net> wrote:
>> > >>> From: "Michael S. Tsirkin" <mst@redhat.com>
>> > >>> Date: Fri, 28 Oct 2016 01:25:48 +0300
>> > >>>
>> > >>>> On Thu, Oct 27, 2016 at 05:42:18PM -0400, David Miller wrote:
>> > >>>>> From: "Michael S. Tsirkin" <mst@redhat.com>
>> > >>>>> Date: Fri, 28 Oct 2016 00:30:35 +0300
>> > >>>>>
>> > >>>>>> Something I'd like to understand is how does XDP address the
>> > >>>>>> problem that 100Byte packets are consuming 4K of memory now.
>> > >>>>>
>> > >>>>> Via page pools. We're going to make a generic one, but right now
>> > >>>>> each and every driver implements a quick list of pages to allocate
>> > >>>>> from (and thus avoid the DMA man/unmap overhead, etc.)
>> > >>>>
>> > >>>> So to clarify, ATM virtio doesn't attempt to avoid dma map/unmap
>> > >>>> so there should be no issue with that even when using sub/page
>> > >>>> regions, assuming DMA APIs support sub-page map/unmap correctly.
>> > >>>
>> > >>> That's not what I said.
>> > >>>
>> > >>> The page pools are meant to address the performance degradation from
>> > >>> going to having one packet per page for the sake of XDP's
>> > >>> requirements.
>> > >>>
>> > >>> You still need to have one packet per page for correct XDP operation
>> > >>> whether you do page pools or not, and whether you have DMA mapping
>> > >>> (or it's equivalent virutalization operation) or not.
>> > >>
>> > >> Maybe I am missing something here, but why do you need to limit things
>> > >> to one packet per page for correct XDP operation? Most of the drivers
>> > >> out there now are usually storing something closer to at least 2
>> > >> packets per page, and with the DMA API fixes I am working on there
>> > >> should be no issue with changing the contents inside those pages since
>> > >> we won't invalidate or overwrite the data after the DMA buffer has
>> > >> been synchronized for use by the CPU.
>> > >
>> > > Because with SKB's you can share the page with other packets.
>> > >
>> > > With XDP you simply cannot.
>> > >
>> > > It's software semantics that are the issue. SKB frag list pages
>> > > are read only, XDP packets are writable.
>> > >
>> > > This has nothing to do with "writability" of the pages wrt. DMA
>> > > mapping or cpu mappings.
>> > >
>> >
>> > Sorry I'm not seeing it either. The current xdp_buff is defined
>> > by,
>> >
>> > struct xdp_buff {
>> > void *data;
>> > void *data_end;
>> > };
>> >
>> > The verifier has an xdp_is_valid_access() check to ensure we don't go
>> > past data_end. The page for now at least never leaves the driver. For
>> > the work to get xmit to other devices working I'm still not sure I see
>> > any issue.
>>
>> +1
>>
>> Do we want to make the packet-per-page a requirement because it could
>> be useful in the future from architectural standpoint? I guess there
>> is a trade-off here between having the comfort of people following this
>> requirement today and making driver support for XDP even more complex.
>
> It looks to me that packet per page makes drivers simpler instead of complex.
> ixgbe split-page and mlx* order-3/5 tricks are definitely complex.
> The skb truesize concerns come from the host when data is delivered to user
> space and we need to have precise memory accounting for different applications
> and different users. XDP is all root and imo it's far away from the days when
> multi-user non-root issues start to pop up.
Right but having XDP require 4K pages is going to hurt performance for
user space when we are using sockets. We cannot justify killing
application performance just because we want to support XDP, and
having to alloc new memory and memcpy out of the buffers isn't going
to work as a viable workaround for this either.
> At the same time XDP doesn't require to use 4k buffer in something like Netronome.
> If xdp bpf program can be offloaded into HW with 1800 byte buffers, great!
So are you saying this is only really meant to be used with a full bpf
hardware offload then?
> For x86 cpu the 4k byte is a natural allocation chunk. Anything lower requires
> delicate dma tricks paired with even more complex slab allocator and atomic recnts.
> All of that can only drive the performance down.
> Comparing to kernel bypass xdp is using 4k pages whereas dpdk has
> to use huge pages, so xdp is saving a ton of memory already!
Do you really think the page pool Jesper is talking about doing is any
different? Half the reason why I have to implement the DMA API
changes that I am are so that the page pool can unmap a page if the
device decides to cut it from the pool without invalidating the data
written by the CPU.
If anything I think we end up needing to add two more data members to
xdp_buff so that we can define the bounds of the sandbox it gets to
play in. Otherwise on platforms such as PowerPC, that can use pages
larger than 4K, this is going to quickly get ridiculous.
- Alex
^ permalink raw reply
* Re: [PATCH net-next RFC WIP] Patch for XDP support for virtio_net
From: Jakub Kicinski @ 2016-10-28 20:36 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: John Fastabend, David Miller, alexander.duyck, mst, brouer,
shrijeet, tom, netdev, shm, roopa, nikolay
In-Reply-To: <20161028182223.GA53930@ast-mbp.thefacebook.com>
On Fri, 28 Oct 2016 11:22:25 -0700, Alexei Starovoitov wrote:
> On Fri, Oct 28, 2016 at 05:18:12PM +0100, Jakub Kicinski wrote:
> > On Fri, 28 Oct 2016 08:56:35 -0700, John Fastabend wrote:
> > > On 16-10-27 07:10 PM, David Miller wrote:
> > > > From: Alexander Duyck <alexander.duyck@gmail.com>
> > > > Date: Thu, 27 Oct 2016 18:43:59 -0700
> > > >
> > > >> On Thu, Oct 27, 2016 at 6:35 PM, David Miller <davem@davemloft.net> wrote:
> > > >>> From: "Michael S. Tsirkin" <mst@redhat.com>
> > > >>> Date: Fri, 28 Oct 2016 01:25:48 +0300
> > > >>>
> > > >>>> On Thu, Oct 27, 2016 at 05:42:18PM -0400, David Miller wrote:
> > > >>>>> From: "Michael S. Tsirkin" <mst@redhat.com>
> > > >>>>> Date: Fri, 28 Oct 2016 00:30:35 +0300
> > > >>>>>
> > > >>>>>> Something I'd like to understand is how does XDP address the
> > > >>>>>> problem that 100Byte packets are consuming 4K of memory now.
> > > >>>>>
> > > >>>>> Via page pools. We're going to make a generic one, but right now
> > > >>>>> each and every driver implements a quick list of pages to allocate
> > > >>>>> from (and thus avoid the DMA man/unmap overhead, etc.)
> > > >>>>
> > > >>>> So to clarify, ATM virtio doesn't attempt to avoid dma map/unmap
> > > >>>> so there should be no issue with that even when using sub/page
> > > >>>> regions, assuming DMA APIs support sub-page map/unmap correctly.
> > > >>>
> > > >>> That's not what I said.
> > > >>>
> > > >>> The page pools are meant to address the performance degradation from
> > > >>> going to having one packet per page for the sake of XDP's
> > > >>> requirements.
> > > >>>
> > > >>> You still need to have one packet per page for correct XDP operation
> > > >>> whether you do page pools or not, and whether you have DMA mapping
> > > >>> (or it's equivalent virutalization operation) or not.
> > > >>
> > > >> Maybe I am missing something here, but why do you need to limit things
> > > >> to one packet per page for correct XDP operation? Most of the drivers
> > > >> out there now are usually storing something closer to at least 2
> > > >> packets per page, and with the DMA API fixes I am working on there
> > > >> should be no issue with changing the contents inside those pages since
> > > >> we won't invalidate or overwrite the data after the DMA buffer has
> > > >> been synchronized for use by the CPU.
> > > >
> > > > Because with SKB's you can share the page with other packets.
> > > >
> > > > With XDP you simply cannot.
> > > >
> > > > It's software semantics that are the issue. SKB frag list pages
> > > > are read only, XDP packets are writable.
> > > >
> > > > This has nothing to do with "writability" of the pages wrt. DMA
> > > > mapping or cpu mappings.
> > > >
> > >
> > > Sorry I'm not seeing it either. The current xdp_buff is defined
> > > by,
> > >
> > > struct xdp_buff {
> > > void *data;
> > > void *data_end;
> > > };
> > >
> > > The verifier has an xdp_is_valid_access() check to ensure we don't go
> > > past data_end. The page for now at least never leaves the driver. For
> > > the work to get xmit to other devices working I'm still not sure I see
> > > any issue.
> >
> > +1
> >
> > Do we want to make the packet-per-page a requirement because it could
> > be useful in the future from architectural standpoint? I guess there
> > is a trade-off here between having the comfort of people following this
> > requirement today and making driver support for XDP even more complex.
>
> It looks to me that packet per page makes drivers simpler instead of complex.
> ixgbe split-page and mlx* order-3/5 tricks are definitely complex.
> The skb truesize concerns come from the host when data is delivered to user
> space and we need to have precise memory accounting for different applications
> and different users. XDP is all root and imo it's far away from the days when
> multi-user non-root issues start to pop up.
> At the same time XDP doesn't require to use 4k buffer in something like Netronome.
> If xdp bpf program can be offloaded into HW with 1800 byte buffers, great!
> For x86 cpu the 4k byte is a natural allocation chunk. Anything lower requires
> delicate dma tricks paired with even more complex slab allocator and atomic recnts.
> All of that can only drive the performance down.
> Comparing to kernel bypass xdp is using 4k pages whereas dpdk has
> to use huge pages, so xdp is saving a ton of memory already!
Thanks a lot for explaining! I was not aware of the user space
delivery and precise memory accounting requirements.
My understanding was that we would be driving toward some common
implementation of the recycle tricks either as part of the frag
allocator or some new mechanism of handing out mapped pages. Basically
moving the allocation strategy decision further up the stack.
I'm not actually worried about the offload, full disclosure, I have a
XDP implementation based on the frag allocator :) (still pending
internal review), so if packet-per-page is the way forward then I'll
have revise to flip between 4k pages and frag allocator based on !!xdp.
^ permalink raw reply
* [PATCH net] net: clear sk_err_soft in sk_clone_lock()
From: Eric Dumazet @ 2016-10-28 20:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Soheil Hassas Yeganeh
From: Eric Dumazet <edumazet@google.com>
At accept() time, it is possible the parent has a non zero
sk_err_soft, leftover from a prior error.
Make sure we do not leave this value in the child, as it
makes future getsockopt(SO_ERROR) calls quite unreliable.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/core/sock.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/core/sock.c b/net/core/sock.c
index d8e4532e89e7c28737c95c723e5f5b3d184a7805..662ccf1c40ed1b66ee253b063dcbfbd186deccee 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1543,6 +1543,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
RCU_INIT_POINTER(newsk->sk_reuseport_cb, NULL);
newsk->sk_err = 0;
+ newsk->sk_err_soft = 0;
newsk->sk_priority = 0;
newsk->sk_incoming_cpu = raw_smp_processor_id();
atomic64_set(&newsk->sk_cookie, 0);
^ permalink raw reply related
* Re: [PATCH net-next RFC WIP] Patch for XDP support for virtio_net
From: Jakub Kicinski @ 2016-10-28 20:42 UTC (permalink / raw)
To: Alexander Duyck
Cc: Alexei Starovoitov, John Fastabend, David Miller,
Michael S. Tsirkin, Jesper Dangaard Brouer, shrijeet, Tom Herbert,
Netdev, Shrijeet Mukherjee, roopa, nikolay
In-Reply-To: <CAKgT0UfZJ1wP9f-ZFVqdDUXMw90DKsRp+NDuam9YnHzbD=Tuig@mail.gmail.com>
On Fri, 28 Oct 2016 13:35:02 -0700, Alexander Duyck wrote:
> > At the same time XDP doesn't require to use 4k buffer in something like Netronome.
> > If xdp bpf program can be offloaded into HW with 1800 byte buffers, great!
>
> So are you saying this is only really meant to be used with a full bpf
> hardware offload then?
I think Alexei just meant to say I don't have to worry about providing
4k buffers when program is offloaded but on the host a page is the
memory granularity for XDP...
^ permalink raw reply
* RE: [PATCH net-next] lan78xx: Use irq_domain for phy interrupt from USB Int. EP
From: Woojung.Huh @ 2016-10-28 20:50 UTC (permalink / raw)
To: f.fainelli, davem, netdev, andrew; +Cc: UNGLinuxDriver
In-Reply-To: <919da0a4-3a5c-8c88-bab5-6fc2bf557a48@gmail.com>
> > +static void lan78xx_irq_mask(struct irq_data *irqd)
> > +{
> > + struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
> > + struct lan78xx_net *dev =
> > + container_of(data, struct lan78xx_net, domain_data);
> > + u32 buf;
> > +
> > + lan78xx_read_reg(dev, INT_EP_CTL, &buf);
>
> lan78xx_read_reg() uses kmalloc() with GFP_KERNEL, while
> irq_mask/irq_unmask can be called in atomic context AFAIR, you may need
> to pass down a specific gfp_t to lan78xx_read_reg.
>
> What about usb_submit_urb(), can that work in atomic context? Do you
> need to have lan78xx_read_reg() acquire a raw spinlock or something to
> serialize them?
>
> > + buf &= ~INT_EP_PHY_INT_EN_;
>
> Even though you may have only one interrupt line to deal with at the
> moment, better make this bit derived from irqd->hwirq instead of hard
> coding it here.
>
> > + lan78xx_write_reg(dev, INT_EP_CTL, buf);
> > +}
> > +
> > +static void lan78xx_irq_unmask(struct irq_data *irqd)
> > +{
> > + struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd);
> > + struct lan78xx_net *dev =
> > + container_of(data, struct lan78xx_net, domain_data);
> > + u32 buf;
> > +
> > + lan78xx_read_reg(dev, INT_EP_CTL, &buf);
> > + buf |= INT_EP_PHY_INT_EN_;
>
> Same here, this should come from irqd->hwirq.
>
> > + lan78xx_write_reg(dev, INT_EP_CTL, buf);
> > +}
> > +
> > +static struct irq_chip lan78xx_irqchip = {
> > + .name = "lan78xx-phyirq",
> > + .irq_mask = lan78xx_irq_mask,
> > + .irq_unmask = lan78xx_irq_unmask,
> > +};
> > +
> > +static int lan78xx_setup_irq_domain(struct lan78xx_net *dev)
> > +{
> > + struct device_node *of_node;
> > + struct irq_domain *irqdomain;
> > + unsigned int irq_base = 0;
> > + int ret = 0;
> > +
> > + of_node = dev->udev->dev.parent->of_node;
> > +
> > + dev->domain_data.irqchip = &lan78xx_irqchip;
> > + dev->domain_data.irq_handler = handle_simple_irq;
> > +
> > + irqdomain = irq_domain_add_simple(of_node, 1, 0,
> &chip_domain_ops,
> > + &dev->domain_data);
>
> Is there really just one interrupt associated with this peripheral here?
>
> >
> > + if (lan78xx_setup_irq_domain(dev) < 0) {
> > + netdev_warn(dev->net, "lan78xx_setup_irq_domain()
> failed");
> > + return -EIO;
> > + }
>
> Any reason not to propagate the error code from
> lan78xx_setup_irq_domain() here?
Thanks for prompt review.
I'll look into it and submit update.
Thanks.
- Woojung
^ permalink raw reply
* [PATCH v2 0/6] add NS2 support to bgmac
From: Jon Mason @ 2016-10-28 20:56 UTC (permalink / raw)
To: David Miller, Rob Herring, Mark Rutland, Florian Fainelli
Cc: rafal, bcm-kernel-feedback-list, netdev, devicetree,
linux-arm-kernel, linux-kernel
Changes in v2:
* Remove the PHY power-on (per Andrew Lunn)
* Misc PHY clean-ups regarding comments and #defines (per Andrew Lunn)
This results on none of the original PHY code from Vikas being
present. So, I'm removing him as an author and giving him
"Inspired-by" credit.
* Move PHY lane swapping to PHY driver (per Andrew Lunn and Florian
Fainelli)
* Remove bgmac sleep (per Florian Fainelli)
* Re-add bgmac chip reset (per Florian Fainelli and Ray Jui)
* Rebased on latest net-next
* Added patch for bcm54xx_auxctl_read, which is used in the BCM54810
Add support for the amac found in the Broadcom Northstar2 SoC to the
bgmac driver. This necessitates adding support to connect to an
externally defined phy (as described in the device tree) in the driver.
These phy changes are in addition to the changes necessary to get NS2
working.
Jon Mason (6):
net: phy: broadcom: add bcm54xx_auxctl_read
net: phy: broadcom: Add BCM54810 PHY entry
Documentation: devicetree: net: add NS2 bindings to amac
net: ethernet: bgmac: device tree phy enablement
net: ethernet: bgmac: add NS2 support
arm64: dts: NS2: add AMAC ethernet support
.../devicetree/bindings/net/brcm,amac.txt | 5 +-
arch/arm64/boot/dts/broadcom/ns2-svk.dts | 5 ++
arch/arm64/boot/dts/broadcom/ns2.dtsi | 12 +++
drivers/net/ethernet/broadcom/bgmac-bcma.c | 48 ++++++++++
drivers/net/ethernet/broadcom/bgmac-platform.c | 100 ++++++++++++++++++++-
drivers/net/ethernet/broadcom/bgmac.c | 55 ++----------
drivers/net/ethernet/broadcom/bgmac.h | 8 ++
drivers/net/phy/Kconfig | 2 +-
drivers/net/phy/broadcom.c | 68 +++++++++++++-
include/linux/brcmphy.h | 11 +++
10 files changed, 260 insertions(+), 54 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH v2 1/6] net: phy: broadcom: add bcm54xx_auxctl_read
From: Jon Mason @ 2016-10-28 20:56 UTC (permalink / raw)
To: David Miller, Rob Herring, Mark Rutland, Florian Fainelli
Cc: rafal, bcm-kernel-feedback-list, netdev, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <1477688219-3871-1-git-send-email-jon.mason@broadcom.com>
Add a helper function to read the AUXCTL register for the BCM54xx. This
mirrors the bcm54xx_auxctl_write function already present in the code.
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
drivers/net/phy/broadcom.c | 10 ++++++++++
include/linux/brcmphy.h | 1 +
2 files changed, 11 insertions(+)
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 583ef8a..3a64b3d 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -30,6 +30,16 @@ MODULE_DESCRIPTION("Broadcom PHY driver");
MODULE_AUTHOR("Maciej W. Rozycki");
MODULE_LICENSE("GPL");
+static int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum)
+{
+ /* The register must be written to both the Shadow Register Select and
+ * the Shadow Read Register Selector
+ */
+ phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum |
+ regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT);
+ return phy_read(phydev, MII_BCM54XX_AUX_CTL);
+}
+
static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
{
return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index 60def78..0ed6691 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -110,6 +110,7 @@
#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
+#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12
#define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007
--
2.7.4
^ permalink raw reply related
* [PATCH v2 2/6] net: phy: broadcom: Add BCM54810 PHY entry
From: Jon Mason @ 2016-10-28 20:56 UTC (permalink / raw)
To: David Miller, Rob Herring, Mark Rutland, Florian Fainelli
Cc: rafal, bcm-kernel-feedback-list, netdev, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <1477688219-3871-1-git-send-email-jon.mason@broadcom.com>
The BCM54810 PHY requires some semi-unique configuration, which results
in some additional configuration in addition to the standard config.
Also, some users of the BCM54810 require the PHY lanes to be swapped.
Since there is no way to detect this, add a device tree query to see if
it is applicable.
Inspired-by: Vikas Soni <vsoni@broadcom.com>
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
drivers/net/phy/Kconfig | 2 +-
drivers/net/phy/broadcom.c | 58 +++++++++++++++++++++++++++++++++++++++++++++-
include/linux/brcmphy.h | 10 ++++++++
3 files changed, 68 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 45f68ea..31967ca 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -217,7 +217,7 @@ config BROADCOM_PHY
select BCM_NET_PHYLIB
---help---
Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
- BCM5481 and BCM5482 PHYs.
+ BCM5481, BCM54810 and BCM5482 PHYs.
config CICADA_PHY
tristate "Cicada PHYs"
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 3a64b3d..777ea29 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -18,7 +18,7 @@
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/brcmphy.h>
-
+#include <linux/of.h>
#define BRCM_PHY_MODEL(phydev) \
((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
@@ -45,6 +45,34 @@ static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
}
+static int bcm54810_config(struct phy_device *phydev)
+{
+ int rc, val;
+
+ val = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
+ val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
+ rc = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
+ val);
+ if (rc < 0)
+ return rc;
+
+ val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
+ val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
+ val |= MII_BCM54XX_AUXCTL_MISC_WREN;
+ rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
+ val);
+ if (rc < 0)
+ return rc;
+
+ val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
+ val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
+ rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
static int bcm50610_a0_workaround(struct phy_device *phydev)
{
@@ -217,6 +245,12 @@ static int bcm54xx_config_init(struct phy_device *phydev)
(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
bcm54xx_adjust_rxrefclk(phydev);
+ if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
+ err = bcm54810_config(phydev);
+ if (err)
+ return err;
+ }
+
bcm54xx_phydsp_config(phydev);
return 0;
@@ -314,6 +348,7 @@ static int bcm5482_read_status(struct phy_device *phydev)
static int bcm5481_config_aneg(struct phy_device *phydev)
{
+ struct device_node *np = phydev->mdio.dev.of_node;
int ret;
/* Aneg firsly. */
@@ -344,6 +379,14 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
phy_write(phydev, 0x18, reg);
}
+ if (of_property_read_bool(np, "brcm,enet-phy-lane-swap")) {
+ /* Lane Swap - Undocumented register...magic! */
+ ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
+ 0x11B);
+ if (ret < 0)
+ return ret;
+ }
+
return ret;
}
@@ -578,6 +621,18 @@ static struct phy_driver broadcom_drivers[] = {
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
}, {
+ .phy_id = PHY_ID_BCM54810,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Broadcom BCM54810",
+ .features = PHY_GBIT_FEATURES |
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = bcm54xx_config_init,
+ .config_aneg = bcm5481_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = bcm_phy_ack_intr,
+ .config_intr = bcm_phy_config_intr,
+}, {
.phy_id = PHY_ID_BCM5482,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5482",
@@ -661,6 +716,7 @@ static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
{ PHY_ID_BCM54616S, 0xfffffff0 },
{ PHY_ID_BCM5464, 0xfffffff0 },
{ PHY_ID_BCM5481, 0xfffffff0 },
+ { PHY_ID_BCM54810, 0xfffffff0 },
{ PHY_ID_BCM5482, 0xfffffff0 },
{ PHY_ID_BCM50610, 0xfffffff0 },
{ PHY_ID_BCM50610M, 0xfffffff0 },
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index 0ed6691..69c7a79 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -13,6 +13,7 @@
#define PHY_ID_BCM5241 0x0143bc30
#define PHY_ID_BCMAC131 0x0143bc70
#define PHY_ID_BCM5481 0x0143bca0
+#define PHY_ID_BCM54810 0x03625d00
#define PHY_ID_BCM5482 0x0143bcb0
#define PHY_ID_BCM5411 0x00206070
#define PHY_ID_BCM5421 0x002060e0
@@ -56,6 +57,8 @@
#define PHY_BRCM_EXT_IBND_TX_ENABLE 0x00002000
#define PHY_BRCM_CLEAR_RGMII_MODE 0x00004000
#define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00008000
+#define PHY_BRCM_EXP_LANE_SWAP 0x00010000
+
/* Broadcom BCM7xxx specific workarounds */
#define PHY_BRCM_7XXX_REV(x) (((x) >> 8) & 0xff)
#define PHY_BRCM_7XXX_PATCH(x) ((x) & 0xff)
@@ -111,6 +114,7 @@
#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN (1 << 8)
#define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007
@@ -192,6 +196,12 @@
#define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */
#define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */
+/* BCM54810 Registers */
+#define BCM54810_EXP_BROADREACH_LRE_MISC_CTL (MII_BCM54XX_EXP_SEL_ER + 0x90)
+#define BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN (1 << 0)
+#define BCM54810_SHD_CLK_CTL 0x3
+#define BCM54810_SHD_CLK_CTL_GTXCLK_EN (1 << 9)
+
/*****************************************************************************/
/* Fast Ethernet Transceiver definitions. */
--
2.7.4
^ permalink raw reply related
* [PATCH v2 4/6] net: ethernet: bgmac: device tree phy enablement
From: Jon Mason @ 2016-10-28 20:56 UTC (permalink / raw)
To: David Miller, Rob Herring, Mark Rutland, Florian Fainelli
Cc: rafal, bcm-kernel-feedback-list, netdev, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <1477688219-3871-1-git-send-email-jon.mason@broadcom.com>
Change the bgmac driver to allow for phy's defined by the device tree
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
drivers/net/ethernet/broadcom/bgmac-bcma.c | 48 ++++++++++++++++++++++++
drivers/net/ethernet/broadcom/bgmac-platform.c | 48 +++++++++++++++++++++++-
drivers/net/ethernet/broadcom/bgmac.c | 52 ++------------------------
drivers/net/ethernet/broadcom/bgmac.h | 7 ++++
4 files changed, 105 insertions(+), 50 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bgmac-bcma.c b/drivers/net/ethernet/broadcom/bgmac-bcma.c
index c16ec3a..3e3efde 100644
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
@@ -80,6 +80,50 @@ static void bcma_bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset, u32 mask,
bcma_maskset32(bgmac->bcma.cmn, offset, mask, set);
}
+static int bcma_phy_connect(struct bgmac *bgmac)
+{
+ struct phy_device *phy_dev;
+ char bus_id[MII_BUS_ID_SIZE + 3];
+
+ /* Connect to the PHY */
+ snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id,
+ bgmac->phyaddr);
+ phy_dev = phy_connect(bgmac->net_dev, bus_id, bgmac_adjust_link,
+ PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phy_dev)) {
+ dev_err(bgmac->dev, "PHY connecton failed\n");
+ return PTR_ERR(phy_dev);
+ }
+
+ return 0;
+}
+
+static int bcma_phy_direct_connect(struct bgmac *bgmac)
+{
+ struct fixed_phy_status fphy_status = {
+ .link = 1,
+ .speed = SPEED_1000,
+ .duplex = DUPLEX_FULL,
+ };
+ struct phy_device *phy_dev;
+ int err;
+
+ phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL);
+ if (!phy_dev || IS_ERR(phy_dev)) {
+ dev_err(bgmac->dev, "Failed to register fixed PHY device\n");
+ return -ENODEV;
+ }
+
+ err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link,
+ PHY_INTERFACE_MODE_MII);
+ if (err) {
+ dev_err(bgmac->dev, "Connecting PHY failed\n");
+ return err;
+ }
+
+ return err;
+}
+
static const struct bcma_device_id bgmac_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT,
BCMA_ANY_REV, BCMA_ANY_CLASS),
@@ -275,6 +319,10 @@ static int bgmac_probe(struct bcma_device *core)
bgmac->cco_ctl_maskset = bcma_bgmac_cco_ctl_maskset;
bgmac->get_bus_clock = bcma_bgmac_get_bus_clock;
bgmac->cmn_maskset32 = bcma_bgmac_cmn_maskset32;
+ if (bgmac->mii_bus)
+ bgmac->phy_connect = bcma_phy_connect;
+ else
+ bgmac->phy_connect = bcma_phy_direct_connect;
err = bgmac_enet_probe(bgmac);
if (err)
diff --git a/drivers/net/ethernet/broadcom/bgmac-platform.c b/drivers/net/ethernet/broadcom/bgmac-platform.c
index be52f27..aed5dc5 100644
--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
+++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
@@ -16,6 +16,7 @@
#include <linux/bcma/bcma.h>
#include <linux/etherdevice.h>
#include <linux/of_address.h>
+#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include "bgmac.h"
@@ -86,6 +87,46 @@ static void platform_bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset,
WARN_ON(1);
}
+static int platform_phy_connect(struct bgmac *bgmac)
+{
+ struct phy_device *phy_dev;
+
+ phy_dev = of_phy_get_and_connect(bgmac->net_dev, bgmac->dev->of_node,
+ bgmac_adjust_link);
+ if (!phy_dev) {
+ dev_err(bgmac->dev, "Phy connect failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int platform_phy_direct_connect(struct bgmac *bgmac)
+{
+ struct fixed_phy_status fphy_status = {
+ .link = 1,
+ .speed = SPEED_1000,
+ .duplex = DUPLEX_FULL,
+ };
+ struct phy_device *phy_dev;
+ int err;
+
+ phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL);
+ if (!phy_dev || IS_ERR(phy_dev)) {
+ dev_err(bgmac->dev, "Failed to register fixed PHY device\n");
+ return -ENODEV;
+ }
+
+ err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link,
+ PHY_INTERFACE_MODE_MII);
+ if (err) {
+ dev_err(bgmac->dev, "Connecting PHY failed\n");
+ return err;
+ }
+
+ return err;
+}
+
static int bgmac_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -102,7 +143,6 @@ static int bgmac_probe(struct platform_device *pdev)
/* Set the features of the 4707 family */
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
- bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4;
bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP;
bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP;
@@ -151,6 +191,12 @@ static int bgmac_probe(struct platform_device *pdev)
bgmac->cco_ctl_maskset = platform_bgmac_cco_ctl_maskset;
bgmac->get_bus_clock = platform_bgmac_get_bus_clock;
bgmac->cmn_maskset32 = platform_bgmac_cmn_maskset32;
+ if (of_parse_phandle(np, "phy-handle", 0)) {
+ bgmac->phy_connect = platform_phy_connect;
+ } else {
+ bgmac->phy_connect = platform_phy_direct_connect;
+ bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
+ }
return bgmac_enet_probe(bgmac);
}
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 856379c..4584958 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1388,7 +1388,7 @@ static const struct ethtool_ops bgmac_ethtool_ops = {
* MII
**************************************************/
-static void bgmac_adjust_link(struct net_device *net_dev)
+void bgmac_adjust_link(struct net_device *net_dev)
{
struct bgmac *bgmac = netdev_priv(net_dev);
struct phy_device *phy_dev = net_dev->phydev;
@@ -1411,50 +1411,7 @@ static void bgmac_adjust_link(struct net_device *net_dev)
phy_print_status(phy_dev);
}
}
-
-static int bgmac_phy_connect_direct(struct bgmac *bgmac)
-{
- struct fixed_phy_status fphy_status = {
- .link = 1,
- .speed = SPEED_1000,
- .duplex = DUPLEX_FULL,
- };
- struct phy_device *phy_dev;
- int err;
-
- phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL);
- if (!phy_dev || IS_ERR(phy_dev)) {
- dev_err(bgmac->dev, "Failed to register fixed PHY device\n");
- return -ENODEV;
- }
-
- err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link,
- PHY_INTERFACE_MODE_MII);
- if (err) {
- dev_err(bgmac->dev, "Connecting PHY failed\n");
- return err;
- }
-
- return err;
-}
-
-static int bgmac_phy_connect(struct bgmac *bgmac)
-{
- struct phy_device *phy_dev;
- char bus_id[MII_BUS_ID_SIZE + 3];
-
- /* Connect to the PHY */
- snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id,
- bgmac->phyaddr);
- phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link,
- PHY_INTERFACE_MODE_MII);
- if (IS_ERR(phy_dev)) {
- dev_err(bgmac->dev, "PHY connecton failed\n");
- return PTR_ERR(phy_dev);
- }
-
- return 0;
-}
+EXPORT_SYMBOL_GPL(bgmac_adjust_link);
int bgmac_enet_probe(struct bgmac *info)
{
@@ -1507,10 +1464,7 @@ int bgmac_enet_probe(struct bgmac *info)
netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
- if (!bgmac->mii_bus)
- err = bgmac_phy_connect_direct(bgmac);
- else
- err = bgmac_phy_connect(bgmac);
+ err = bgmac_phy_connect(bgmac);
if (err) {
dev_err(bgmac->dev, "Cannot connect to phy\n");
goto err_dma_free;
diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h
index 80836b4..ea52ac3 100644
--- a/drivers/net/ethernet/broadcom/bgmac.h
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -513,10 +513,12 @@ struct bgmac {
u32 (*get_bus_clock)(struct bgmac *bgmac);
void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask,
u32 set);
+ int (*phy_connect)(struct bgmac *bgmac);
};
int bgmac_enet_probe(struct bgmac *info);
void bgmac_enet_remove(struct bgmac *bgmac);
+void bgmac_adjust_link(struct net_device *net_dev);
struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr);
void bcma_mdio_mii_unregister(struct mii_bus *mii_bus);
@@ -583,4 +585,9 @@ static inline void bgmac_set(struct bgmac *bgmac, u16 offset, u32 set)
{
bgmac_maskset(bgmac, offset, ~0, set);
}
+
+static inline int bgmac_phy_connect(struct bgmac *bgmac)
+{
+ return bgmac->phy_connect(bgmac);
+}
#endif /* _BGMAC_H */
--
2.7.4
^ permalink raw reply related
* [PATCH v2 6/6] arm64: dts: NS2: add AMAC ethernet support
From: Jon Mason @ 2016-10-28 20:56 UTC (permalink / raw)
To: David Miller, Rob Herring, Mark Rutland, Florian Fainelli
Cc: rafal, bcm-kernel-feedback-list, netdev, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <1477688219-3871-1-git-send-email-jon.mason@broadcom.com>
Add support for the AMAC ethernet to the Broadcom Northstar2 SoC device
tree
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
arch/arm64/boot/dts/broadcom/ns2-svk.dts | 5 +++++
arch/arm64/boot/dts/broadcom/ns2.dtsi | 12 ++++++++++++
2 files changed, 17 insertions(+)
diff --git a/arch/arm64/boot/dts/broadcom/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
index 2d7872a..9e5c3c9 100644
--- a/arch/arm64/boot/dts/broadcom/ns2-svk.dts
+++ b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
@@ -56,6 +56,10 @@
};
};
+&enet {
+ status = "ok";
+};
+
&pci_phy0 {
status = "ok";
};
@@ -172,6 +176,7 @@
&mdio_mux_iproc {
mdio@10 {
gphy0: eth-phy@10 {
+ brcm,enet-phy-lane-swap;
reg = <0x10>;
};
};
diff --git a/arch/arm64/boot/dts/broadcom/ns2.dtsi b/arch/arm64/boot/dts/broadcom/ns2.dtsi
index d95dc40..773ed59 100644
--- a/arch/arm64/boot/dts/broadcom/ns2.dtsi
+++ b/arch/arm64/boot/dts/broadcom/ns2.dtsi
@@ -191,6 +191,18 @@
#include "ns2-clock.dtsi"
+ enet: ethernet@61000000 {
+ compatible = "brcm,ns2-amac";
+ reg = <0x61000000 0x1000>,
+ <0x61090000 0x1000>,
+ <0x61030000 0x100>;
+ reg-names = "amac_base", "idm_base", "nicpm_base";
+ interrupts = <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>;
+ phy-handle = <&gphy0>;
+ phy-mode = "rgmii";
+ status = "disabled";
+ };
+
dma0: dma@61360000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x61360000 0x1000>;
--
2.7.4
^ permalink raw reply related
* [PATCH v2 3/6] Documentation: devicetree: net: add NS2 bindings to amac
From: Jon Mason @ 2016-10-28 20:56 UTC (permalink / raw)
To: David Miller, Rob Herring, Mark Rutland, Florian Fainelli
Cc: rafal, bcm-kernel-feedback-list, netdev, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <1477688219-3871-1-git-send-email-jon.mason@broadcom.com>
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
Documentation/devicetree/bindings/net/brcm,amac.txt | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/brcm,amac.txt b/Documentation/devicetree/bindings/net/brcm,amac.txt
index ba5ecc1..f2b194e 100644
--- a/Documentation/devicetree/bindings/net/brcm,amac.txt
+++ b/Documentation/devicetree/bindings/net/brcm,amac.txt
@@ -2,11 +2,12 @@ Broadcom AMAC Ethernet Controller Device Tree Bindings
-------------------------------------------------------------
Required properties:
- - compatible: "brcm,amac" or "brcm,nsp-amac"
+ - compatible: "brcm,amac", "brcm,nsp-amac", or "brcm,ns2-amac"
- reg: Address and length of the GMAC registers,
Address and length of the GMAC IDM registers
+ Address and length of the NIC Port Manager registers (optional)
- reg-names: Names of the registers. Must have both "amac_base" and
- "idm_base"
+ "idm_base". "nicpm_base" is optional (required for NS2)
- interrupts: Interrupt number
Optional properties:
--
2.7.4
^ permalink raw reply related
* [PATCH v2 5/6] net: ethernet: bgmac: add NS2 support
From: Jon Mason @ 2016-10-28 20:56 UTC (permalink / raw)
To: David Miller, Rob Herring, Mark Rutland, Florian Fainelli
Cc: rafal, bcm-kernel-feedback-list, netdev, devicetree,
linux-arm-kernel, linux-kernel
In-Reply-To: <1477688219-3871-1-git-send-email-jon.mason@broadcom.com>
Add support for the variant of amac hardware present in the Broadcom
Northstar2 based SoCs. Northstar2 requires an additional register to be
configured with the port speed/duplexity (NICPM). This can be added to
the link callback to hide it from the instances that do not use this.
Also, clearing of the pending interrupts on init is required due to
observed issues on some platforms.
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
---
drivers/net/ethernet/broadcom/bgmac-platform.c | 56 +++++++++++++++++++++++++-
drivers/net/ethernet/broadcom/bgmac.c | 3 ++
drivers/net/ethernet/broadcom/bgmac.h | 1 +
3 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bgmac-platform.c b/drivers/net/ethernet/broadcom/bgmac-platform.c
index aed5dc5..f6d48c7 100644
--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
+++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
@@ -14,12 +14,21 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bcma/bcma.h>
+#include <linux/brcmphy.h>
#include <linux/etherdevice.h>
#include <linux/of_address.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include "bgmac.h"
+#define NICPM_IOMUX_CTRL 0x00000008
+
+#define NICPM_IOMUX_CTRL_INIT_VAL 0x3196e000
+#define NICPM_IOMUX_CTRL_SPD_SHIFT 10
+#define NICPM_IOMUX_CTRL_SPD_10M 0
+#define NICPM_IOMUX_CTRL_SPD_100M 1
+#define NICPM_IOMUX_CTRL_SPD_1000M 2
+
static u32 platform_bgmac_read(struct bgmac *bgmac, u16 offset)
{
return readl(bgmac->plat.base + offset);
@@ -87,12 +96,46 @@ static void platform_bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset,
WARN_ON(1);
}
+static void bgmac_nicpm_speed_set(struct net_device *net_dev)
+{
+ struct bgmac *bgmac = netdev_priv(net_dev);
+ u32 val;
+
+ if (!bgmac->plat.nicpm_base)
+ return;
+
+ val = NICPM_IOMUX_CTRL_INIT_VAL;
+ switch (bgmac->net_dev->phydev->speed) {
+ default:
+ pr_err("Unsupported speed. Defaulting to 1000Mb\n");
+ case SPEED_1000:
+ val |= NICPM_IOMUX_CTRL_SPD_1000M << NICPM_IOMUX_CTRL_SPD_SHIFT;
+ break;
+ case SPEED_100:
+ val |= NICPM_IOMUX_CTRL_SPD_100M << NICPM_IOMUX_CTRL_SPD_SHIFT;
+ break;
+ case SPEED_10:
+ val |= NICPM_IOMUX_CTRL_SPD_10M << NICPM_IOMUX_CTRL_SPD_SHIFT;
+ break;
+ }
+
+ writel(val, bgmac->plat.nicpm_base + NICPM_IOMUX_CTRL);
+
+ bgmac_adjust_link(bgmac->net_dev);
+}
+
static int platform_phy_connect(struct bgmac *bgmac)
{
struct phy_device *phy_dev;
- phy_dev = of_phy_get_and_connect(bgmac->net_dev, bgmac->dev->of_node,
- bgmac_adjust_link);
+ if (bgmac->plat.nicpm_base)
+ phy_dev = of_phy_get_and_connect(bgmac->net_dev,
+ bgmac->dev->of_node,
+ bgmac_nicpm_speed_set);
+ else
+ phy_dev = of_phy_get_and_connect(bgmac->net_dev,
+ bgmac->dev->of_node,
+ bgmac_adjust_link);
if (!phy_dev) {
dev_err(bgmac->dev, "Phy connect failed\n");
return -ENODEV;
@@ -182,6 +225,14 @@ static int bgmac_probe(struct platform_device *pdev)
if (IS_ERR(bgmac->plat.idm_base))
return PTR_ERR(bgmac->plat.idm_base);
+ regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nicpm_base");
+ if (regs) {
+ bgmac->plat.nicpm_base = devm_ioremap_resource(&pdev->dev,
+ regs);
+ if (IS_ERR(bgmac->plat.nicpm_base))
+ return PTR_ERR(bgmac->plat.nicpm_base);
+ }
+
bgmac->read = platform_bgmac_read;
bgmac->write = platform_bgmac_write;
bgmac->idm_read = platform_bgmac_idm_read;
@@ -213,6 +264,7 @@ static int bgmac_remove(struct platform_device *pdev)
static const struct of_device_id bgmac_of_enet_match[] = {
{.compatible = "brcm,amac",},
{.compatible = "brcm,nsp-amac",},
+ {.compatible = "brcm,ns2-amac",},
{},
};
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 4584958..a805cc8 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1082,6 +1082,9 @@ static void bgmac_enable(struct bgmac *bgmac)
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */
static void bgmac_chip_init(struct bgmac *bgmac)
{
+ /* Clear any erroneously pending interrupts */
+ bgmac_write(bgmac, BGMAC_INT_STATUS, ~0);
+
/* 1 interrupt per received frame */
bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT);
diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h
index ea52ac3..b1820ea 100644
--- a/drivers/net/ethernet/broadcom/bgmac.h
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -463,6 +463,7 @@ struct bgmac {
struct {
void *base;
void *idm_base;
+ void *nicpm_base;
} plat;
struct {
struct bcma_device *core;
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] net: phy: at803x: the Atheros 8031 supports pause frames
From: Florian Fainelli @ 2016-10-28 21:03 UTC (permalink / raw)
To: Timur Tabi, netdev, zefir.kurtisi, scampbel, alokc, shankerd,
andrew
In-Reply-To: <5813AFC1.50506@codeaurora.org>
On 10/28/2016 01:06 PM, Timur Tabi wrote:
> Florian Fainelli wrote:
>> On 10/27/2016 03:24 PM, Timur Tabi wrote:
>>> Florian Fainelli wrote:
>>>
>>>> Hu? In my experience that should not come from supporting Pause frames
>>>> or not, but rather properly configuring a (RG)MII delay, but your
>>>> mileage may vary.
>>>
>>> I can assure you, I'm more confused than you. I've been working in this
>>> for almost two weeks, and not only does this patch align with other phy
>>> drivers, but it does fix my bug. Without this patch, phylib does not
>>> set the pause frame bits (10 and 11) in MII_ADVERTISE.
>>
>> And that's expected, but if your MAC does not act upon phydev->pause and
>> phydev->asym_pause, then chances are that you can indeed lose packets
>> every once in a while.
>
> Can you give me more details on that? I'm not really an expert on our
> MAC, so I'm not sure how it's supposed to work. The MAC supports the
> concept of "flow control". The non-upstream version of my driver reads
> PHY register 0x11, which apparently is a PHY-specific status register
> that says whether or not "transmit pause" and "receive pause" is
> enabled. (The AT8031 datasheet is here, if you'd like to read it:
> http://www.datasheet-pdf.com/datasheet/AtherosCommunications/734720/AR8031.pdf.html).
How it works is that you read phydev->pause and phydev->asym_pause to
know what your link partner advertises in terms of flow control/pause
frame (they are the same thing here). Based on that, and your local
settings (from ethool -A) you advertise/enable flow control as well or
don't do it, and the result is either both agree on what is being used,
flow control is enabled, end-to-end, or it is not. It's exactly the same
thing as speed, except that there is a possibly to do asymetric things,
where flow control is only enabled in one direction or the other.
The way this works is this:
You transmit data, faster than your link partner can process it (busy
receiving, loaded, you name it), it sends back Pause frames back at you
(see below for how this is typically implemented), your MAC gets these
Pause frames back, which feed into the transmit logic, your TX
completion interrupt gets signaled slower than the actual data rate you
are pushing to your link partner, you call dev_kfree_skb() a little
slower from your TX completion handler, the networking stack knows this
means to back off, your transmission rate adjusts to your link partner's
processing capability, no packets get lost.
Conversely, if you were receiving a stream of packets that you have a
hard time keeping up with, the part of your Ethernet MAC that fills
system memory with packets should realize that it is producing them
faster than you are consuming them, this triggers the flow control
mechanism of your MAC receiver, and it sends Pause frames back at the
link partner.
>
>
> If both are enabled in the PHY, then the driver enables the same
> features in the MAC. Unfortunately, I don't have any documentation that
> explains that that really means. I've tried enabling and disabling this
> feature in the MAC, and it makes no difference. You would think that if
> the feature is disabled in both the MAC and the PHY, then no packets
> would be lost, but that's not the case.
The PHY does not participate in flow control, other than passing frames
through (and your Atheros PHY may have a register to control that
passthrough, but that would be surprising, could not find one).
>
>> The part that is totally crappy about Pause frames and PHYLIB is that we
>> need some information about whether this should be supported or not,
>> such that we can change MII_ADVERTISE accordingly to reflect that, and
>> what best way to do this than use one of these SUPPORTED_* bits to set
>> that, except, that unlike speed (which is both a MAC and PHY property),
>> Pause is exclusively MAC, yet, it transpires in PHYLIB.
>
> Then what do those bits in register 0x11 do? If I don't set them, I
> lose packets, no matter how my MAC is programmed.
This is just a status register, as you can see, all bits are read-only,
it just aggregates the resolution of what is advertised and what is
negotiated, which is not without value, but PHYLIB does the same
intersection here.
>
> It's like that joke, "Doctor, if I hold my arm like this, then it
> hurts!", "Well, then don't hold your arm like that." If I don't program
> those PHY register bits, then my hardware doesn't work.
>
>> MACs that I work with for instance need to be told to ignore pause
>> frames, or not ignore them, it all depends on what you want to
>> advertise/support.
>
> That's the problem, I don't know what I "want", except that I want my
> hardware to work. :-) 99% of my knowledge of the hardware comes from
> scanning the source code of the internal version of the driver that 1)
> does not support phylib, and 2) is hard-coded to initialize the Atheros
> 8031 PHY.
May I suggest reading about standards a bit more, or just looking at
other drivers, like tg3.c.
>
>>>> It does not, support for Pause frames is a MAC-level feature, yet,
>>>> PHYLIB (and that's been on my todo for a while now) insists on
>>>> reporting
>>>> the confusing phydev->pause and phydev->asym_pause, which really is
>>>> what
>>>> has been determined from auto-negotiating with your partner, as opposed
>>>> to being a supported thing or not. The PHY has absolutely not business
>>>> in that.
>>>
>>> But there are pause frame bits in the MII_ADVERTISE register, and this
>>> setting directly impacts whether those bits are set. I don't see how
>>> this is a MAC-level feature.
>>
>> This is a MAC level feature, that needs to be auto-negotiated with your
>> link partner, which is why there is room for this in MII_ADVERTISE, but
>> the PHY absolutely does not participate in Pause frames, other than
>> passing them through the MAC, like normal frames. Whether your MAC acts
>> upon that or not is a MAC dependent feature.
>
> Ok, to me that means that the PHY driver must tell phylib whether or not
> it supports pause frames. The question becomes:
>
> 1) Is my patch correct?
> 2) Is my patch necessary?
> 3) Is my patch sufficient?
Your patch is correct but also insufficient, although, as indicated
before, there is an misconception with PHY drivers that they should be
setting SUPPORTED_*Pause* bits, the MAC should do that, based on what it
does, anyway, but more importantly you need to have your Ethernet MAC
react properly upon what the auto-negotiation and locally configured
pause/flow control settings are, and configure the Ethernet MAC accordingly.
When you want pause frames to be enabled, you need to advertise them,
and in order to do so, you need to set phydev->supported to have
SUPPORTED_Pause and SUPPORTED_AsymPause, and call genphy_restart_aneg()
to transfer that to a write to the MII_ADVERTISE register, resulting in
your link partner to see that you now support Pause frames. Since pause
frames are now in use, you want your Ethernet MAC, not to ignore pause
frames (have flow control enabled).
>
> 1) I believe my patch is correct, because many other PHY drivers do the
> same thing for the same reason. If the PHY supports register 4 bits 10
> and 11, then those SUPPORTED_xxx bits should be set.
>
> 2) I don't know why my patch appears to be necessary, because I don't
> understand why a 1Gb NIC on a 2Ghz processor drops frames. I suspect
> the program is not performance but rather a mis-programming.
>
> 4) Is my patch sufficient? The internal driver always enables pause
> frame support in the PHY if the PHY says that pause frames are enabled.
> In fact, I can't even turn off flow control in the internal driver:
Please stop abusing this "PHY says", the PHY advertises what it is being
told to advertise, by the MAC...
>
> $ sudo ethtool -A eth1 tx off rx off
> $ sudo ethtool -a eth1
> Pause parameters for eth1:
> Autonegotiate: on
> RX: on
> TX: on
>
> The driver insists on leaving flow control enabled if autonegotiation is
> enabled.
Actually, the driver forces the enabling of flow control in the MAC,
period, but does not do anything with the auto-negotiation results, or I
could not spot it.
This was spotted in the review, but not addressed, but your adjust_link
callback seems completely bogus, it does a full MAC stop,
reconfiguration and restart, that is at best unnecessary and costly, but
it also misses a few things and does not act upon reading phydev->pause
and phydev->asym_pause to set or clear TXFC and RXFC, that really seems
to be your problem here.
Here is what could possibly go wrong right now:
- your Ethernet MAC unconditionally enables flow control at the MAC
level, but does not advertise support for that in MII_ADVERTISE until
you set SUPPORTED_Pause and SUPPORTED_Asym_Pause in the PHY driver, fair
enough
- the link partner you are testing against does not keep up well with
your transmit rates, but supports flow control, so Pause frames that it
sends back at you to tell you to stop transmitting so quickly just get
ignored, because not being advertised, you experience packet loss
--
Florian
^ permalink raw reply
* Re: [PATCH 17/17] batman-adv: Avoid precedence issues in macros
From: Joe Perches @ 2016-10-28 21:13 UTC (permalink / raw)
To: Simon Wunderlich, davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann
In-Reply-To: <20161027190150.7880-18-sw@simonwunderlich.de>
On Thu, 2016-10-27 at 21:01 +0200, Simon Wunderlich wrote:
> From: Sven Eckelmann <sven@narfation.org>
>
> It must be avoided that arguments to a macro are evaluated ungrouped (which
> enforces normal operator precendence). Otherwise the result of the macro
> is not well defined.
Curiosity:
in net/batman-adv/tp_meter.c
static int batadv_tp_send(void *arg)
{
struct batadv_tp_vars *tp_vars = arg;
struct batadv_priv *bat_priv = tp_vars->bat_priv;
struct batadv_hard_iface *primary_if = NULL;
struct batadv_orig_node *orig_node = NULL;
size_t payload_len, packet_len;
int err = 0;
if (unlikely(tp_vars->role != BATADV_TP_SENDER)) {
err = BATADV_TP_REASON_DST_UNREACHABLE;
tp_vars->reason = err;
goto out;
}
orig_node = batadv_orig_hash_find(bat_priv, tp_vars->other_end);
if (unlikely(!orig_node)) {
err = BATADV_TP_REASON_DST_UNREACHABLE;
tp_vars->reason = err;
goto out;
}
primary_if = batadv_primary_if_get_selected(bat_priv);
if (unlikely(!primary_if)) {
err = BATADV_TP_REASON_DST_UNREACHABLE;
goto out;
}
err is not used in the out block
Is the last if block supposed to set tp_vars->reason to err?
^ permalink raw reply
* Re: [PATCH net] net: clear sk_err_soft in sk_clone_lock()
From: Soheil Hassas Yeganeh @ 2016-10-28 21:25 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1477687224.7065.261.camel@edumazet-glaptop3.roam.corp.google.com>
On Fri, Oct 28, 2016 at 4:40 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> At accept() time, it is possible the parent has a non zero
> sk_err_soft, leftover from a prior error.
>
> Make sure we do not leave this value in the child, as it
> makes future getsockopt(SO_ERROR) calls quite unreliable.
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Soheil Hassas Yeganeh <soheil@google.com>
> ---
> net/core/sock.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/net/core/sock.c b/net/core/sock.c
> index d8e4532e89e7c28737c95c723e5f5b3d184a7805..662ccf1c40ed1b66ee253b063dcbfbd186deccee 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1543,6 +1543,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
> RCU_INIT_POINTER(newsk->sk_reuseport_cb, NULL);
>
> newsk->sk_err = 0;
> + newsk->sk_err_soft = 0;
> newsk->sk_priority = 0;
> newsk->sk_incoming_cpu = raw_smp_processor_id();
> atomic64_set(&newsk->sk_cookie, 0);
>
>
Very nice catch! Thank you, Eric!
^ permalink raw reply
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