Netdev List
 help / color / mirror / Atom feed
* [for-next 4/6] net/mlx5: FPGA, Add basic support for Innova
From: Saeed Mahameed @ 2017-05-23 11:44 UTC (permalink / raw)
  To: David S. Miller, Doug Ledford
  Cc: netdev, linux-rdma, Ilan Tayari, Saeed Mahameed
In-Reply-To: <20170523114404.20387-1-saeedm@mellanox.com>

From: Ilan Tayari <ilant@mellanox.com>

Mellanox Innova is a NIC with ConnectX and an FPGA on the same
board. The FPGA is a bump-on-the-wire and thus affects operation of
the mlx5_core driver on the ConnectX ASIC.

Add basic support for Innova in mlx5_core.

This allows using the Innova card as a regular NIC, by detecting
the FPGA capability bit, and verifying its load state before
initializing ConnectX interfaces.

Also detect FPGA fatal runtime failures and enter error state if
they ever happen.

All new FPGA-related logic is placed in its own subdirectory 'fpga',
which may be built by selecting CONFIG_MLX5_FPGA.
This prepares for further support of various Innova features in later
patchsets.
Additional details about hardware architecture will be provided as
more features get submitted.

Signed-off-by: Ilan Tayari <ilant@mellanox.com>
Reviewed-by: Boris Pismenny <borisp@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 MAINTAINERS                                        |  10 +
 drivers/net/ethernet/mellanox/mlx5/core/Kconfig    |  10 +
 drivers/net/ethernet/mellanox/mlx5/core/Makefile   |   3 +
 drivers/net/ethernet/mellanox/mlx5/core/eq.c       |  11 ++
 drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c |  64 +++++++
 drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h |  59 ++++++
 .../net/ethernet/mellanox/mlx5/core/fpga/core.c    | 202 +++++++++++++++++++++
 .../net/ethernet/mellanox/mlx5/core/fpga/core.h    |  99 ++++++++++
 drivers/net/ethernet/mellanox/mlx5/core/main.c     |  19 +-
 include/linux/mlx5/device.h                        |   6 +
 include/linux/mlx5/driver.h                        |   5 +
 include/linux/mlx5/mlx5_ifc.h                      |  11 +-
 include/linux/mlx5/mlx5_ifc_fpga.h                 | 144 +++++++++++++++
 13 files changed, 640 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h
 create mode 100644 include/linux/mlx5/mlx5_ifc_fpga.h

diff --git a/MAINTAINERS b/MAINTAINERS
index f7d568b8f133..374ebf1b5d5d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8304,6 +8304,16 @@ W:	http://www.mellanox.com
 Q:	http://patchwork.ozlabs.org/project/netdev/list/
 F:	drivers/net/ethernet/mellanox/mlx5/core/en_*
 
+MELLANOX ETHERNET INNOVA DRIVER
+M:	Ilan Tayari <ilant@mellanox.com>
+R:	Boris Pismenny <borisp@mellanox.com>
+L:	netdev@vger.kernel.org
+S:	Supported
+W:	http://www.mellanox.com
+Q:	http://patchwork.ozlabs.org/project/netdev/list/
+F:	drivers/net/ethernet/mellanox/mlx5/core/fpga/*
+F:	include/linux/mlx5/mlx5_ifc_fpga.h
+
 MELLANOX ETHERNET SWITCH DRIVERS
 M:	Jiri Pirko <jiri@mellanox.com>
 M:	Ido Schimmel <idosch@mellanox.com>
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
index fc52d742b7f7..28cf88483ca4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig
@@ -11,6 +11,16 @@ config MLX5_CORE
 	  Core driver for low level functionality of the ConnectX-4 and
 	  Connect-IB cards by Mellanox Technologies.
 
+config MLX5_FPGA
+        bool "Mellanox Technologies Innova support"
+        depends on MLX5_CORE
+        ---help---
+          Build support for the Innova family of network cards by Mellanox
+          Technologies. Innova network cards are comprised of a ConnectX chip
+          and an FPGA chip on one board. If you select this option, the
+          mlx5_core driver will include the Innova FPGA core and allow building
+          sandbox-specific client drivers.
+
 config MLX5_CORE_EN
 	bool "Mellanox Technologies ConnectX-4 Ethernet support"
 	depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index 9e644615f07a..12556c03eec4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -1,10 +1,13 @@
 obj-$(CONFIG_MLX5_CORE)		+= mlx5_core.o
+subdir-ccflags-y += -I$(src)
 
 mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
 		health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \
 		mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \
 		fs_counters.o rl.o lag.o dev.o
 
+mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o
+
 mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \
 		en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \
 		en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index df0034d8f48c..01d2cd7e4746 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -35,6 +35,7 @@
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/cmd.h>
 #include "mlx5_core.h"
+#include "fpga/core.h"
 #ifdef CONFIG_MLX5_CORE_EN
 #include "eswitch.h"
 #endif
@@ -156,6 +157,8 @@ static const char *eqe_type_str(u8 type)
 		return "MLX5_EVENT_TYPE_PAGE_FAULT";
 	case MLX5_EVENT_TYPE_PPS_EVENT:
 		return "MLX5_EVENT_TYPE_PPS_EVENT";
+	case MLX5_EVENT_TYPE_FPGA_ERROR:
+		return "MLX5_EVENT_TYPE_FPGA_ERROR";
 	default:
 		return "Unrecognized event";
 	}
@@ -476,6 +479,11 @@ static irqreturn_t mlx5_eq_int(int irq, void *eq_ptr)
 			if (dev->event)
 				dev->event(dev, MLX5_DEV_EVENT_PPS, (unsigned long)eqe);
 			break;
+
+		case MLX5_EVENT_TYPE_FPGA_ERROR:
+			mlx5_fpga_event(dev, eqe->type, &eqe->data.raw);
+			break;
+
 		default:
 			mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n",
 				       eqe->type, eq->eqn);
@@ -693,6 +701,9 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
 	if (MLX5_CAP_GEN(dev, pps))
 		async_event_mask |= (1ull << MLX5_EVENT_TYPE_PPS_EVENT);
 
+	if (MLX5_CAP_GEN(dev, fpga))
+		async_event_mask |= (1ull << MLX5_EVENT_TYPE_FPGA_ERROR);
+
 	err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD,
 				 MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD,
 				 "mlx5_cmd_eq", MLX5_EQ_TYPE_ASYNC);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c
new file mode 100644
index 000000000000..99cba644b4fc
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/mlx5/cmd.h>
+#include <linux/mlx5/driver.h>
+
+#include "mlx5_core.h"
+#include "fpga/cmd.h"
+
+int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps)
+{
+	u32 in[MLX5_ST_SZ_DW(fpga_cap)] = {0};
+
+	return mlx5_core_access_reg(dev, in, sizeof(in), caps,
+				    MLX5_ST_SZ_BYTES(fpga_cap),
+				    MLX5_REG_FPGA_CAP, 0, 0);
+}
+
+int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query)
+{
+	u32 in[MLX5_ST_SZ_DW(fpga_ctrl)] = {0};
+	u32 out[MLX5_ST_SZ_DW(fpga_ctrl)];
+	int err;
+
+	err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
+				   MLX5_REG_FPGA_CTRL, 0, false);
+	if (err)
+		return err;
+
+	query->status = MLX5_GET(fpga_ctrl, out, status);
+	query->admin_image = MLX5_GET(fpga_ctrl, out, flash_select_admin);
+	query->oper_image = MLX5_GET(fpga_ctrl, out, flash_select_oper);
+	return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h
new file mode 100644
index 000000000000..a74396a61bc3
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_FPGA_H__
+#define __MLX5_FPGA_H__
+
+#include <linux/mlx5/driver.h>
+
+enum mlx5_fpga_image {
+	MLX5_FPGA_IMAGE_USER = 0,
+	MLX5_FPGA_IMAGE_FACTORY,
+};
+
+enum mlx5_fpga_status {
+	MLX5_FPGA_STATUS_SUCCESS = 0,
+	MLX5_FPGA_STATUS_FAILURE = 1,
+	MLX5_FPGA_STATUS_IN_PROGRESS = 2,
+	MLX5_FPGA_STATUS_NONE = 0xFFFF,
+};
+
+struct mlx5_fpga_query {
+	enum mlx5_fpga_image admin_image;
+	enum mlx5_fpga_image oper_image;
+	enum mlx5_fpga_status status;
+};
+
+int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps);
+int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query);
+
+#endif /* __MLX5_FPGA_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
new file mode 100644
index 000000000000..d88b332e9669
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/mlx5/driver.h>
+
+#include "mlx5_core.h"
+#include "fpga/core.h"
+
+static const char *const mlx5_fpga_error_strings[] = {
+	"Null Syndrome",
+	"Corrupted DDR",
+	"Flash Timeout",
+	"Internal Link Error",
+	"Watchdog HW Failure",
+	"I2C Failure",
+	"Image Changed",
+	"Temperature Critical",
+};
+
+static struct mlx5_fpga_device *mlx5_fpga_device_alloc(void)
+{
+	struct mlx5_fpga_device *fdev = NULL;
+
+	fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
+	if (!fdev)
+		return NULL;
+
+	spin_lock_init(&fdev->state_lock);
+	fdev->state = MLX5_FPGA_STATUS_NONE;
+	return fdev;
+}
+
+static const char *mlx5_fpga_image_name(enum mlx5_fpga_image image)
+{
+	switch (image) {
+	case MLX5_FPGA_IMAGE_USER:
+		return "user";
+	case MLX5_FPGA_IMAGE_FACTORY:
+		return "factory";
+	default:
+		return "unknown";
+	}
+}
+
+static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev)
+{
+	struct mlx5_fpga_query query;
+	int err;
+
+	err = mlx5_fpga_query(fdev->mdev, &query);
+	if (err) {
+		mlx5_fpga_err(fdev, "Failed to query status: %d\n", err);
+		return err;
+	}
+
+	fdev->last_admin_image = query.admin_image;
+	fdev->last_oper_image = query.oper_image;
+
+	mlx5_fpga_dbg(fdev, "Status %u; Admin image %u; Oper image %u\n",
+		      query.status, query.admin_image, query.oper_image);
+
+	if (query.status != MLX5_FPGA_STATUS_SUCCESS) {
+		mlx5_fpga_err(fdev, "%s image failed to load; status %u\n",
+			      mlx5_fpga_image_name(fdev->last_oper_image),
+			      query.status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int mlx5_fpga_device_start(struct mlx5_core_dev *mdev)
+{
+	struct mlx5_fpga_device *fdev = mdev->fpga;
+	unsigned long flags;
+	int err;
+
+	if (!fdev)
+		return 0;
+
+	err = mlx5_fpga_device_load_check(fdev);
+	if (err)
+		goto out;
+
+	err = mlx5_fpga_caps(fdev->mdev,
+			     fdev->mdev->caps.hca_cur[MLX5_CAP_FPGA]);
+	if (err)
+		goto out;
+
+	mlx5_fpga_info(fdev, "device %u; %s image, version %u\n",
+		       MLX5_CAP_FPGA(fdev->mdev, fpga_device),
+		       mlx5_fpga_image_name(fdev->last_oper_image),
+		       MLX5_CAP_FPGA(fdev->mdev, image_version));
+
+out:
+	spin_lock_irqsave(&fdev->state_lock, flags);
+	fdev->state = err ? MLX5_FPGA_STATUS_FAILURE : MLX5_FPGA_STATUS_SUCCESS;
+	spin_unlock_irqrestore(&fdev->state_lock, flags);
+	return err;
+}
+
+int mlx5_fpga_device_init(struct mlx5_core_dev *mdev)
+{
+	struct mlx5_fpga_device *fdev = NULL;
+
+	if (!MLX5_CAP_GEN(mdev, fpga)) {
+		mlx5_core_dbg(mdev, "FPGA capability not present\n");
+		return 0;
+	}
+
+	mlx5_core_dbg(mdev, "Initializing FPGA\n");
+
+	fdev = mlx5_fpga_device_alloc();
+	if (!fdev)
+		return -ENOMEM;
+
+	fdev->mdev = mdev;
+	mdev->fpga = fdev;
+
+	return 0;
+}
+
+void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev)
+{
+	kfree(mdev->fpga);
+	mdev->fpga = NULL;
+}
+
+static const char *mlx5_fpga_syndrome_to_string(u8 syndrome)
+{
+	if (syndrome < ARRAY_SIZE(mlx5_fpga_error_strings))
+		return mlx5_fpga_error_strings[syndrome];
+	return "Unknown";
+}
+
+void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data)
+{
+	struct mlx5_fpga_device *fdev = mdev->fpga;
+	const char *event_name;
+	bool teardown = false;
+	unsigned long flags;
+	u8 syndrome;
+
+	if (event != MLX5_EVENT_TYPE_FPGA_ERROR) {
+		mlx5_fpga_warn_ratelimited(fdev, "Unexpected event %u\n",
+					   event);
+		return;
+	}
+
+	syndrome = MLX5_GET(fpga_error_event, data, syndrome);
+	event_name = mlx5_fpga_syndrome_to_string(syndrome);
+
+	spin_lock_irqsave(&fdev->state_lock, flags);
+	switch (fdev->state) {
+	case MLX5_FPGA_STATUS_SUCCESS:
+		mlx5_fpga_warn(fdev, "Error %u: %s\n", syndrome, event_name);
+		teardown = true;
+		break;
+	default:
+		mlx5_fpga_warn_ratelimited(fdev, "Unexpected error event %u: %s\n",
+					   syndrome, event_name);
+	}
+	spin_unlock_irqrestore(&fdev->state_lock, flags);
+	/* We tear-down the card's interfaces and functionality because
+	 * the FPGA bump-on-the-wire is misbehaving and we lose ability
+	 * to communicate with the network. User may still be able to
+	 * recover by re-programming or debugging the FPGA
+	 */
+	if (teardown)
+		mlx5_trigger_health_work(fdev->mdev);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h
new file mode 100644
index 000000000000..c55044d66778
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_FPGA_CORE_H__
+#define __MLX5_FPGA_CORE_H__
+
+#ifdef CONFIG_MLX5_FPGA
+
+#include "fpga/cmd.h"
+
+/* Represents an Innova device */
+struct mlx5_fpga_device {
+	struct mlx5_core_dev *mdev;
+	spinlock_t state_lock; /* Protects state transitions */
+	enum mlx5_fpga_status state;
+	enum mlx5_fpga_image last_admin_image;
+	enum mlx5_fpga_image last_oper_image;
+};
+
+#define mlx5_fpga_dbg(__adev, format, ...) \
+	dev_dbg(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \
+		 __func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define mlx5_fpga_err(__adev, format, ...) \
+	dev_err(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \
+		__func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define mlx5_fpga_warn(__adev, format, ...) \
+	dev_warn(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \
+		__func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define mlx5_fpga_warn_ratelimited(__adev, format, ...) \
+	dev_warn_ratelimited(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d: " \
+		format, __func__, __LINE__, ##__VA_ARGS__)
+
+#define mlx5_fpga_notice(__adev, format, ...) \
+	dev_notice(&(__adev)->mdev->pdev->dev, "FPGA: " format, ##__VA_ARGS__)
+
+#define mlx5_fpga_info(__adev, format, ...) \
+	dev_info(&(__adev)->mdev->pdev->dev, "FPGA: " format, ##__VA_ARGS__)
+
+int mlx5_fpga_device_init(struct mlx5_core_dev *mdev);
+void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev);
+int mlx5_fpga_device_start(struct mlx5_core_dev *mdev);
+void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data);
+
+#else
+
+static inline int mlx5_fpga_device_init(struct mlx5_core_dev *mdev)
+{
+	return 0;
+}
+
+static inline void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev)
+{
+}
+
+static inline int mlx5_fpga_device_start(struct mlx5_core_dev *mdev)
+{
+	return 0;
+}
+
+static inline void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event,
+				   void *data)
+{
+}
+
+#endif
+
+#endif /* __MLX5_FPGA_CORE_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index f933922d5cca..ad0202cef203 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -56,6 +56,7 @@
 #ifdef CONFIG_MLX5_CORE_EN
 #include "eswitch.h"
 #endif
+#include "fpga/core.h"
 
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver");
@@ -1113,10 +1114,16 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 		goto err_disable_msix;
 	}
 
+	err = mlx5_fpga_device_init(dev);
+	if (err) {
+		dev_err(&pdev->dev, "fpga device init failed %d\n", err);
+		goto err_put_uars;
+	}
+
 	err = mlx5_start_eqs(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Failed to start pages and async EQs\n");
-		goto err_put_uars;
+		goto err_fpga_init;
 	}
 
 	err = alloc_comp_eqs(dev);
@@ -1147,6 +1154,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 		goto err_sriov;
 	}
 
+	err = mlx5_fpga_device_start(dev);
+	if (err) {
+		dev_err(&pdev->dev, "fpga device start failed %d\n", err);
+		goto err_reg_dev;
+	}
+
 	if (mlx5_device_registered(dev)) {
 		mlx5_attach_device(dev);
 	} else {
@@ -1182,6 +1195,9 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 err_stop_eqs:
 	mlx5_stop_eqs(dev);
 
+err_fpga_init:
+	mlx5_fpga_device_cleanup(dev);
+
 err_put_uars:
 	mlx5_put_uars_page(dev, priv->uar);
 
@@ -1246,6 +1262,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 	mlx5_irq_clear_affinity_hints(dev);
 	free_comp_eqs(dev);
 	mlx5_stop_eqs(dev);
+	mlx5_fpga_device_cleanup(dev);
 	mlx5_put_uars_page(dev, priv->uar);
 	mlx5_disable_msix(dev);
 	if (cleanup)
diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index dd9a263ed368..786a43843da9 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -300,6 +300,8 @@ enum mlx5_event {
 
 	MLX5_EVENT_TYPE_PAGE_FAULT	   = 0xc,
 	MLX5_EVENT_TYPE_NIC_VPORT_CHANGE   = 0xd,
+
+	MLX5_EVENT_TYPE_FPGA_ERROR         = 0x20,
 };
 
 enum {
@@ -967,6 +969,7 @@ enum mlx5_cap_type {
 	MLX5_CAP_RESERVED,
 	MLX5_CAP_VECTOR_CALC,
 	MLX5_CAP_QOS,
+	MLX5_CAP_FPGA,
 	/* NUM OF CAP Types */
 	MLX5_CAP_NUM
 };
@@ -1088,6 +1091,9 @@ enum mlx5_mcam_feature_groups {
 #define MLX5_CAP_MCAM_FEATURE(mdev, fld) \
 	MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_feature_cap_mask.enhanced_features.fld)
 
+#define MLX5_CAP_FPGA(mdev, cap) \
+	MLX5_GET(fpga_cap, (mdev)->caps.hca_cur[MLX5_CAP_FPGA], cap)
+
 enum {
 	MLX5_CMD_STAT_OK			= 0x0,
 	MLX5_CMD_STAT_INT_ERR			= 0x1,
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index a277bb36c21f..55bb712643cb 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -108,6 +108,8 @@ enum {
 	MLX5_REG_QTCT		 = 0x400a,
 	MLX5_REG_DCBX_PARAM      = 0x4020,
 	MLX5_REG_DCBX_APP        = 0x4021,
+	MLX5_REG_FPGA_CAP	 = 0x4022,
+	MLX5_REG_FPGA_CTRL	 = 0x4023,
 	MLX5_REG_PCAP		 = 0x5001,
 	MLX5_REG_PMTU		 = 0x5003,
 	MLX5_REG_PTYS		 = 0x5004,
@@ -761,6 +763,9 @@ struct mlx5_core_dev {
 	atomic_t		num_qps;
 	u32			issi;
 	struct mlx5e_resources  mlx5e_res;
+#ifdef CONFIG_MLX5_FPGA
+	struct mlx5_fpga_device *fpga;
+#endif
 #ifdef CONFIG_RFS_ACCEL
 	struct cpu_rmap         *rmap;
 #endif
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index 32de0724b400..6fa1eb6766af 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -32,6 +32,8 @@
 #ifndef MLX5_IFC_H
 #define MLX5_IFC_H
 
+#include "mlx5_ifc_fpga.h"
+
 enum {
 	MLX5_EVENT_TYPE_CODING_COMPLETION_EVENTS                   = 0x0,
 	MLX5_EVENT_TYPE_CODING_PATH_MIGRATED_SUCCEEDED             = 0x1,
@@ -56,7 +58,8 @@ enum {
 	MLX5_EVENT_TYPE_CODING_STALL_VL_EVENT                      = 0x1b,
 	MLX5_EVENT_TYPE_CODING_DROPPED_PACKET_LOGGED_EVENT         = 0x1f,
 	MLX5_EVENT_TYPE_CODING_COMMAND_INTERFACE_COMPLETION        = 0xa,
-	MLX5_EVENT_TYPE_CODING_PAGE_REQUEST                        = 0xb
+	MLX5_EVENT_TYPE_CODING_PAGE_REQUEST                        = 0xb,
+	MLX5_EVENT_TYPE_CODING_FPGA_ERROR                          = 0x20,
 };
 
 enum {
@@ -854,7 +857,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
 	u8         max_tc[0x4];
 	u8         reserved_at_1d0[0x1];
 	u8         dcbx[0x1];
-	u8         reserved_at_1d2[0x4];
+	u8         reserved_at_1d2[0x3];
+	u8         fpga[0x1];
 	u8         rol_s[0x1];
 	u8         rol_g[0x1];
 	u8         reserved_at_1d8[0x1];
@@ -2186,6 +2190,7 @@ union mlx5_ifc_hca_cap_union_bits {
 	struct mlx5_ifc_e_switch_cap_bits e_switch_cap;
 	struct mlx5_ifc_vector_calc_cap_bits vector_calc_cap;
 	struct mlx5_ifc_qos_cap_bits qos_cap;
+	struct mlx5_ifc_fpga_cap_bits fpga_cap;
 	u8         reserved_at_0[0x8000];
 };
 
@@ -8182,6 +8187,8 @@ union mlx5_ifc_ports_control_registers_document_bits {
 	struct mlx5_ifc_sltp_reg_bits sltp_reg;
 	struct mlx5_ifc_mtpps_reg_bits mtpps_reg;
 	struct mlx5_ifc_mtppse_reg_bits mtppse_reg;
+	struct mlx5_ifc_fpga_ctrl_bits fpga_ctrl_bits;
+	struct mlx5_ifc_fpga_cap_bits fpga_cap_bits;
 	u8         reserved_at_0[0x60e0];
 };
 
diff --git a/include/linux/mlx5/mlx5_ifc_fpga.h b/include/linux/mlx5/mlx5_ifc_fpga.h
new file mode 100644
index 000000000000..0032d10ac6cf
--- /dev/null
+++ b/include/linux/mlx5/mlx5_ifc_fpga.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MLX5_IFC_FPGA_H
+#define MLX5_IFC_FPGA_H
+
+struct mlx5_ifc_fpga_shell_caps_bits {
+	u8         max_num_qps[0x10];
+	u8         reserved_at_10[0x8];
+	u8         total_rcv_credits[0x8];
+
+	u8         reserved_at_20[0xe];
+	u8         qp_type[0x2];
+	u8         reserved_at_30[0x5];
+	u8         rae[0x1];
+	u8         rwe[0x1];
+	u8         rre[0x1];
+	u8         reserved_at_38[0x4];
+	u8         dc[0x1];
+	u8         ud[0x1];
+	u8         uc[0x1];
+	u8         rc[0x1];
+
+	u8         reserved_at_40[0x1a];
+	u8         log_ddr_size[0x6];
+
+	u8         max_fpga_qp_msg_size[0x20];
+
+	u8         reserved_at_80[0x180];
+};
+
+struct mlx5_ifc_fpga_cap_bits {
+	u8         fpga_id[0x8];
+	u8         fpga_device[0x18];
+
+	u8         register_file_ver[0x20];
+
+	u8         fpga_ctrl_modify[0x1];
+	u8         reserved_at_41[0x5];
+	u8         access_reg_query_mode[0x2];
+	u8         reserved_at_48[0x6];
+	u8         access_reg_modify_mode[0x2];
+	u8         reserved_at_50[0x10];
+
+	u8         reserved_at_60[0x20];
+
+	u8         image_version[0x20];
+
+	u8         image_date[0x20];
+
+	u8         image_time[0x20];
+
+	u8         shell_version[0x20];
+
+	u8         reserved_at_100[0x80];
+
+	struct mlx5_ifc_fpga_shell_caps_bits shell_caps;
+
+	u8         reserved_at_380[0x8];
+	u8         ieee_vendor_id[0x18];
+
+	u8         sandbox_product_version[0x10];
+	u8         sandbox_product_id[0x10];
+
+	u8         sandbox_basic_caps[0x20];
+
+	u8         reserved_at_3e0[0x10];
+	u8         sandbox_extended_caps_len[0x10];
+
+	u8         sandbox_extended_caps_addr[0x40];
+
+	u8         fpga_ddr_start_addr[0x40];
+
+	u8         fpga_cr_space_start_addr[0x40];
+
+	u8         fpga_ddr_size[0x20];
+
+	u8         fpga_cr_space_size[0x20];
+
+	u8         reserved_at_500[0x300];
+};
+
+struct mlx5_ifc_fpga_ctrl_bits {
+	u8         reserved_at_0[0x8];
+	u8         operation[0x8];
+	u8         reserved_at_10[0x8];
+	u8         status[0x8];
+
+	u8         reserved_at_20[0x8];
+	u8         flash_select_admin[0x8];
+	u8         reserved_at_30[0x8];
+	u8         flash_select_oper[0x8];
+
+	u8         reserved_at_40[0x40];
+};
+
+enum {
+	MLX5_FPGA_ERROR_EVENT_SYNDROME_CORRUPTED_DDR        = 0x1,
+	MLX5_FPGA_ERROR_EVENT_SYNDROME_FLASH_TIMEOUT        = 0x2,
+	MLX5_FPGA_ERROR_EVENT_SYNDROME_INTERNAL_LINK_ERROR  = 0x3,
+	MLX5_FPGA_ERROR_EVENT_SYNDROME_WATCHDOG_FAILURE     = 0x4,
+	MLX5_FPGA_ERROR_EVENT_SYNDROME_I2C_FAILURE          = 0x5,
+	MLX5_FPGA_ERROR_EVENT_SYNDROME_IMAGE_CHANGED        = 0x6,
+	MLX5_FPGA_ERROR_EVENT_SYNDROME_TEMPERATURE_CRITICAL = 0x7,
+};
+
+struct mlx5_ifc_fpga_error_event_bits {
+	u8         reserved_at_0[0x40];
+
+	u8         reserved_at_40[0x18];
+	u8         syndrome[0x8];
+
+	u8         reserved_at_60[0x80];
+};
+
+#endif /* MLX5_IFC_FPGA_H */
-- 
2.11.0

^ permalink raw reply related

* [for-next 3/6] net/mlx5: Introduce trigger_health_work function
From: Saeed Mahameed @ 2017-05-23 11:44 UTC (permalink / raw)
  To: David S. Miller, Doug Ledford
  Cc: netdev, linux-rdma, Ilan Tayari, Saeed Mahameed
In-Reply-To: <20170523114404.20387-1-saeedm@mellanox.com>

From: Ilan Tayari <ilant@mellanox.com>

Introduce new function for entering bad-health state.

This function will be called from FPGA-related logic in a later patch from
asynchronous event (IRQ) context, for that we change the spin lock to an
IRQ-safe one.

Signed-off-by: Ilan Tayari <ilant@mellanox.com>
Reviewed-by: Boris Pismenny <borisp@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/health.c | 32 ++++++++++++++++--------
 include/linux/mlx5/driver.h                      |  1 +
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
index d0515391d33b..c3cedb6cec3f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -185,6 +185,7 @@ static void health_care(struct work_struct *work)
 	struct mlx5_core_health *health;
 	struct mlx5_core_dev *dev;
 	struct mlx5_priv *priv;
+	unsigned long flags;
 
 	health = container_of(work, struct mlx5_core_health, work);
 	priv = container_of(health, struct mlx5_priv, health);
@@ -192,13 +193,13 @@ static void health_care(struct work_struct *work)
 	mlx5_core_warn(dev, "handling bad device here\n");
 	mlx5_handle_bad_state(dev);
 
-	spin_lock(&health->wq_lock);
+	spin_lock_irqsave(&health->wq_lock, flags);
 	if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
 		schedule_delayed_work(&health->recover_work, recover_delay);
 	else
 		dev_err(&dev->pdev->dev,
 			"new health works are not permitted at this stage\n");
-	spin_unlock(&health->wq_lock);
+	spin_unlock_irqrestore(&health->wq_lock, flags);
 }
 
 static const char *hsynd_str(u8 synd)
@@ -269,6 +270,20 @@ static unsigned long get_next_poll_jiffies(void)
 	return next;
 }
 
+void mlx5_trigger_health_work(struct mlx5_core_dev *dev)
+{
+	struct mlx5_core_health *health = &dev->priv.health;
+	unsigned long flags;
+
+	spin_lock_irqsave(&health->wq_lock, flags);
+	if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
+		queue_work(health->wq, &health->work);
+	else
+		dev_err(&dev->pdev->dev,
+			"new health works are not permitted at this stage\n");
+	spin_unlock_irqrestore(&health->wq_lock, flags);
+}
+
 static void poll_health(unsigned long data)
 {
 	struct mlx5_core_dev *dev = (struct mlx5_core_dev *)data;
@@ -297,13 +312,7 @@ static void poll_health(unsigned long data)
 	if (in_fatal(dev) && !health->sick) {
 		health->sick = true;
 		print_health_info(dev);
-		spin_lock(&health->wq_lock);
-		if (!test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags))
-			queue_work(health->wq, &health->work);
-		else
-			dev_err(&dev->pdev->dev,
-				"new health works are not permitted at this stage\n");
-		spin_unlock(&health->wq_lock);
+		mlx5_trigger_health_work(dev);
 	}
 }
 
@@ -333,10 +342,11 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev)
 void mlx5_drain_health_wq(struct mlx5_core_dev *dev)
 {
 	struct mlx5_core_health *health = &dev->priv.health;
+	unsigned long flags;
 
-	spin_lock(&health->wq_lock);
+	spin_lock_irqsave(&health->wq_lock, flags);
 	set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags);
-	spin_unlock(&health->wq_lock);
+	spin_unlock_irqrestore(&health->wq_lock, flags);
 	cancel_delayed_work_sync(&health->recover_work);
 	cancel_work_sync(&health->work);
 }
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index c2740688d679..a277bb36c21f 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -915,6 +915,7 @@ int mlx5_health_init(struct mlx5_core_dev *dev);
 void mlx5_start_health_poll(struct mlx5_core_dev *dev);
 void mlx5_stop_health_poll(struct mlx5_core_dev *dev);
 void mlx5_drain_health_wq(struct mlx5_core_dev *dev);
+void mlx5_trigger_health_work(struct mlx5_core_dev *dev);
 int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size,
 			struct mlx5_buf *buf, int node);
 int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf);
-- 
2.11.0

^ permalink raw reply related

* [for-next 2/6] net/mlx5: Update the list of the PCI supported devices
From: Saeed Mahameed @ 2017-05-23 11:44 UTC (permalink / raw)
  To: David S. Miller, Doug Ledford
  Cc: netdev, linux-rdma, Ilan Tayari, Noa Osherovich, Saeed Mahameed
In-Reply-To: <20170523114404.20387-1-saeedm@mellanox.com>

From: Noa Osherovich <noaos@mellanox.com>

Add the BlueField device and VF IDs to the supported devices list.

Signed-off-by: Noa Osherovich <noaos@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 0c123d571b4c..f933922d5cca 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -1520,6 +1520,8 @@ static const struct pci_device_id mlx5_core_pci_table[] = {
 	{ PCI_VDEVICE(MELLANOX, 0x101a), MLX5_PCI_DEV_IS_VF},	/* ConnectX-5 Ex VF */
 	{ PCI_VDEVICE(MELLANOX, 0x101b) },			/* ConnectX-6 */
 	{ PCI_VDEVICE(MELLANOX, 0x101c), MLX5_PCI_DEV_IS_VF},	/* ConnectX-6 VF */
+	{ PCI_VDEVICE(MELLANOX, 0xa2d2) },			/* BlueField integrated ConnectX-5 network controller */
+	{ PCI_VDEVICE(MELLANOX, 0xa2d3), MLX5_PCI_DEV_IS_VF},	/* BlueField integrated ConnectX-5 network controller VF */
 	{ 0, }
 };
 
-- 
2.11.0

^ permalink raw reply related

* Re: [patch net-next] net: sched: cls_api: make reclassify return all the way back to the original tp
From: Simon Horman @ 2017-05-23 11:50 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, davem, jhs, xiyou.wangcong, dsa, edumazet, daniel,
	alexander.h.duyck, mlxsw
In-Reply-To: <20170523071159.1951-1-jiri@resnulli.us>

On Tue, May 23, 2017 at 09:11:59AM +0200, Jiri Pirko wrote:
> From: Jiri Pirko <jiri@mellanox.com>
> 
> With the introduction of chain goto action, the reclassification would
> cause the re-iteration of the actual chain. It makes more sense to restart
> the whole thing and re-iterate starting from the original tp - start
> of chain 0.
> 
> Signed-off-by: Jiri Pirko <jiri@mellanox.com>

Reviewed-by: Simon Horman <simon.horman@netronome.com>

> ---
>  net/sched/cls_api.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
> index 01a8b8b..89fbb35 100644
> --- a/net/sched/cls_api.c
> +++ b/net/sched/cls_api.c
> @@ -300,7 +300,8 @@ int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
>  	__be16 protocol = tc_skb_protocol(skb);
>  #ifdef CONFIG_NET_CLS_ACT
>  	const int max_reclassify_loop = 4;
> -	const struct tcf_proto *old_tp = tp;
> +	const struct tcf_proto *orig_tp = tp;
> +	const struct tcf_proto *first_tp;
>  	int limit = 0;
>  
>  reclassify:
> @@ -315,9 +316,10 @@ int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
>  		err = tp->classify(skb, tp, res);
>  #ifdef CONFIG_NET_CLS_ACT
>  		if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode)) {
> +			first_tp = orig_tp;
>  			goto reset;
>  		} else if (unlikely(TC_ACT_EXT_CMP(err, TC_ACT_GOTO_CHAIN))) {
> -			old_tp = res->goto_tp;
> +			first_tp = res->goto_tp;
>  			goto reset;
>  		}
>  #endif
> @@ -335,7 +337,7 @@ int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
>  		return TC_ACT_SHOT;
>  	}
>  
> -	tp = old_tp;
> +	tp = first_tp;
>  	protocol = tc_skb_protocol(skb);
>  	goto reclassify;
>  #endif
> -- 
> 2.9.3
> 

^ permalink raw reply

* RE: [PATCH v2 net] smsc95xx: Support only IPv4 TCP/UDP csum offload
From: Nisar.Sayed @ 2017-05-23 12:06 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, steve.glendinning, popcornmix
In-Reply-To: <20170521.133219.666611127277983923.davem@davemloft.net>

> > When TX checksum offload is used, if the computed checksum is 0 the
> > LAN95xx device do not alter the checksum to 0xffff.  In the case of ipv4
> > UDP checksum, it indicates to receiver that no checksum is calculated.
> > Under ipv6, UDP checksum yields a result of zero must be changed to
> > 0xffff. Hence disabling checksum offload for ipv6 packets.
> >
> > Signed-off-by: Nisar Sayed <Nisar.Sayed@microchip.com>
> >
> > Reported-by: popcorn mix <popcornmix@gmail.com>
> 
> Appied, thanks.

Thanks.

^ permalink raw reply

* stmmac tx timeout
From: Niklas Cassel @ 2017-05-23 12:06 UTC (permalink / raw)
  To: Alexandre Torgue, Giuseppe Cavallaro, Joao Pinto, Pavel Machek,
	Lars Persson
  Cc: netdev

Hello


I'm debugging a transmit queue 0 timeout on stmmac with DWMAC4 (4.10a).
I'm using kernel v4.9.23, which is before multi queue support was added.
I've cherry-picked
98a29944774a ("net: ethernet: stmmac: remove private tx queue lock")
84c53b4baef8 ("stmmac: fix memory barriers")
but I still get tx timeouts with these patches.

I've managed to reproduce the problem several times,
mainly by transmitting the syslog over HTTP.

The stmmac driver does not reset the IP in its .ndo_tx_timeout function,
so when the timeout occurs, the device does not recover.

I've added some code in the .ndo_tx_timeout function, before the
driver tries to restart the transmission (which fails anyway),
that dumps all registers and the triggers a kernel crashdump.


Here is some of the registers:

GMAC4 DMA registers
       DMA_BUS_MODE, offset: 0x1000, val: 0x0
       DMA_SYS_BUS_MODE, offset: 0x1004, val: 0x10f1008
       DMA_STATUS, offset: 0x1008, val: 0x0
       DMA_DEBUG_STATUS_0, offset: 0x100c, val: 0x7701
       DMA_DEBUG_STATUS_1, offset: 0x1010, val: 0x0
       DMA_DEBUG_STATUS_2, offset: 0x1014, val: 0x0
Channel 0
       DMA_CHAN_CONTROL, offset: 0x0, val: 0x0
       DMA_CHAN_TX_CONTROL, offset: 0x4, val: 0x41001
       DMA_CHAN_RX_CONTROL, offset: 0x8, val: 0x100001
       DMA_CHAN_TX_BASE_ADDR, offset: 0x14, val: 0x9005e000
       DMA_CHAN_RX_BASE_ADDR, offset: 0x1c, val: 0x9005c000
       DMA_CHAN_TX_END_ADDR, offset: 0x20, val: 0x90060000
       DMA_CHAN_RX_END_ADDR, offset: 0x28, val: 0x9005e000
       DMA_CHAN_TX_RING_LEN, offset: 0x2c, val: 0x1ff
       DMA_CHAN_RX_RING_LEN, offset: 0x30, val: 0x1ff
       DMA_CHAN_INTR_ENA, offset: 0x34, val: 0xd041
       DMA_CHAN_RX_WATCHDOG, offset: 0x38, val: 0xff
       DMA_CHAN_SLOT_CTRL_STATUS, offset: 0x3c, val: 0x0
       DMA_CHAN_CUR_TX_DESC, offset: 0x44, val: 0x9005e610
       DMA_CHAN_CUR_RX_DESC, offset: 0x4c, val: 0x9005de50
       DMA_CHAN_CUR_TX_BUF_ADDR, offset: 0x54, val: 0x8d723fff
       DMA_CHAN_CUR_RX_BUF_ADDR, offset: 0x5c, val: 0x8eb02942
       DMA_CHAN_STATUS, offset: 0x60, val: 0x0


DMA_DEBUG_STATUS_0 gives us:
DMA Channel 0 Transmit Process State:
3'b111: Running (Closing Tx Descriptor)

DMA Channel 0 Receive Process State:
3'b111: Running (Transferring the received packet
data from the Rx buffer to the system memory)

In some of the hangs, DMA_DEBUG_STATUS_0 has been 0x3300


In all of the hangs the current application transmit
buffer address register (DMA_CHAN_CUR_TX_BUF_ADDR)
has been on an unaligned address.

Examples from three different crash dumps:
       DMA_CHAN_CUR_TX_BUF_ADDR, offset: 0x54, val: 0x8d723fff
       DMA_CHAN_CUR_TX_BUF_ADDR, offset: 0x54, val: 0x8732bfff
       DMA_CHAN_CUR_TX_BUF_ADDR, offset: 0x54, val: 0x8ffc3fff


By inspecting struct stmmac_priv in the
crashdump, we can see that
cur_tx = 78 => 78*16+0x9005e000=0x9005e4e0
which is the address of the descriptor that
will be used next by stmmac_xmit().
When the IP starts processing descriptors,
it will eventually read this descriptor.

dirty_tx = 97 => 97*16+0x9005e000=0x9005e610
which is the address where stmmac_tx_clean()
will start checking for completed descriptors,
the next time the function gets called.

That means that descriptors from
0x9005e4e0 to 0x9005e610 have recently been
cleaned by stmmac_tx_clean().

Excerpt from DMA desc ring:
each descriptor is 16 bytes, so each row is
a new descriptor.

           TDES0    TDES1    TDES2    TDES3
9005e460:  b541e210 875a1910 0000008a b000008a
9005e470:  b738c410 875a6110 0000008a b000008a
9005e480:  bc255202 871e7110 0000002a b000002a
9005e490:  bc255302 871e1910 0000002a b000002a
9005e4a0:  bc255002 875a6110 0000002a b000002a
9005e4b0:  b738d010 871e4110 0000008a b000008a
9005e4c0:  b541e610 875a2110 0000008a b000008a
9005e4d0:  b738c210 871e3910 0000008a b000008a
9005e4e0:  8b74ee66 85f5d110 00000000 00000000
9005e4f0:  bc0f3cce 871e1910 00000000 00000000
9005e500:  8b74f7ef 875a3910 00000000 00000000
9005e510:  81940000 875a5110 00000000 00000000
9005e520:  81943fff 871e1910 00000000 00000000
9005e530:  bc0f32ce 871e4910 00000000 00000000
9005e540:  81944177 875a3110 00000000 00000000
9005e550:  bc0f38ce 871e4110 00000000 00000000
9005e560:  8194471f 871e4910 00000000 00000000
9005e570:  84508000 875a4910 00000000 00000000
9005e580:  bc0f3ece 871e2910 00000000 00000000
9005e590:  8450964f 875a6110 00000000 00000000
9005e5a0:  8450d64e 871e6910 00000000 00000000
9005e5b0:  bc0f32ce 875a7110 00000000 00000000
9005e5c0:  8450e57f 875a0910 00000000 00000000
9005e5d0:  bc0f3cce 875a4910 00000000 00000000
9005e5e0:  8450eb27 875a4110 00000000 00000000
9005e5f0:  8d720000 871e0110 00000000 00000000
9005e600:  bc0f38ce 875a0910 00000000 00000000
9005e610:  8d723fff 875a2110 000005a8 900305ea
9005e620:  bc0f22ce 875a6110 00000042 a0444f30
9005e630:  8d7245a7 85f5c110 00003a59 80000000
9005e640:  8c6a8000 871e7910 000014d7 90000000
9005e650:  bc0f32ce 875a7910 00000042 a00305ea
9005e660:  8c6a94d7 85f59110 000005a8 900305ea
9005e670:  bc0f3cce 875a6110 00000042 a00305ea
9005e680:  8450eb27 85f5f910 000005a8 900305ea
9005e690:  bc1e0610 871e5110 0000009f b000009f
9005e6a0:  bb112802 875a3910 000001d9 b00301d9
9005e6b0:  bb112002 875a4910 000001df b00301df
9005e6c0:  bb113402 875a7110 00000201 b0030201
9005e6d0:  bb110402 85f58110 00000201 b0030201

Looking at the DMA_CHAN_CUR_TX_DESC (0x9005e610)
TDES0 and TDES1 can contain tx buffers.

TDES2 tells us that the length of TDES1 is zero,
so let's ignore the address in TDES1.
(It would be clearer if we actually did set TDES1
to zero when TDES1's size is set to zero.)

TDES2 tells us that length of TDES0 is 1448.

TDES3 tells us that we have the DMA own bit set.
Last descriptor is set, but not first descriptor,
and that the total packet length is 1514.

TDES0 matches DMA_CHAN_CUR_TX_BUF_ADDR.
The buffer is on an unaligned address.
Reading the buffer in TDES0 shows text
that appears to be from the syslog,
so it appears to be a valid buffer.

Looking at the previous descriptor (9005e600),
and reading contents from its TDES0,
it's an ethernet hdr + ip hdr + tcp hdr,
total size 14 + 20 + 32 = 66,
1448+66=1514, so this matches the size
we previously saw is TDES3.

Note that TDES* has different formats depending
on if it's before the IP has handled the packet
or not. I was thinking that TDES0 and TDES1
might be timestamps, but I have not enabled
PTP, and the Transmit Timestamp Enable bit
is not set in any descriptor.


By debugging, I could see that we can get
unaligned buffers when we have fragments
(skb_shinfo(skb)->nr_frags > 0), so having
unaligned tx buffers in itself in not that
unusual.


In struct stmmac_priv we also have
stmmac_priv->tx_skbuff_dma
which contains all txbuf addresses, i.e.
dma_map_single(.., skb->data, ..) or
skb_frag_dma_map(.., frag, ..)
which we will put in the descriptors'
TDES0 (or TDES1).

tx_skbuff_dma contains elements of stmmac_tx_info,
which each are 16 bytes, so each row corresponds
to a descriptor.

struct stmmac_tx_info {
        dma_addr_t buf;
	bool map_as_page;
        unsigned len;
        bool last_segment;
	bool is_jumbo;
};

Here we see our txbuff, 8d723fff (as we know,
we are last descriptor, and the desc before
us is first descriptor)

be282600:  00000000 040a4100 00000000 4d2d0000
be282610:  8d723fff 9c316501 000005a8 54520001



Then in struct stmmac_priv we also have
stmmac_priv->tx_skbuff
which contains a list of pointers to skbs.
Each 32 bits corresponds to a descriptor.
For descs that are fragments, stmmac sets
the value to NULL, so only the descs which
has first descriptor set will have a skb
pointer.

bd42e940:  00000000 00000000 00000000 00000000
bd42e950:  00000000 00000000 00000000 00000000
bd42e960:  00000000 00000000 00000000 00000000
bd42e970:  00000000 00000000 00000000 00000000
bd42e980:  00000000 00000000 bb2c8530 00000000
bd42e990:  00000000 bb2c8fb0 00000000 bb2c80b0
bd42e9a0:  00000000 b7ecfa80 be241600 be241000
bd42e9b0:  be241cc0 be241540 be241240 be2413c0
bd42e9c0:  be241b40 be241480 b53e8c00 bb005b40

We can see that the cell which has bb2c8530 is
first desc, followed by a desc which is neither
first or last, followed by a desc that is last.
Then we have bb2c8fb0 which is first, followed by
a last.

Calculating the address where our desc should be:
The index that corresponds to a certain desc is
always the same, and from the dma ring we know
that desc 9005e610 has index 97, so
(stmmac_priv->tx_skbuff)+4*97=
0xbd42e800+4*97=0xbd42e984

Looking at address 0xbd42e984 in the output above,
we can see that is it zero, which is correct,
since we are not first desc, however the one
before us should be a first desc, but is zero.

This means that stmmac_tx_clean() has
done dev_consume_skb_any() (which calls kfree_skb)
and has set it to NULL, before the IP has sent
out our fragment which is part of the same skb.
I'm not sure that this is related to the hangs
that I'm debugging, but is this really allowed?


I've also tried adding attribute ____cacheline_aligned
to struct dma_desc in stmmac/descs.h, together
with setting a matching Descriptor Skip Length
in the IP, but I still get tx timeouts.


I've also noted that
84c53b4baef8 ("stmmac: fix memory barriers")
replaced some wmb()'s with dma_wmb()'s.
On arm, wmb() calls arm_heavy_mb(), which also
flushes L2. A dma_wmb() doesn't flush L2.
I'm not sure if this is of any importance,
since I've seen tx timeouts even before
cherry-picking this commit to v4.9.23.


Regards,
Niklas

^ permalink raw reply

* Re: [PATCH] net: set default value for somaxconn
From: Roman Kapl @ 2017-05-23 12:26 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20170522.141809.2056075174395561778.davem@davemloft.net>

On 05/22/2017 08:18 PM, David Miller wrote:
> From: Roman Kapl <roman.kapl@sysgo.com>
> Date: Mon, 22 May 2017 14:22:41 +0200
>
>> The default value for somaxconn is set in sysctl_core_net_init(), but this
>> function is not called when kernel is configured without CONFIG_SYSCTL.
>>
>> This results in the kernel not being able to accept TCP connections,
>> because the backlog has zero size. Usually, the user ends up with:
>> "TCP: request_sock_TCP: Possible SYN flooding on port 7. Dropping request.  Check SNMP counters."
>>
>> Before ef547f2ac16 (tcp: remove max_qlen_log), the effects were less
>> severe, because the backlog was always at least eight slots long.
>>
>> Signed-off-by: Roman Kapl <roman.kapl@sysgo.com>
> I see the problem, but this changes behavior.
>
> Existing code will set somaxconn to the default value for every namespace
> that is created.
>
> But with you changes, any modification made to init_net's value will
> get inherited by any namespace created as a child thereafterwards.
Hmm, I can not find where somaxconn is inherited. But I see this needs 
to be per-net.
>
> You really need to make this happen via pernet_operations, or even
> inside of setup_net().
I will create new pernet_operations in net_namespace.c, move the 
somaxconn initialization there and send a new patch.

Thanks for comments, Roman Kapl

^ permalink raw reply

* pull-request: mac80211 2017-05-23
From: Johannes Berg @ 2017-05-23 12:42 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-wireless

Hi Dave,

I have just two fixes here, one of the scheduled scan issue that
Sander Eikelenboom found, and the other properly makes mesh more
strictly check its extension headers.

Please pull and let me know if there's any problem.

Thanks,
johannes



The following changes since commit 29cee56c0be46ad01e78af104a06223c65ee0c67:

  Merge tag 'mac80211-for-davem-2017-05-08' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211 (2017-05-08 16:02:23 -0400)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git tags/mac80211-for-davem-2017-05-23

for you to fetch changes up to 1b57b6210f4e52904393be97c62122aae69bc8aa:

  cfg80211: make cfg80211_sched_scan_results() work from atomic context (2017-05-23 14:36:46 +0200)

----------------------------------------------------------------
Just two fixes this time:
 * fix the scheduled scan "BUG: scheduling while atomic"
 * check mesh address extension flags more strictly

----------------------------------------------------------------
Arend Van Spriel (1):
      cfg80211: make cfg80211_sched_scan_results() work from atomic context

Rajkumar Manoharan (1):
      mac80211: strictly check mesh address extension mode

 net/mac80211/rx.c   |  3 ++-
 net/wireless/scan.c |  8 ++++----
 net/wireless/util.c | 10 ++++++----
 3 files changed, 12 insertions(+), 9 deletions(-)

^ permalink raw reply

* [PATCH net] net/mlx4: Fix the check in attaching steering rules
From: Tariq Toukan @ 2017-05-23 12:50 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Eran Ben Elisha, Or Gerlitz, Talat Batheesh, Tariq Toukan

From: Talat Batheesh <talatb@mellanox.com>

Our previous patch (cited below) introduced a regression
for RAW Eth QPs.

Fix it by checking if the QP number provided by user-space
exists, hence allowing steering rules to be added for valid
QPs only.

Fixes: 89c557687a32 ("net/mlx4_en: Avoid adding steering rules with ...")
Reported-by: Or Gerlitz <gerlitz.or@gmail.com>
Signed-off-by: Talat Batheesh <talatb@mellanox.com>
Signed-off-by: Tariq Toukan <tariqt@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx4/en_ethtool.c |  3 +--
 drivers/net/ethernet/mellanox/mlx4/qp.c         | 14 ++++++++++++++
 include/linux/mlx4/qp.h                         |  1 +
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index ae5fdc2df654..00a7cd3dcc2e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -1562,8 +1562,7 @@ static int mlx4_en_flow_replace(struct net_device *dev,
 		qpn = priv->drop_qp.qpn;
 	else if (cmd->fs.ring_cookie & EN_ETHTOOL_QP_ATTACH) {
 		qpn = cmd->fs.ring_cookie & (EN_ETHTOOL_QP_ATTACH - 1);
-		if (qpn < priv->rss_map.base_qpn ||
-		    qpn >= priv->rss_map.base_qpn + priv->rx_ring_num) {
+		if (!mlx4_qp_lookup(priv->mdev->dev, qpn)) {
 			en_warn(priv, "rxnfc: QP (0x%x) doesn't exist\n", qpn);
 			return -EINVAL;
 		}
diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index 2d6abd4662b1..1eff2fe32a8b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -384,6 +384,20 @@ static void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn)
 		__mlx4_qp_free_icm(dev, qpn);
 }
 
+struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn)
+{
+	struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
+	struct mlx4_qp *qp;
+
+	spin_lock(&qp_table->lock);
+
+	qp = __mlx4_qp_lookup(dev, qpn);
+
+	spin_unlock(&qp_table->lock);
+	return qp;
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_lookup);
+
 int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp, gfp_t gfp)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h
index b4ee8f62ce8d..8e2828d48d7f 100644
--- a/include/linux/mlx4/qp.h
+++ b/include/linux/mlx4/qp.h
@@ -470,6 +470,7 @@ struct mlx4_update_qp_params {
 	u16	rate_val;
 };
 
+struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn);
 int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn,
 		   enum mlx4_update_qp_attr attr,
 		   struct mlx4_update_qp_params *params);
-- 
1.8.3.1

^ permalink raw reply related

* Re: [PATCH v2] net: fec: add post PHY reset delay DT property
From: Andrew Lunn @ 2017-05-23 12:52 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: fugang.duan, robh+dt, mark.rutland, netdev, devicetree,
	linux-kernel, thomas.petazzoni
In-Reply-To: <20170523094808.11102-1-quentin.schulz@free-electrons.com>

On Tue, May 23, 2017 at 11:48:08AM +0200, Quentin Schulz wrote:
> Some PHY require to wait for a bit after the reset GPIO has been
> toggled. This adds support for the DT property `phy-reset-post-delay`
> which gives the delay in milliseconds to wait after reset.
> 
> If the DT property is not given, no delay is observed. Post reset delay
> greater than 1000ms are invalid.
> 
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* Re: [PATCH net 1/3] vlan: Fix tcp checksums offloads for Q-in-Q vlan.
From: Vlad Yasevich @ 2017-05-23 12:59 UTC (permalink / raw)
  To: David Miller, vyasevich; +Cc: netdev, makita.toshiaki
In-Reply-To: <20170522.195921.1033609103219347751.davem@davemloft.net>

On 05/22/2017 07:59 PM, David Miller wrote:
> From: Vladislav Yasevich <vyasevich@gmail.com>
> Date: Thu, 18 May 2017 09:31:03 -0400
> 
>> It appears that since commit 8cb65d000, Q-in-Q vlans have been
>> broken.  The series that commit is part of enabled TSO and checksum
>> offloading on Q-in-Q vlans.  However, most HW we support can't handle
>> it.  To work around the issue, the above commit added a function that
>> turns off offloads on Q-in-Q devices, but it left the checksum offload.
>> That will cause issues with most older devices that supprort very basic
>> checksum offload capabilities as well as some newer devices (we've
>> reproduced te problem with both be2net and bnx).
>>
>> To solve this for everyone, turn off checksum offloading feature
>> by default when sending Q-in-Q traffic.  Devices that are proven to
>> work can provided a corrected ndo_features_check implemetation.
>>
>> Fixes: 8cb65d000 ("net: Move check for multiple vlans to drivers")
>> CC: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
>> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
> 
> This is a tough one.  I can certainly sympathize with your frustration
> trying to track this down.
> 
> Clearing NETIF_F_HW_CSUM completely is the most conservative change.
> 
> However, for all the (perhaps many) cards upon which the checksumming
> does work properly in Q-in-Q situations, this change could be
> introducing non-trivial performance regressions.
> 
> So I think Toshiaki's suggestion to drop IP_CSUM and IPV6_CSUM is,
> on balance, the best way forward.
> 

Thanks.  I'll update and re-submit.

-vlad

> Thanks.
> 

^ permalink raw reply

* Re: [PATCH v4 next 0/3] modules: automatic module loading restrictions
From: Djalal Harouni @ 2017-05-23 13:02 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Kees Cook, Solar Designer, linux-kernel, Network Development,
	LSM List, kernel-hardening@lists.openwall.com, Andrew Morton,
	Rusty Russell, Serge E. Hallyn, Jessica Yu, David S. Miller,
	James Morris, Paul Moore, Stephen Smalley, Greg Kroah-Hartman,
	Tetsuo Handa, Ingo Molnar, Linux API, Dongsu Park,
	Casey Schaufler, Jonathan Corbet
In-Reply-To: <CALCETrXyf3vM+NdFNcjwaOZs1KFJomuTL0DobXoH9Z68k8dknQ@mail.gmail.com>

On Tue, May 23, 2017 at 1:38 AM, Andy Lutomirski <luto@kernel.org> wrote:
> On Mon, May 22, 2017 at 4:07 PM, Kees Cook <keescook@chromium.org> wrote:
>> On Mon, May 22, 2017 at 12:55 PM, Djalal Harouni <tixxdz@gmail.com> wrote:
>>> On Mon, May 22, 2017 at 6:43 PM, Solar Designer <solar@openwall.com> wrote:
>>>> On Mon, May 22, 2017 at 03:49:15PM +0200, Djalal Harouni wrote:
>>>>> On Mon, May 22, 2017 at 2:08 PM, Solar Designer <solar@openwall.com> wrote:
>>>>> > On Mon, May 22, 2017 at 01:57:03PM +0200, Djalal Harouni wrote:
>>>>> >> *) When modules_autoload_mode is set to (2), automatic module loading is
>>>>> >> disabled for all. Once set, this value can not be changed.
>>>>> >
>>>>> > What purpose does this securelevel-like property ("Once set, this value
>>>>> > can not be changed.") serve here?  I think this mode 2 is needed, but
>>>>> > without this extra property, which is bypassable by e.g. explicitly
>>>>> > loaded kernel modules anyway (and that's OK).
>>>>>
>>>>> My reasoning about "Once set, this value can not be changed" is mainly for:
>>>>>
>>>>> If you have some systems where modules are not updated for any given
>>>>> reason, then the only one who will be able to load a module is an
>>>>> administrator, basically this is a shortcut for:
>>>>>
>>>>> * Apps/services can run with CAP_NET_ADMIN but they are not allowed to
>>>>> auto-load 'netdev' modules.
>>>>>
>>>>> * Explicitly loading modules can be guarded by seccomp filters *per*
>>>>> app, so even if these apps have
>>>>>   CAP_SYS_MODULE they won't be able to explicitly load modules, one
>>>>> has to remount some sysctl /proc/ entries read-only here and remove
>>>>> CAP_SYS_ADMIN for all apps anyway.
>>>>>
>>>>> This mainly serves the purpose of these systems that do not receive
>>>>> updates, if I don't want to expose those kernel interfaces what should
>>>>> I do ? then if I want to unload old versions and replace them with new
>>>>> ones what operation should be allowed ? and only real root of the
>>>>> system can do it. Hence, the "Once set, this value can not be changed"
>>>>> is more of a shortcut, also the idea was put in my mind based on how
>>>>> "modules_disabled" is disabled forever, and some other interfaces. I
>>>>> would say: it is easy to handle a transition from 1) "hey this system
>>>>> is still up to date, some features should be exposed" to 2) "this
>>>>> system is not up to date anymore, only root should expose some
>>>>> features..."
>>>>>
>>>>> Hmm, I am not sure if this answers your question ? :-)
>>>>
>>>> This answers my question, but in a way that I summarize as "there's no
>>>> good reason to include this securelevel-like property".
>>>>
>>>
>>> Hmm, sorry I did forget to add in my previous comment that with such
>>> systems, CAP_SYS_MODULE can be used to reset the
>>> "modules_autoload_mode" sysctl back from mode 2 to mode 1, even if we
>>> disable it privileged tasks can be triggered to overwrite the sysctl
>>> flag and get it back unless /proc is read-only... that's one of the
>>> points, it should not be so easy to relax it.
>>
>> I'm on the fence. For modules_disabled and Yama, it was tied to
>> CAP_SYS_ADMIN, basically designed to be a at-boot setting that could
>> not later be undone by an attacker gaining that privilege, keeping
>> them out of either kernel memory or existing user process memory.
>> Here, it's CAP_SYS_MODULE... it's hard to imagine the situation where
>> a CAP_SYS_MODULE-capable process could write to this sysctl but NOT
>> issue direct modprobe requests, but it's _possible_ via crazy symlink
>> games to trick capable processes into writing to sysctls. We've seen
>> this multiple times before, and it's a way for attackers to turn a
>> single privileged write into a privileged exec.
>>
>> I might turn the question around, though: why would we want to have it
>> changeable at this setting?
>>
>> I'm fine leaving that piece off, either way.
>
> I think that having the un-resettable mode is unnecessary.  We should
> have option that disables loading modules entirely and cannot be
> unset.  (That means no explicit loads and not implicit loads.)  Maybe
> we already have this.  Otherwise, tightening caps needed for implicit
> loads should just be a normal yes/no setting IMO.

Ok, so as requested by you and Alexander in the other email, I will
remove the un-resettable property, if there is no general agreement,
better leave it for future.

I would have preferred if it is "yes/no" (in systemd the module
protection and other directives are also only 'yes/no').  But 1)
backward compatibility for unprivileged loading, 2) capabilities:
CAP_SYS_MODULE, CAP_NET_ADMIN use cases and exploits against
CAP_NET_ADMIN modules, and finally 3) separate and disable implicit
operation from the explicit one for various reasons that are noted in
the commit log like explicitly load the good module version, concluded
that we need three modes!

Thanks!

-- 
tixxdz

^ permalink raw reply

* Re: [net PATCH] mlx5: fix bug reading rss_hash_type from CQE
From: Jesper Dangaard Brouer @ 2017-05-23 13:04 UTC (permalink / raw)
  To: Saeed Mahameed
  Cc: Saeed Mahameed, Daniel Borkmann, Linux Netdev List, Tariq Toukan,
	Alexei Starovoitov, brouer, Arnaldo Carvalho de Melo
In-Reply-To: <CALzJLG9sAw3_-jL9R3=g6pZ517NMVRrFFya0E+NE5jUMH_uu8w@mail.gmail.com>

On Tue, 23 May 2017 13:58:44 +0300
Saeed Mahameed <saeedm@dev.mellanox.co.il> wrote:

> On Mon, May 22, 2017 at 9:13 PM, Jesper Dangaard Brouer
> <brouer@redhat.com> wrote:
> > Masks for extracting part of the Completion Queue Entry (CQE)
> > field rss_hash_type was swapped, namely CQE_RSS_HTYPE_IP and
> > CQE_RSS_HTYPE_L4.
> >
> > The bug resulted in setting skb->l4_hash, even-though the
> > rss_hash_type indicated that hash was NOT computed over the
> > L4 (UDP or TCP) part of the packet.
> >
> > Added comments from the datasheet, to make it more clear what
> > these masks are selecting.
> >
> > Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
> > ---
> >  include/linux/mlx5/device.h |   10 ++++++++--
> >  1 file changed, 8 insertions(+), 2 deletions(-)
> >
> > diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
> > index dd9a263ed368..a940ec6a046c 100644
> > --- a/include/linux/mlx5/device.h
> > +++ b/include/linux/mlx5/device.h
> > @@ -787,8 +787,14 @@ enum {
> >  };
> >
> >  enum {
> > -       CQE_RSS_HTYPE_IP        = 0x3 << 6,
> > -       CQE_RSS_HTYPE_L4        = 0x3 << 2,
> > +       CQE_RSS_HTYPE_IP        = 0x3 << 2,
> > +       /* cqe->rss_hash_type[3:2] - IP destination selected for hash
> > +        * (00 = none,  01 = IPv4, 10 = IPv6, 11 = Reserved)
> > +        */
> > +       CQE_RSS_HTYPE_L4        = 0x3 << 6,
> > +       /* cqe->rss_hash_type[7:6] - L4 destination selected for hash
> > +        * (00 = none, 01 = TCP. 10 = UDP, 11 = IPSEC.SPI
> > +        */
> >  };
> >  
> 
> Acked-by: Saeed Mahameed <saeedm@mellanox.com>
> 
> Nice catch Jesper !!
> 
> Can I ask how did you find the hash was wrong ? 
> any counters/indicators we can look for in internal testing ?

Found this when developing the XDP rxhash RFC patches[1][2].  And I used my
xdp_rxhash[3] program to inspect the hash values, but I guess that
doesn't help for internal testing.

[1] http://patchwork.ozlabs.org/patch/764057/
[2] http://patchwork.ozlabs.org/patch/764060/
[3] https://github.com/netoptimizer/prototype-kernel/tree/master/kernel/samples/bpf

I also have a trafgen script that generate fake packets, but for your
purpose you can just use ping.  A standard ICMP ping packet should be
categorized as 
 CQE_RSS_HTYPE_IP == (IPv4=01) and
 CQE_RSS_HTYPE_L4 == (none=00).

I was going to recommend using a cls_bpf program to inspect the same,
but it looks like it doesn't expose the skb->l4_hash bit, which shows
the bug. 

I guess, Alexie would say use kprobes.  I tried, but everything gets
inlined in the driver.  I did find a reliable inspection point, which
is napi_gro_receive().

Basically follow my blogpost:
 http://netoptimizer.blogspot.dk/2016/12/reading-live-runtime-kernel-variables.html

This is how you can verify my patch works with perf probe:

 perf probe -a 'napi_gro_receive hash=skb->hash htype=skb->ooo_okay:u8 skb->dev->name:string'

 perf record -e probe:napi_gro_receive -aR
 # send traffic
 perf script # results
 perf probe -d napi_gro_receive

Notice (acme), that I had to do an ugly trick: "htype=skb->ooo_okay:u8"
because perf didn't correctly decode bit the field skb->l4_hash.  Thus,
I'm type casting "ooo_okay" to u8, and skb->l4_hash is set if htype=2,
as skb->l4_hash is the second bit in that byte.  Maybe ACME can fix that? ;-)

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer

This is how a ping flood looks like with xdp_rxhash

[jbrouer@skylake prototype-kernel]$ sudo ./xdp_rxhash --dev mlx5p2 --sec 2 

xdp-action     pps        pps-human-readable mem      
XDP_ABORTED    0          0                  2.000273  read
XDP_DROP       0          0                  2.000272  read
XDP_PASS       95626      95,626             2.000272  read
XDP_TX         0          0                  2.000272  read
rx_total       95626      95,626             2.000272  read

hash_type:L3   pps        pps-human-readable sample-period
Unknown        0          0                  2.000270
IPv4           95626      95,626             2.000272
IPv6           0          0                  2.000272

hash_type:L4   pps        pps-human-readable sample-period
Unknown        95627      95,627             2.000272
TCP            0          0                  2.000272
UDP            0          0                  2.000270

^CInterrupted: Removing XDP program on ifindex:5 device:mlx5p2

^ permalink raw reply

* [PATCH] tipc: Delete error messages for failed memory allocations in three functions
From: SF Markus Elfring @ 2017-05-23 13:07 UTC (permalink / raw)
  To: tipc-discussion, netdev, David S. Miller, Jon Maloy, Ying Xue
  Cc: LKML, kernel-janitors

From: Markus Elfring <elfring@users.sourceforge.net>
Date: Tue, 23 May 2017 14:45:25 +0200

Omit four extra messages for memory allocation failures in these functions.

This issue was detected by using the Coccinelle software.

Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
 net/tipc/name_table.c | 15 ++++-----------
 net/tipc/node.c       |  5 ++---
 2 files changed, 6 insertions(+), 14 deletions(-)

diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index bd0aac87b41a..7e731af8a1a7 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -117,10 +117,8 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper,
 				       u32 key)
 {
 	struct publication *publ = kzalloc(sizeof(*publ), GFP_ATOMIC);
-	if (publ == NULL) {
-		pr_warn("Publication creation failure, no memory\n");
+	if (!publ)
 		return NULL;
-	}
 
 	publ->type = type;
 	publ->lower = lower;
@@ -270,11 +268,9 @@ static struct publication *tipc_nameseq_insert_publ(struct net *net,
 		if (nseq->first_free == nseq->alloc) {
 			struct sub_seq *sseqs = tipc_subseq_alloc(nseq->alloc * 2);
 
-			if (!sseqs) {
-				pr_warn("Cannot publish {%u,%u,%u}, no memory\n",
-					type, lower, upper);
+			if (!sseqs)
 				return NULL;
-			}
+
 			memcpy(sseqs, nseq->sseqs,
 			       nseq->alloc * sizeof(struct sub_seq));
 			kfree(nseq->sseqs);
@@ -283,11 +279,8 @@ static struct publication *tipc_nameseq_insert_publ(struct net *net,
 		}
 
 		info = kzalloc(sizeof(*info), GFP_ATOMIC);
-		if (!info) {
-			pr_warn("Cannot publish {%u,%u,%u}, no memory\n",
-				type, lower, upper);
+		if (!info)
 			return NULL;
-		}
 
 		INIT_LIST_HEAD(&info->node_list);
 		INIT_LIST_HEAD(&info->cluster_list);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index aeef8011ac7d..0c7f5f755a28 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -324,10 +324,9 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities)
 		goto exit;
 	}
 	n = kzalloc(sizeof(*n), GFP_ATOMIC);
-	if (!n) {
-		pr_warn("Node creation failed, no memory\n");
+	if (!n)
 		goto exit;
-	}
+
 	n->addr = addr;
 	n->net = net;
 	n->capabilities = capabilities;
-- 
2.13.0

^ permalink raw reply related

* [PATCH v6 net-next 01/17] net: qualcomm: remove unnecessary includes
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

Most of the includes in qca_7k.c are unnecessary so we better remove them.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/qca_7k.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c
index f0066fb..557d53c 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k.c
+++ b/drivers/net/ethernet/qualcomm/qca_7k.c
@@ -23,11 +23,7 @@
  *   kernel-based SPI device.
  */
 
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/spi/spi.h>
-#include <linux/version.h>
 
 #include "qca_7k.h"
 
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 02/17] net: qca_framing: use u16 for frame offset
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

It doesn't make sense to use a signed variable for offset here, so
fix it up.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/qca_framing.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qualcomm/qca_framing.h b/drivers/net/ethernet/qualcomm/qca_framing.h
index d5e795d..8b385e6 100644
--- a/drivers/net/ethernet/qualcomm/qca_framing.h
+++ b/drivers/net/ethernet/qualcomm/qca_framing.h
@@ -103,7 +103,7 @@ struct qcafrm_handle {
 	enum qcafrm_state state;
 
 	/* Offset in buffer (borrowed for length too) */
-	s16 offset;
+	u16 offset;
 
 	/* Frame length as kept by this module */
 	u16 len;
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 03/17] net: qca_7k: Use BIT macro
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

Use the BIT macro for the CONFIG and INT register values.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/qca_7k.h | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h
index 1cad851..4047f0a 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k.h
+++ b/drivers/net/ethernet/qualcomm/qca_7k.h
@@ -54,15 +54,15 @@
 #define SPI_REG_ACTION_CTRL     0x1B00
 
 /*   SPI_CONFIG register definition;             */
-#define QCASPI_SLAVE_RESET_BIT (1 << 6)
+#define QCASPI_SLAVE_RESET_BIT  BIT(6)
 
 /*   INTR_CAUSE/ENABLE register definition.      */
-#define SPI_INT_WRBUF_BELOW_WM (1 << 10)
-#define SPI_INT_CPU_ON         (1 << 6)
-#define SPI_INT_ADDR_ERR       (1 << 3)
-#define SPI_INT_WRBUF_ERR      (1 << 2)
-#define SPI_INT_RDBUF_ERR      (1 << 1)
-#define SPI_INT_PKT_AVLBL      (1 << 0)
+#define SPI_INT_WRBUF_BELOW_WM  BIT(10)
+#define SPI_INT_CPU_ON          BIT(6)
+#define SPI_INT_ADDR_ERR        BIT(3)
+#define SPI_INT_WRBUF_ERR       BIT(2)
+#define SPI_INT_RDBUF_ERR       BIT(1)
+#define SPI_INT_PKT_AVLBL       BIT(0)
 
 void qcaspi_spi_error(struct qcaspi *qca);
 int qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result);
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 05/17] net: qualcomm: use net_device_ops instead of direct call
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

There is no need to export qcaspi_netdev_open and qcaspi_netdev_close
because they are also accessible via the net_device_ops.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/qca_debug.c | 5 +++--
 drivers/net/ethernet/qualcomm/qca_spi.c   | 4 ++--
 drivers/net/ethernet/qualcomm/qca_spi.h   | 3 ---
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c
index d145df9..92b6be9 100644
--- a/drivers/net/ethernet/qualcomm/qca_debug.c
+++ b/drivers/net/ethernet/qualcomm/qca_debug.c
@@ -275,6 +275,7 @@ qcaspi_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
 static int
 qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
 {
+	const struct net_device_ops *ops = dev->netdev_ops;
 	struct qcaspi *qca = netdev_priv(dev);
 
 	if ((ring->rx_pending) ||
@@ -283,13 +284,13 @@ qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
 		return -EINVAL;
 
 	if (netif_running(dev))
-		qcaspi_netdev_close(dev);
+		ops->ndo_stop(dev);
 
 	qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN);
 	qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN);
 
 	if (netif_running(dev))
-		qcaspi_netdev_open(dev);
+		ops->ndo_open(dev);
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 0c3fdee..7e039e3 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -603,7 +603,7 @@ qcaspi_intr_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-int
+static int
 qcaspi_netdev_open(struct net_device *dev)
 {
 	struct qcaspi *qca = netdev_priv(dev);
@@ -640,7 +640,7 @@ qcaspi_netdev_open(struct net_device *dev)
 	return 0;
 }
 
-int
+static int
 qcaspi_netdev_close(struct net_device *dev)
 {
 	struct qcaspi *qca = netdev_priv(dev);
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h
index 6e31a0e..064853d 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.h
+++ b/drivers/net/ethernet/qualcomm/qca_spi.h
@@ -108,7 +108,4 @@ struct qcaspi {
 	u16 burst_len;
 };
 
-int qcaspi_netdev_open(struct net_device *dev);
-int qcaspi_netdev_close(struct net_device *dev);
-
 #endif /* _QCA_SPI_H */
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 07/17] net: qca_spi: remove QCASPI_MTU
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

There is no need for an additional MTU define.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/qca_spi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index f155548..7464628 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -69,7 +69,6 @@ static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN;
 module_param(qcaspi_pluggable, int, 0);
 MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no).");
 
-#define QCASPI_MTU QCAFRM_MAX_MTU
 #define QCASPI_TX_TIMEOUT (1 * HZ)
 #define QCASPI_QCA7K_REBOOT_TIME_MS 1000
 
@@ -746,7 +745,7 @@ qcaspi_netdev_init(struct net_device *dev)
 {
 	struct qcaspi *qca = netdev_priv(dev);
 
-	dev->mtu = QCASPI_MTU;
+	dev->mtu = QCAFRM_MAX_MTU;
 	dev->type = ARPHRD_ETHER;
 	qca->clkspeed = qcaspi_clkspeed;
 	qca->burst_len = qcaspi_burst_len;
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 08/17] net: qualcomm: move qcaspi_tx_cmd to qca_spi.c
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

The function qcaspi_tx_cmd() is only called from qca_spi.c. So we better
move it there.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/qca_7k.c  | 24 ------------------------
 drivers/net/ethernet/qualcomm/qca_7k.h  |  1 -
 drivers/net/ethernet/qualcomm/qca_spi.c | 24 ++++++++++++++++++++++++
 3 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c
index 557d53c..aa90a1d 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k.c
+++ b/drivers/net/ethernet/qualcomm/qca_7k.c
@@ -119,27 +119,3 @@ qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value)
 
 	return ret;
 }
-
-int
-qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd)
-{
-	__be16 tx_data;
-	struct spi_message *msg = &qca->spi_msg1;
-	struct spi_transfer *transfer = &qca->spi_xfer1;
-	int ret;
-
-	tx_data = cpu_to_be16(cmd);
-	transfer->len = sizeof(tx_data);
-	transfer->tx_buf = &tx_data;
-	transfer->rx_buf = NULL;
-
-	ret = spi_sync(qca->spi_dev, msg);
-
-	if (!ret)
-		ret = msg->status;
-
-	if (ret)
-		qcaspi_spi_error(qca);
-
-	return ret;
-}
diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h
index 4047f0a..27124c2 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k.h
+++ b/drivers/net/ethernet/qualcomm/qca_7k.h
@@ -67,6 +67,5 @@
 void qcaspi_spi_error(struct qcaspi *qca);
 int qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result);
 int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value);
-int qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd);
 
 #endif /* _QCA_7K_H */
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 7464628..50adc4f 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -192,6 +192,30 @@ qcaspi_read_legacy(struct qcaspi *qca, u8 *dst, u32 len)
 }
 
 static int
+qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd)
+{
+	__be16 tx_data;
+	struct spi_message *msg = &qca->spi_msg1;
+	struct spi_transfer *transfer = &qca->spi_xfer1;
+	int ret;
+
+	tx_data = cpu_to_be16(cmd);
+	transfer->len = sizeof(tx_data);
+	transfer->tx_buf = &tx_data;
+	transfer->rx_buf = NULL;
+
+	ret = spi_sync(qca->spi_dev, msg);
+
+	if (!ret)
+		ret = msg->status;
+
+	if (ret)
+		qcaspi_spi_error(qca);
+
+	return ret;
+}
+
+static int
 qcaspi_tx_frame(struct qcaspi *qca, struct sk_buff *skb)
 {
 	u32 count;
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 09/17] net: qca_spi: Clarify MODULE_DESCRIPTION
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

Since this driver is specific to the QCA7000, we should make the module
description more precisely.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/qca_spi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 50adc4f..ee90af3 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -999,7 +999,7 @@ static struct spi_driver qca_spi_driver = {
 };
 module_spi_driver(qca_spi_driver);
 
-MODULE_DESCRIPTION("Qualcomm Atheros SPI Driver");
+MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 SPI Driver");
 MODULE_AUTHOR("Qualcomm Atheros Communications");
 MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
 MODULE_LICENSE("Dual BSD/GPL");
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 10/17] net: qualcomm: rename qca_framing.c to qca_7k_common.c
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

As preparation for the upcoming UART driver we need a module
which contains common functions for both interfaces. The module
qca_framing is a good candidate but renaming to qca_7k_common would
make it clear.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/Makefile                           | 2 +-
 drivers/net/ethernet/qualcomm/{qca_framing.c => qca_7k_common.c} | 2 +-
 drivers/net/ethernet/qualcomm/{qca_framing.h => qca_7k_common.h} | 0
 drivers/net/ethernet/qualcomm/qca_spi.c                          | 2 +-
 drivers/net/ethernet/qualcomm/qca_spi.h                          | 2 +-
 5 files changed, 4 insertions(+), 4 deletions(-)
 rename drivers/net/ethernet/qualcomm/{qca_framing.c => qca_7k_common.c} (99%)
 rename drivers/net/ethernet/qualcomm/{qca_framing.h => qca_7k_common.h} (100%)

diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile
index aacb0a5..5e17bf1 100644
--- a/drivers/net/ethernet/qualcomm/Makefile
+++ b/drivers/net/ethernet/qualcomm/Makefile
@@ -3,6 +3,6 @@
 #
 
 obj-$(CONFIG_QCA7000) += qcaspi.o
-qcaspi-objs := qca_spi.o qca_framing.o qca_7k.o qca_debug.o
+qcaspi-objs := qca_spi.o qca_7k_common.o qca_7k.o qca_debug.o
 
 obj-y += emac/
diff --git a/drivers/net/ethernet/qualcomm/qca_framing.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c
similarity index 99%
rename from drivers/net/ethernet/qualcomm/qca_framing.c
rename to drivers/net/ethernet/qualcomm/qca_7k_common.c
index 2341f2b..6d17fbd 100644
--- a/drivers/net/ethernet/qualcomm/qca_framing.c
+++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c
@@ -23,7 +23,7 @@
 
 #include <linux/kernel.h>
 
-#include "qca_framing.h"
+#include "qca_7k_common.h"
 
 u16
 qcafrm_create_header(u8 *buf, u16 length)
diff --git a/drivers/net/ethernet/qualcomm/qca_framing.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h
similarity index 100%
rename from drivers/net/ethernet/qualcomm/qca_framing.h
rename to drivers/net/ethernet/qualcomm/qca_7k_common.h
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index ee90af3..43cc7de 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -43,8 +43,8 @@
 #include <linux/types.h>
 
 #include "qca_7k.h"
+#include "qca_7k_common.h"
 #include "qca_debug.h"
-#include "qca_framing.h"
 #include "qca_spi.h"
 
 #define MAX_DMA_BURST_LEN 5000
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h
index 064853d..fc4beb1 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.h
+++ b/drivers/net/ethernet/qualcomm/qca_spi.h
@@ -32,7 +32,7 @@
 #include <linux/spi/spi.h>
 #include <linux/types.h>
 
-#include "qca_framing.h"
+#include "qca_7k_common.h"
 
 #define QCASPI_DRV_VERSION "0.2.7-i"
 #define QCASPI_DRV_NAME    "qcaspi"
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 11/17] net: qualcomm: prepare frame decoding for UART driver
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

Unfortunately the frame format is not exactly identical between SPI
and UART. In case of SPI there is an additional HW length at the
beginning. So store the initial state to make the decoding state machine
more flexible and easy to extend for UART support.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/qca_7k_common.c | 12 ++++++------
 drivers/net/ethernet/qualcomm/qca_7k_common.h |  8 ++++++--
 drivers/net/ethernet/qualcomm/qca_spi.c       |  2 +-
 3 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c
index 6d17fbd..0d3daa9 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k_common.c
+++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c
@@ -83,7 +83,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
 
 		if (recv_byte != 0x00) {
 			/* first two bytes of length must be 0 */
-			handle->state = QCAFRM_HW_LEN0;
+			handle->state = handle->init;
 		}
 		break;
 	case QCAFRM_HW_LEN2:
@@ -97,7 +97,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
 	case QCAFRM_WAIT_AA4:
 		if (recv_byte != 0xAA) {
 			ret = QCAFRM_NOHEAD;
-			handle->state = QCAFRM_HW_LEN0;
+			handle->state = handle->init;
 		} else {
 			handle->state--;
 		}
@@ -119,7 +119,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
 		len = handle->offset;
 		if (len > buf_len || len < QCAFRM_MIN_LEN) {
 			ret = QCAFRM_INVLEN;
-			handle->state = QCAFRM_HW_LEN0;
+			handle->state = handle->init;
 		} else {
 			handle->state = (enum qcafrm_state)(len + 1);
 			/* Remaining number of bytes. */
@@ -135,7 +135,7 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
 	case QCAFRM_WAIT_551:
 		if (recv_byte != 0x55) {
 			ret = QCAFRM_NOTAIL;
-			handle->state = QCAFRM_HW_LEN0;
+			handle->state = handle->init;
 		} else {
 			handle->state = QCAFRM_WAIT_552;
 		}
@@ -143,11 +143,11 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
 	case QCAFRM_WAIT_552:
 		if (recv_byte != 0x55) {
 			ret = QCAFRM_NOTAIL;
-			handle->state = QCAFRM_HW_LEN0;
+			handle->state = handle->init;
 		} else {
 			ret = handle->offset;
 			/* Frame is fully received. */
-			handle->state = QCAFRM_HW_LEN0;
+			handle->state = handle->init;
 		}
 		break;
 	}
diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h
index 5df7c65..07bdd6c 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k_common.h
+++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h
@@ -61,6 +61,7 @@
 #define QCAFRM_ERR_BASE -1000
 
 enum qcafrm_state {
+	/* HW length is only available on SPI */
 	QCAFRM_HW_LEN0 = 0x8000,
 	QCAFRM_HW_LEN1 = QCAFRM_HW_LEN0 - 1,
 	QCAFRM_HW_LEN2 = QCAFRM_HW_LEN1 - 1,
@@ -101,6 +102,8 @@ enum qcafrm_state {
 struct qcafrm_handle {
 	/*  Current decoding state */
 	enum qcafrm_state state;
+	/* Initial state depends on connection type */
+	enum qcafrm_state init;
 
 	/* Offset in buffer (borrowed for length too) */
 	u16 offset;
@@ -113,9 +116,10 @@ u16 qcafrm_create_header(u8 *buf, u16 len);
 
 u16 qcafrm_create_footer(u8 *buf);
 
-static inline void qcafrm_fsm_init(struct qcafrm_handle *handle)
+static inline void qcafrm_fsm_init_spi(struct qcafrm_handle *handle)
 {
-	handle->state = QCAFRM_HW_LEN0;
+	handle->init = QCAFRM_HW_LEN0;
+	handle->state = handle->init;
 }
 
 /*   Gather received bytes and try to extract a full Ethernet frame
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 43cc7de..de78f60 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -638,7 +638,7 @@ qcaspi_netdev_open(struct net_device *dev)
 	qca->intr_req = 1;
 	qca->intr_svc = 0;
 	qca->sync = QCASPI_SYNC_UNKNOWN;
-	qcafrm_fsm_init(&qca->frm_handle);
+	qcafrm_fsm_init_spi(&qca->frm_handle);
 
 	qca->spi_thread = kthread_run((void *)qcaspi_spi_thread,
 				      qca, "%s", dev->name);
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 12/17] net: qualcomm: make qca_7k_common a separate kernel module
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

In order to share common functions between QCA7000 SPI and UART protocol
driver the qca_7k_common needs to be a separate kernel module.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 drivers/net/ethernet/qualcomm/Kconfig         |  8 +++++++-
 drivers/net/ethernet/qualcomm/Makefile        |  5 +++--
 drivers/net/ethernet/qualcomm/qca_7k_common.c | 10 ++++++++++
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
index d7720bf..b4c369d 100644
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -16,7 +16,13 @@ config NET_VENDOR_QUALCOMM
 if NET_VENDOR_QUALCOMM
 
 config QCA7000
-	tristate "Qualcomm Atheros QCA7000 support"
+	tristate
+	help
+	  This enables support for the Qualcomm Atheros QCA7000.
+
+config QCA7000_SPI
+	tristate "Qualcomm Atheros QCA7000 SPI support"
+	select QCA7000
 	depends on SPI_MASTER && OF
 	---help---
 	  This SPI protocol driver supports the Qualcomm Atheros QCA7000.
diff --git a/drivers/net/ethernet/qualcomm/Makefile b/drivers/net/ethernet/qualcomm/Makefile
index 5e17bf1..65556ca 100644
--- a/drivers/net/ethernet/qualcomm/Makefile
+++ b/drivers/net/ethernet/qualcomm/Makefile
@@ -2,7 +2,8 @@
 # Makefile for the Qualcomm network device drivers.
 #
 
-obj-$(CONFIG_QCA7000) += qcaspi.o
-qcaspi-objs := qca_spi.o qca_7k_common.o qca_7k.o qca_debug.o
+obj-$(CONFIG_QCA7000) += qca_7k_common.o
+obj-$(CONFIG_QCA7000_SPI) += qcaspi.o
+qcaspi-objs := qca_7k.o qca_debug.o qca_spi.o
 
 obj-y += emac/
diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c
index 0d3daa9..6b511f0 100644
--- a/drivers/net/ethernet/qualcomm/qca_7k_common.c
+++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c
@@ -21,7 +21,9 @@
  *   by an atheros frame while transmitted over a serial channel;
  */
 
+#include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 
 #include "qca_7k_common.h"
 
@@ -46,6 +48,7 @@ qcafrm_create_header(u8 *buf, u16 length)
 
 	return QCAFRM_HEADER_LEN;
 }
+EXPORT_SYMBOL_GPL(qcafrm_create_header);
 
 u16
 qcafrm_create_footer(u8 *buf)
@@ -57,6 +60,7 @@ qcafrm_create_footer(u8 *buf)
 	buf[1] = 0x55;
 	return QCAFRM_FOOTER_LEN;
 }
+EXPORT_SYMBOL_GPL(qcafrm_create_footer);
 
 /*   Gather received bytes and try to extract a full ethernet frame by
  *   following a simple state machine.
@@ -154,3 +158,9 @@ qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_by
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(qcafrm_fsm_decode);
+
+MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 common");
+MODULE_AUTHOR("Qualcomm Atheros Communications");
+MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
+MODULE_LICENSE("Dual BSD/GPL");
-- 
2.1.4

^ permalink raw reply related

* [PATCH v6 net-next 13/17] dt-bindings: qca7000-spi: Rework binding
From: Stefan Wahren @ 2017-05-23 13:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, David S. Miller
  Cc: Greg Kroah-Hartman, Jiri Slaby, Lino Sanfilippo, Jakub Kicinski,
	devicetree, netdev, linux-serial, linux-kernel, Stefan Wahren
In-Reply-To: <1495545173-22150-1-git-send-email-stefan.wahren@i2se.com>

In preparation for the QCA7000 UART binding rework the binding document.

Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
 .../devicetree/bindings/net/qca-qca7000-spi.txt    | 49 +++++++++++++---------
 1 file changed, 29 insertions(+), 20 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/qca-qca7000-spi.txt b/Documentation/devicetree/bindings/net/qca-qca7000-spi.txt
index c74989c..a37f656 100644
--- a/Documentation/devicetree/bindings/net/qca-qca7000-spi.txt
+++ b/Documentation/devicetree/bindings/net/qca-qca7000-spi.txt
@@ -1,29 +1,38 @@
-* Qualcomm QCA7000 (Ethernet over SPI protocol)
+* Qualcomm QCA7000
 
-Note: The QCA7000 is useable as a SPI device. In this case it must be defined
-as a child of a SPI master in the device tree.
+The QCA7000 is a serial-to-powerline bridge with a host interface which could
+be configured either as SPI or UART slave. This configuration is done by
+the QCA7000 firmware.
+
+(a) Ethernet over SPI
+
+In order to use the QCA7000 as SPI device it must be defined as a child of a
+SPI master in the device tree.
 
 Required properties:
-- compatible : Should be "qca,qca7000"
-- reg : Should specify the SPI chip select
-- interrupts : The first cell should specify the index of the source interrupt
-  and the second cell should specify the trigger type as rising edge
-- spi-cpha : Must be set
-- spi-cpol: Must be set
+- compatible	    : Should be "qca,qca7000"
+- reg		    : Should specify the SPI chip select
+- interrupts	    : The first cell should specify the index of the source
+		      interrupt and the second cell should specify the trigger
+		      type as rising edge
+- spi-cpha	    : Must be set
+- spi-cpol	    : Must be set
 
 Optional properties:
-- interrupt-parent : Specify the pHandle of the source interrupt
+- interrupt-parent  : Specify the pHandle of the source interrupt
 - spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at.
-  Numbers smaller than 1000000 or greater than 16000000 are invalid. Missing
-  the property will set the SPI frequency to 8000000 Hertz.
-- local-mac-address: 6 bytes, MAC address
-- qca,legacy-mode : Set the SPI data transfer of the QCA7000 to legacy mode.
-  In this mode the SPI master must toggle the chip select between each data
-  word. In burst mode these gaps aren't necessary, which is faster.
-  This setting depends on how the QCA7000 is setup via GPIO pin strapping.
-  If the property is missing the driver defaults to burst mode.
-
-Example:
+		      Numbers smaller than 1000000 or greater than 16000000
+		      are invalid. Missing the property will set the SPI
+		      frequency to 8000000 Hertz.
+- local-mac-address : see ./ethernet.txt
+- qca,legacy-mode   : Set the SPI data transfer of the QCA7000 to legacy mode.
+		      In this mode the SPI master must toggle the chip select
+		      between each data word. In burst mode these gaps aren't
+		      necessary, which is faster. This setting depends on how
+		      the QCA7000 is setup via GPIO pin strapping. If the
+		      property is missing the driver defaults to burst mode.
+
+SPI Example:
 
 /* Freescale i.MX28 SPI master*/
 ssp2: spi@80014000 {
-- 
2.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox