Netdev List
 help / color / mirror / Atom feed
* [PATCH mlx5-next 02/11] net/mlx5: FWTrace, Use async events chain
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Remove the explicit call to mlx5_fw_tracer_event on
MLX5_EVENT_TYPE_DEVICE_TRACER and let fw tracer to register
its own handler when its ready.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 .../mellanox/mlx5/core/diag/fw_tracer.c       | 27 ++++++++++---------
 .../mellanox/mlx5/core/diag/fw_tracer.h       |  2 +-
 drivers/net/ethernet/mellanox/mlx5/core/eq.c  |  4 ---
 3 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
index d4ec93bde4de..6999f4486e9e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
@@ -30,6 +30,7 @@
  * SOFTWARE.
  */
 #define CREATE_TRACE_POINTS
+#include "lib/eq.h"
 #include "fw_tracer.h"
 #include "fw_tracer_tracepoint.h"
 
@@ -846,9 +847,9 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
 	return ERR_PTR(err);
 }
 
-/* Create HW resources + start tracer
- * must be called before Async EQ is created
- */
+static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
+
+/* Create HW resources + start tracer */
 int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
 {
 	struct mlx5_core_dev *dev;
@@ -874,6 +875,9 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
 		goto err_dealloc_pd;
 	}
 
+	MLX5_NB_INIT(&tracer->nb, fw_tracer_event, DEVICE_TRACER);
+	mlx5_eq_notifier_register(dev, &tracer->nb);
+
 	mlx5_fw_tracer_start(tracer);
 
 	return 0;
@@ -883,9 +887,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
 	return err;
 }
 
-/* Stop tracer + Cleanup HW resources
- * must be called after Async EQ is destroyed
- */
+/* Stop tracer + Cleanup HW resources */
 void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
 {
 	if (IS_ERR_OR_NULL(tracer))
@@ -893,7 +895,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
 
 	mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n",
 		      tracer->owner);
-
+	mlx5_eq_notifier_unregister(tracer->dev, &tracer->nb);
 	cancel_work_sync(&tracer->ownership_change_work);
 	cancel_work_sync(&tracer->handle_traces_work);
 
@@ -922,12 +924,11 @@ void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
 	kfree(tracer);
 }
 
-void mlx5_fw_tracer_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe)
+static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data)
 {
-	struct mlx5_fw_tracer *tracer = dev->tracer;
-
-	if (!tracer)
-		return;
+	struct mlx5_fw_tracer *tracer = mlx5_nb_cof(nb, struct mlx5_fw_tracer, nb);
+	struct mlx5_core_dev *dev = tracer->dev;
+	struct mlx5_eqe *eqe = data;
 
 	switch (eqe->sub_type) {
 	case MLX5_TRACER_SUBTYPE_OWNERSHIP_CHANGE:
@@ -942,6 +943,8 @@ void mlx5_fw_tracer_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe)
 		mlx5_core_dbg(dev, "FWTracer: Event with unrecognized subtype: sub_type %d\n",
 			      eqe->sub_type);
 	}
+
+	return NOTIFY_OK;
 }
 
 EXPORT_TRACEPOINT_SYMBOL(mlx5_fw);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h
index 0347f2dd5cee..a8b8747f2b61 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h
@@ -55,6 +55,7 @@
 
 struct mlx5_fw_tracer {
 	struct mlx5_core_dev *dev;
+	struct mlx5_nb        nb;
 	bool owner;
 	u8   trc_ver;
 	struct workqueue_struct *work_queue;
@@ -170,6 +171,5 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev);
 int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer);
 void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer);
 void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer);
-void mlx5_fw_tracer_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe);
 
 #endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 34e4b2c246ff..c7c436b0ed2e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -434,10 +434,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 			general_event_handler(dev, eqe);
 			break;
 
-		case MLX5_EVENT_TYPE_DEVICE_TRACER:
-			mlx5_fw_tracer_event(dev, eqe);
-			break;
-
 		default:
 			mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n",
 				       eqe->type, eq->eqn);
-- 
2.19.1

^ permalink raw reply related

* [PATCH mlx5-next 03/11] net/mlx5: FPGA, Use async events chain
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Remove the explicit call to mlx5_fpga_event on
MLX5_EVENT_TYPE_FPGA_ERROR or MLX5_EVENT_TYPE_FPGA_QP_ERROR
let fpga core to register its own handler when its ready.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/eq.c  |  5 ---
 .../ethernet/mellanox/mlx5/core/fpga/core.c   | 38 ++++++++++++++++---
 .../ethernet/mellanox/mlx5/core/fpga/core.h   | 11 +++---
 3 files changed, 38 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index c7c436b0ed2e..8aabd23d2166 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -421,11 +421,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 			mlx5_pps_event(dev, eqe);
 			break;
 
-		case MLX5_EVENT_TYPE_FPGA_ERROR:
-		case MLX5_EVENT_TYPE_FPGA_QP_ERROR:
-			mlx5_fpga_event(dev, eqe->type, &eqe->data.raw);
-			break;
-
 		case MLX5_EVENT_TYPE_TEMP_WARN_EVENT:
 			mlx5_temp_warning_event(dev, eqe);
 			break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
index 436a8136f26f..27c5f6c7d36a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
@@ -36,6 +36,7 @@
 
 #include "mlx5_core.h"
 #include "lib/mlx5.h"
+#include "lib/eq.h"
 #include "fpga/core.h"
 #include "fpga/conn.h"
 
@@ -145,6 +146,22 @@ static int mlx5_fpga_device_brb(struct mlx5_fpga_device *fdev)
 	return 0;
 }
 
+static int mlx5_fpga_event(struct mlx5_fpga_device *, unsigned long, void *);
+
+static int fpga_err_event(struct notifier_block *nb, unsigned long event, void *eqe)
+{
+	struct mlx5_fpga_device *fdev = mlx5_nb_cof(nb, struct mlx5_fpga_device, fpga_err_nb);
+
+	return mlx5_fpga_event(fdev, event, eqe);
+}
+
+static int fpga_qp_err_event(struct notifier_block *nb, unsigned long event, void *eqe)
+{
+	struct mlx5_fpga_device *fdev = mlx5_nb_cof(nb, struct mlx5_fpga_device, fpga_qp_err_nb);
+
+	return mlx5_fpga_event(fdev, event, eqe);
+}
+
 int mlx5_fpga_device_start(struct mlx5_core_dev *mdev)
 {
 	struct mlx5_fpga_device *fdev = mdev->fpga;
@@ -185,6 +202,11 @@ int mlx5_fpga_device_start(struct mlx5_core_dev *mdev)
 	if (err)
 		goto out;
 
+	MLX5_NB_INIT(&fdev->fpga_err_nb, fpga_err_event, FPGA_ERROR);
+	MLX5_NB_INIT(&fdev->fpga_qp_err_nb, fpga_qp_err_event, FPGA_QP_ERROR);
+	mlx5_eq_notifier_register(fdev->mdev, &fdev->fpga_err_nb);
+	mlx5_eq_notifier_register(fdev->mdev, &fdev->fpga_qp_err_nb);
+
 	err = mlx5_fpga_conn_device_init(fdev);
 	if (err)
 		goto err_rsvd_gid;
@@ -201,6 +223,8 @@ int mlx5_fpga_device_start(struct mlx5_core_dev *mdev)
 	mlx5_fpga_conn_device_cleanup(fdev);
 
 err_rsvd_gid:
+	mlx5_eq_notifier_unregister(fdev->mdev, &fdev->fpga_err_nb);
+	mlx5_eq_notifier_unregister(fdev->mdev, &fdev->fpga_qp_err_nb);
 	mlx5_core_unreserve_gids(mdev, max_num_qps);
 out:
 	spin_lock_irqsave(&fdev->state_lock, flags);
@@ -256,6 +280,9 @@ void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev)
 	}
 
 	mlx5_fpga_conn_device_cleanup(fdev);
+	mlx5_eq_notifier_unregister(fdev->mdev, &fdev->fpga_err_nb);
+	mlx5_eq_notifier_unregister(fdev->mdev, &fdev->fpga_qp_err_nb);
+
 	max_num_qps = MLX5_CAP_FPGA(mdev, shell_caps.max_num_qps);
 	mlx5_core_unreserve_gids(mdev, max_num_qps);
 }
@@ -283,9 +310,10 @@ static const char *mlx5_fpga_qp_syndrome_to_string(u8 syndrome)
 	return "Unknown";
 }
 
-void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data)
+static int mlx5_fpga_event(struct mlx5_fpga_device *fdev,
+			   unsigned long event, void *eqe)
 {
-	struct mlx5_fpga_device *fdev = mdev->fpga;
+	void *data = ((struct mlx5_eqe *)eqe)->data.raw;
 	const char *event_name;
 	bool teardown = false;
 	unsigned long flags;
@@ -303,9 +331,7 @@ void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data)
 		fpga_qpn = MLX5_GET(fpga_qp_error_event, data, fpga_qpn);
 		break;
 	default:
-		mlx5_fpga_warn_ratelimited(fdev, "Unexpected event %u\n",
-					   event);
-		return;
+		return NOTIFY_DONE;
 	}
 
 	spin_lock_irqsave(&fdev->state_lock, flags);
@@ -326,4 +352,6 @@ void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data)
 	 */
 	if (teardown)
 		mlx5_trigger_health_work(fdev->mdev);
+
+	return NOTIFY_OK;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h
index 3e2355c8df3f..7e2e871dbf83 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h
@@ -35,11 +35,16 @@
 
 #ifdef CONFIG_MLX5_FPGA
 
+#include <linux/mlx5/eq.h>
+
+#include "lib/eq.h"
 #include "fpga/cmd.h"
 
 /* Represents an Innova device */
 struct mlx5_fpga_device {
 	struct mlx5_core_dev *mdev;
+	struct mlx5_nb fpga_err_nb;
+	struct mlx5_nb fpga_qp_err_nb;
 	spinlock_t state_lock; /* Protects state transitions */
 	enum mlx5_fpga_status state;
 	enum mlx5_fpga_image last_admin_image;
@@ -82,7 +87,6 @@ int mlx5_fpga_init(struct mlx5_core_dev *mdev);
 void mlx5_fpga_cleanup(struct mlx5_core_dev *mdev);
 int mlx5_fpga_device_start(struct mlx5_core_dev *mdev);
 void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev);
-void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data);
 
 #else
 
@@ -104,11 +108,6 @@ static inline void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev)
 {
 }
 
-static inline void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event,
-				   void *data)
-{
-}
-
 #endif
 
 #endif /* __MLX5_FPGA_CORE_H__ */
-- 
2.19.1

^ permalink raw reply related

* [PATCH mlx5-next 04/11] net/mlx5: Clock, Use async events chain
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Remove the explicit call to mlx5_pps_event on MLX5_EVENT_TYPE_PPS_EVENT
and let clock logic to register its own handler when its ready.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/eq.c  |  4 ----
 .../ethernet/mellanox/mlx5/core/lib/clock.c   | 24 +++++++++++++------
 .../ethernet/mellanox/mlx5/core/lib/clock.h   |  3 ---
 include/linux/mlx5/driver.h                   |  4 +++-
 4 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 8aabd23d2166..e5fcce9ca107 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -417,10 +417,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 			mlx5_port_module_event(dev, eqe);
 			break;
 
-		case MLX5_EVENT_TYPE_PPS_EVENT:
-			mlx5_pps_event(dev, eqe);
-			break;
-
 		case MLX5_EVENT_TYPE_TEMP_WARN_EVENT:
 			mlx5_temp_warning_event(dev, eqe);
 			break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
index 0d90b1b4a3d3..d27c239e7d6c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
@@ -33,6 +33,7 @@
 #include <linux/clocksource.h>
 #include <linux/highmem.h>
 #include <rdma/mlx5-abi.h>
+#include "lib/eq.h"
 #include "en.h"
 #include "clock.h"
 
@@ -439,16 +440,17 @@ static void mlx5_get_pps_caps(struct mlx5_core_dev *mdev)
 	clock->pps_info.pin_caps[7] = MLX5_GET(mtpps_reg, out, cap_pin_7_mode);
 }
 
-void mlx5_pps_event(struct mlx5_core_dev *mdev,
-		    struct mlx5_eqe *eqe)
+static int mlx5_pps_event(struct notifier_block *nb,
+			  unsigned long type, void *data)
 {
-	struct mlx5_clock *clock = &mdev->clock;
+	struct mlx5_clock *clock = mlx5_nb_cof(nb, struct mlx5_clock, pps_nb);
+	struct mlx5_core_dev *mdev = clock->mdev;
 	struct ptp_clock_event ptp_event;
-	struct timespec64 ts;
-	u64 nsec_now, nsec_delta;
 	u64 cycles_now, cycles_delta;
+	u64 nsec_now, nsec_delta, ns;
+	struct mlx5_eqe *eqe = data;
 	int pin = eqe->data.pps.pin;
-	s64 ns;
+	struct timespec64 ts;
 	unsigned long flags;
 
 	switch (clock->ptp_info.pin_config[pin].func) {
@@ -463,6 +465,7 @@ void mlx5_pps_event(struct mlx5_core_dev *mdev,
 		} else {
 			ptp_event.type = PTP_CLOCK_EXTTS;
 		}
+		/* TODOL clock->ptp can be NULL if ptp_clock_register failes */
 		ptp_clock_event(clock->ptp, &ptp_event);
 		break;
 	case PTP_PF_PEROUT:
@@ -481,8 +484,11 @@ void mlx5_pps_event(struct mlx5_core_dev *mdev,
 		write_sequnlock_irqrestore(&clock->lock, flags);
 		break;
 	default:
-		mlx5_core_err(mdev, " Unhandled event\n");
+		mlx5_core_err(mdev, " Unhandled clock PPS event, func %d\n",
+			      clock->ptp_info.pin_config[pin].func);
 	}
+
+	return NOTIFY_OK;
 }
 
 void mlx5_init_clock(struct mlx5_core_dev *mdev)
@@ -567,6 +573,9 @@ void mlx5_init_clock(struct mlx5_core_dev *mdev)
 			       PTR_ERR(clock->ptp));
 		clock->ptp = NULL;
 	}
+
+	MLX5_NB_INIT(&clock->pps_nb, mlx5_pps_event, PPS_EVENT);
+	mlx5_eq_notifier_register(mdev, &clock->pps_nb);
 }
 
 void mlx5_cleanup_clock(struct mlx5_core_dev *mdev)
@@ -576,6 +585,7 @@ void mlx5_cleanup_clock(struct mlx5_core_dev *mdev)
 	if (!MLX5_CAP_GEN(mdev, device_frequency_khz))
 		return;
 
+	mlx5_eq_notifier_unregister(mdev, &clock->pps_nb);
 	if (clock->ptp) {
 		ptp_clock_unregister(clock->ptp);
 		clock->ptp = NULL;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h
index 263cb6e2aeee..31600924bdc3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.h
@@ -36,7 +36,6 @@
 #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
 void mlx5_init_clock(struct mlx5_core_dev *mdev);
 void mlx5_cleanup_clock(struct mlx5_core_dev *mdev);
-void mlx5_pps_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe);
 
 static inline int mlx5_clock_get_ptp_index(struct mlx5_core_dev *mdev)
 {
@@ -60,8 +59,6 @@ static inline ktime_t mlx5_timecounter_cyc2time(struct mlx5_clock *clock,
 #else
 static inline void mlx5_init_clock(struct mlx5_core_dev *mdev) {}
 static inline void mlx5_cleanup_clock(struct mlx5_core_dev *mdev) {}
-static inline void mlx5_pps_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe) {}
-
 static inline int mlx5_clock_get_ptp_index(struct mlx5_core_dev *mdev)
 {
 	return -1;
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index f41e6713df10..99a23db9a929 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -50,6 +50,7 @@
 #include <linux/mlx5/device.h>
 #include <linux/mlx5/doorbell.h>
 #include <linux/mlx5/srq.h>
+#include <linux/mlx5/eq.h>
 #include <linux/timecounter.h>
 #include <linux/ptp_clock_kernel.h>
 
@@ -671,6 +672,8 @@ struct mlx5_pps {
 };
 
 struct mlx5_clock {
+	struct mlx5_core_dev      *mdev;
+	struct mlx5_nb             pps_nb;
 	seqlock_t                  lock;
 	struct cyclecounter        cycles;
 	struct timecounter         tc;
@@ -678,7 +681,6 @@ struct mlx5_clock {
 	u32                        nominal_c_mult;
 	unsigned long              overflow_period;
 	struct delayed_work        overflow_work;
-	struct mlx5_core_dev      *mdev;
 	struct ptp_clock          *ptp;
 	struct ptp_clock_info      ptp_info;
 	struct mlx5_pps            pps_info;
-- 
2.19.1

^ permalink raw reply related

* [PATCH mlx5-next 05/11] net/mlx5: E-Switch, Use async events chain
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Remove the explicit call to mlx5_eswitch_vport_event on
MLX5_EVENT_TYPE_NIC_VPORT_CHANGE and let the eswitch register its own
handler when its ready.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/eq.c  |  4 --
 .../net/ethernet/mellanox/mlx5/core/eswitch.c | 44 +++++++++++--------
 .../net/ethernet/mellanox/mlx5/core/eswitch.h |  3 +-
 3 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index e5fcce9ca107..7c8b2d89645b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -409,10 +409,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 			}
 			break;
 
-		case MLX5_EVENT_TYPE_NIC_VPORT_CHANGE:
-			mlx5_eswitch_vport_event(dev->priv.eswitch, eqe);
-			break;
-
 		case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
 			mlx5_port_module_event(dev, eqe);
 			break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 2346b6ba3d54..e6a9b19d8626 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -36,6 +36,7 @@
 #include <linux/mlx5/vport.h>
 #include <linux/mlx5/fs.h>
 #include "mlx5_core.h"
+#include "lib/eq.h"
 #include "eswitch.h"
 #include "fs_core.h"
 #include "lib/eq.h"
@@ -1568,7 +1569,6 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num)
 	/* Mark this vport as disabled to discard new events */
 	vport->enabled = false;
 
-	mlx5_eq_synchronize_async_irq(esw->dev);
 	/* Wait for current already scheduled events to complete */
 	flush_workqueue(esw->work_queue);
 	/* Disable events from this vport */
@@ -1594,10 +1594,25 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num)
 	mutex_unlock(&esw->state_lock);
 }
 
+static int eswitch_vport_event(struct notifier_block *nb,
+			       unsigned long type, void *data)
+{
+	struct mlx5_eswitch *esw = mlx5_nb_cof(nb, struct mlx5_eswitch, nb);
+	struct mlx5_eqe *eqe = data;
+	struct mlx5_vport *vport;
+	u16 vport_num;
+
+	vport_num = be16_to_cpu(eqe->data.vport_change.vport_num);
+	vport = &esw->vports[vport_num];
+	if (vport->enabled)
+		queue_work(esw->work_queue, &vport->vport_change_handler);
+
+	return NOTIFY_OK;
+}
+
 /* Public E-Switch API */
 #define ESW_ALLOWED(esw) ((esw) && MLX5_ESWITCH_MANAGER((esw)->dev))
 
-
 int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
 {
 	int err;
@@ -1641,6 +1656,11 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
 	for (i = 0; i <= nvfs; i++)
 		esw_enable_vport(esw, i, enabled_events);
 
+	if (mode == SRIOV_LEGACY) {
+		MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
+		mlx5_eq_notifier_register(esw->dev, &esw->nb);
+	}
+
 	esw_info(esw->dev, "SRIOV enabled: active vports(%d)\n",
 		 esw->enabled_vports);
 	return 0;
@@ -1670,6 +1690,9 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
 	mc_promisc = &esw->mc_promisc;
 	nvports = esw->enabled_vports;
 
+	if (esw->mode == SRIOV_LEGACY)
+		mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
+
 	for (i = 0; i < esw->total_vports; i++)
 		esw_disable_vport(esw, i);
 
@@ -1778,23 +1801,6 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
 	kfree(esw);
 }
 
-void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe)
-{
-	struct mlx5_eqe_vport_change *vc_eqe = &eqe->data.vport_change;
-	u16 vport_num = be16_to_cpu(vc_eqe->vport_num);
-	struct mlx5_vport *vport;
-
-	if (!esw) {
-		pr_warn("MLX5 E-Switch: vport %d got an event while eswitch is not initialized\n",
-			vport_num);
-		return;
-	}
-
-	vport = &esw->vports[vport_num];
-	if (vport->enabled)
-		queue_work(esw->work_queue, &vport->vport_change_handler);
-}
-
 /* Vport Administration */
 #define LEGAL_VPORT(esw, vport) (vport >= 0 && vport < esw->total_vports)
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index aaafc9f17115..480ffa294867 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -181,6 +181,7 @@ struct esw_mc_addr { /* SRIOV only */
 
 struct mlx5_eswitch {
 	struct mlx5_core_dev    *dev;
+	struct mlx5_nb          nb;
 	struct mlx5_eswitch_fdb fdb_table;
 	struct hlist_head       mc_table[MLX5_L2_ADDR_HASH_SIZE];
 	struct workqueue_struct *work_queue;
@@ -211,7 +212,6 @@ int esw_offloads_init_reps(struct mlx5_eswitch *esw);
 /* E-Switch API */
 int mlx5_eswitch_init(struct mlx5_core_dev *dev);
 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw);
-void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe);
 int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode);
 void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw);
 int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
@@ -352,7 +352,6 @@ static inline bool mlx5_eswitch_vlan_actions_supported(struct mlx5_core_dev *dev
 /* eswitch API stubs */
 static inline int  mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
 static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {}
-static inline void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe) {}
 static inline int  mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) { return 0; }
 static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw) {}
 
-- 
2.19.1

^ permalink raw reply related

* [PATCH mlx5-next 06/11] net/mlx5: FWPage, Use async events chain
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Remove the explicit call to mlx5_core_req_pages_handler on
MLX5_EVENT_TYPE_PAGE_REQUEST and let FW page logic  to register its own
handler when its ready.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/eq.c  | 11 -----
 .../net/ethernet/mellanox/mlx5/core/main.c    | 27 ++++++------
 .../ethernet/mellanox/mlx5/core/pagealloc.c   | 44 +++++++++++++------
 include/linux/mlx5/driver.h                   |  5 ++-
 4 files changed, 47 insertions(+), 40 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 7c8b2d89645b..7f6a644700eb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -398,17 +398,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 			mlx5_eq_cq_event(eq, cqn, eqe->type);
 			break;
 
-		case MLX5_EVENT_TYPE_PAGE_REQUEST:
-			{
-				u16 func_id = be16_to_cpu(eqe->data.req_pages.func_id);
-				s32 npages = be32_to_cpu(eqe->data.req_pages.num_pages);
-
-				mlx5_core_dbg(dev, "page request for func 0x%x, npages %d\n",
-					      func_id, npages);
-				mlx5_core_req_pages_handler(dev, func_id, npages);
-			}
-			break;
-
 		case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
 			mlx5_port_module_event(dev, eqe);
 			break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 91022f141855..9e4cd2757ea8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -916,16 +916,10 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 		goto reclaim_boot_pages;
 	}
 
-	err = mlx5_pagealloc_start(dev);
-	if (err) {
-		dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n");
-		goto reclaim_boot_pages;
-	}
-
 	err = mlx5_cmd_init_hca(dev, sw_owner_id);
 	if (err) {
 		dev_err(&pdev->dev, "init hca failed\n");
-		goto err_pagealloc_stop;
+		goto reclaim_boot_pages;
 	}
 
 	mlx5_set_driver_version(dev);
@@ -953,6 +947,8 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 		goto err_get_uars;
 	}
 
+	mlx5_pagealloc_start(dev);
+
 	err = mlx5_eq_table_create(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Failed to create EQs\n");
@@ -1039,6 +1035,7 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 	mlx5_eq_table_destroy(dev);
 
 err_eq_table:
+	mlx5_pagealloc_stop(dev);
 	mlx5_put_uars_page(dev, priv->uar);
 
 err_get_uars:
@@ -1052,9 +1049,6 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 		goto out_err;
 	}
 
-err_pagealloc_stop:
-	mlx5_pagealloc_stop(dev);
-
 reclaim_boot_pages:
 	mlx5_reclaim_startup_pages(dev);
 
@@ -1100,16 +1094,18 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 	mlx5_fpga_device_stop(dev);
 	mlx5_fw_tracer_cleanup(dev->tracer);
 	mlx5_eq_table_destroy(dev);
+	mlx5_pagealloc_stop(dev);
 	mlx5_put_uars_page(dev, priv->uar);
+
 	if (cleanup)
 		mlx5_cleanup_once(dev);
 	mlx5_stop_health_poll(dev, cleanup);
+
 	err = mlx5_cmd_teardown_hca(dev);
 	if (err) {
 		dev_err(&dev->pdev->dev, "tear_down_hca failed, skip cleanup\n");
 		goto out;
 	}
-	mlx5_pagealloc_stop(dev);
 	mlx5_reclaim_startup_pages(dev);
 	mlx5_core_disable_hca(dev, 0);
 	mlx5_cmd_cleanup(dev);
@@ -1186,12 +1182,14 @@ static int init_one(struct pci_dev *pdev,
 		goto close_pci;
 	}
 
-	mlx5_pagealloc_init(dev);
+	err = mlx5_pagealloc_init(dev);
+	if (err)
+		goto err_pagealloc_init;
 
 	err = mlx5_load_one(dev, priv, true);
 	if (err) {
 		dev_err(&pdev->dev, "mlx5_load_one failed with error code %d\n", err);
-		goto clean_health;
+		goto err_load_one;
 	}
 
 	request_module_nowait(MLX5_IB_MOD);
@@ -1205,8 +1203,9 @@ static int init_one(struct pci_dev *pdev,
 
 clean_load:
 	mlx5_unload_one(dev, priv, true);
-clean_health:
+err_load_one:
 	mlx5_pagealloc_cleanup(dev);
+err_pagealloc_init:
 	mlx5_health_cleanup(dev);
 close_pci:
 	mlx5_pci_close(dev, priv);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
index e36d3e3675f9..a83b517b0714 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
@@ -37,6 +37,7 @@
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/cmd.h>
 #include "mlx5_core.h"
+#include "lib/eq.h"
 
 enum {
 	MLX5_PAGES_CANT_GIVE	= 0,
@@ -433,15 +434,28 @@ static void pages_work_handler(struct work_struct *work)
 	kfree(req);
 }
 
-void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
-				 s32 npages)
+static int req_pages_handler(struct notifier_block *nb,
+			     unsigned long type, void *data)
 {
 	struct mlx5_pages_req *req;
-
+	struct mlx5_core_dev *dev;
+	struct mlx5_priv *priv;
+	struct mlx5_eqe *eqe;
+	u16 func_id;
+	s32 npages;
+
+	priv = mlx5_nb_cof(nb, struct mlx5_priv, pg_nb);
+	dev  = container_of(priv, struct mlx5_core_dev, priv);
+	eqe  = data;
+
+	func_id = be16_to_cpu(eqe->data.req_pages.func_id);
+	npages  = be32_to_cpu(eqe->data.req_pages.num_pages);
+	mlx5_core_dbg(dev, "page request for func 0x%x, npages %d\n",
+		      func_id, npages);
 	req = kzalloc(sizeof(*req), GFP_ATOMIC);
 	if (!req) {
 		mlx5_core_warn(dev, "failed to allocate pages request\n");
-		return;
+		return NOTIFY_DONE;
 	}
 
 	req->dev = dev;
@@ -449,6 +463,7 @@ void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
 	req->npages = npages;
 	INIT_WORK(&req->work, pages_work_handler);
 	queue_work(dev->priv.pg_wq, &req->work);
+	return NOTIFY_OK;
 }
 
 int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)
@@ -524,29 +539,32 @@ int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)
 	return 0;
 }
 
-void mlx5_pagealloc_init(struct mlx5_core_dev *dev)
+int mlx5_pagealloc_init(struct mlx5_core_dev *dev)
 {
 	dev->priv.page_root = RB_ROOT;
 	INIT_LIST_HEAD(&dev->priv.free_list);
+	dev->priv.pg_wq = create_singlethread_workqueue("mlx5_page_allocator");
+	if (!dev->priv.pg_wq)
+		return -ENOMEM;
+
+	return 0;
 }
 
 void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev)
 {
-	/* nothing */
+	destroy_workqueue(dev->priv.pg_wq);
 }
 
-int mlx5_pagealloc_start(struct mlx5_core_dev *dev)
+void mlx5_pagealloc_start(struct mlx5_core_dev *dev)
 {
-	dev->priv.pg_wq = create_singlethread_workqueue("mlx5_page_allocator");
-	if (!dev->priv.pg_wq)
-		return -ENOMEM;
-
-	return 0;
+	MLX5_NB_INIT(&dev->priv.pg_nb, req_pages_handler, PAGE_REQUEST);
+	mlx5_eq_notifier_register(dev, &dev->priv.pg_nb);
 }
 
 void mlx5_pagealloc_stop(struct mlx5_core_dev *dev)
 {
-	destroy_workqueue(dev->priv.pg_wq);
+	mlx5_eq_notifier_unregister(dev, &dev->priv.pg_nb);
+	flush_workqueue(dev->priv.pg_wq);
 }
 
 int mlx5_wait_for_vf_pages(struct mlx5_core_dev *dev)
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 99a23db9a929..61088ad33500 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -564,6 +564,7 @@ struct mlx5_priv {
 	struct mlx5_eq_table	*eq_table;
 
 	/* pages stuff */
+	struct mlx5_nb          pg_nb;
 	struct workqueue_struct *pg_wq;
 	struct rb_root		page_root;
 	int			fw_pages;
@@ -962,9 +963,9 @@ int mlx5_core_alloc_pd(struct mlx5_core_dev *dev, u32 *pdn);
 int mlx5_core_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn);
 int mlx5_core_mad_ifc(struct mlx5_core_dev *dev, const void *inb, void *outb,
 		      u16 opmod, u8 port);
-void mlx5_pagealloc_init(struct mlx5_core_dev *dev);
+int mlx5_pagealloc_init(struct mlx5_core_dev *dev);
 void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev);
-int mlx5_pagealloc_start(struct mlx5_core_dev *dev);
+void mlx5_pagealloc_start(struct mlx5_core_dev *dev);
 void mlx5_pagealloc_stop(struct mlx5_core_dev *dev);
 void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
 				 s32 npages);
-- 
2.19.1

^ permalink raw reply related

* [PATCH mlx5-next 07/11] net/mlx5: CmdIF, Use async events chain
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Remove the explicit call to mlx5_cmd_comp_handler on MLX5_EVENT_TYPE_CMD
and let command interface to register its own handler when its ready.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 48 ++++++++++++++++++-
 drivers/net/ethernet/mellanox/mlx5/core/eq.c  |  4 --
 .../net/ethernet/mellanox/mlx5/core/health.c  | 25 +---------
 .../ethernet/mellanox/mlx5/core/mlx5_core.h   |  2 +-
 include/linux/mlx5/driver.h                   |  2 +
 5 files changed, 50 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index 7b18aff955f1..8ab636d59edb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -40,9 +40,11 @@
 #include <linux/random.h>
 #include <linux/io-mapping.h>
 #include <linux/mlx5/driver.h>
+#include <linux/mlx5/eq.h>
 #include <linux/debugfs.h>
 
 #include "mlx5_core.h"
+#include "lib/eq.h"
 
 enum {
 	CMD_IF_REV = 5,
@@ -805,6 +807,8 @@ static u16 msg_to_opcode(struct mlx5_cmd_msg *in)
 	return MLX5_GET(mbox_in, in->first.data, opcode);
 }
 
+static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced);
+
 static void cb_timeout_handler(struct work_struct *work)
 {
 	struct delayed_work *dwork = container_of(work, struct delayed_work,
@@ -1412,14 +1416,32 @@ static void mlx5_cmd_change_mod(struct mlx5_core_dev *dev, int mode)
 		up(&cmd->sem);
 }
 
+static int cmd_comp_notifier(struct notifier_block *nb,
+			     unsigned long type, void *data)
+{
+	struct mlx5_core_dev *dev;
+	struct mlx5_cmd *cmd;
+	struct mlx5_eqe *eqe;
+
+	cmd = mlx5_nb_cof(nb, struct mlx5_cmd, nb);
+	dev = container_of(cmd, struct mlx5_core_dev, cmd);
+	eqe = data;
+
+	mlx5_cmd_comp_handler(dev, be32_to_cpu(eqe->data.cmd.vector), false);
+
+	return NOTIFY_OK;
+}
 void mlx5_cmd_use_events(struct mlx5_core_dev *dev)
 {
+	MLX5_NB_INIT(&dev->cmd.nb, cmd_comp_notifier, CMD);
+	mlx5_eq_notifier_register(dev, &dev->cmd.nb);
 	mlx5_cmd_change_mod(dev, CMD_MODE_EVENTS);
 }
 
 void mlx5_cmd_use_polling(struct mlx5_core_dev *dev)
 {
 	mlx5_cmd_change_mod(dev, CMD_MODE_POLLING);
+	mlx5_eq_notifier_unregister(dev, &dev->cmd.nb);
 }
 
 static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
@@ -1435,7 +1457,7 @@ static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
 	}
 }
 
-void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
+static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
 {
 	struct mlx5_cmd *cmd = &dev->cmd;
 	struct mlx5_cmd_work_ent *ent;
@@ -1533,7 +1555,29 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
 		}
 	}
 }
-EXPORT_SYMBOL(mlx5_cmd_comp_handler);
+
+void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev)
+{
+	unsigned long flags;
+	u64 vector;
+
+	/* wait for pending handlers to complete */
+	mlx5_eq_synchronize_cmd_irq(dev);
+	spin_lock_irqsave(&dev->cmd.alloc_lock, flags);
+	vector = ~dev->cmd.bitmask & ((1ul << (1 << dev->cmd.log_sz)) - 1);
+	if (!vector)
+		goto no_trig;
+
+	vector |= MLX5_TRIGGERED_CMD_COMP;
+	spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
+
+	mlx5_core_dbg(dev, "vector 0x%llx\n", vector);
+	mlx5_cmd_comp_handler(dev, vector, true);
+	return;
+
+no_trig:
+	spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
+}
 
 static int status_to_err(u8 status)
 {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 7f6a644700eb..b28869aa1a4e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -368,10 +368,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 			mlx5_srq_event(dev, rsn, eqe->type);
 			break;
 
-		case MLX5_EVENT_TYPE_CMD:
-			mlx5_cmd_comp_handler(dev, be32_to_cpu(eqe->data.cmd.vector), false);
-			break;
-
 		case MLX5_EVENT_TYPE_PORT_CHANGE:
 			port = (eqe->data.port.port >> 4) & 0xf;
 			switch (eqe->sub_type) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
index 066883003aea..4e42bd290959 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -79,29 +79,6 @@ void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state)
 		    &dev->iseg->cmdq_addr_l_sz);
 }
 
-static void trigger_cmd_completions(struct mlx5_core_dev *dev)
-{
-	unsigned long flags;
-	u64 vector;
-
-	/* wait for pending handlers to complete */
-	mlx5_eq_synchronize_cmd_irq(dev);
-	spin_lock_irqsave(&dev->cmd.alloc_lock, flags);
-	vector = ~dev->cmd.bitmask & ((1ul << (1 << dev->cmd.log_sz)) - 1);
-	if (!vector)
-		goto no_trig;
-
-	vector |= MLX5_TRIGGERED_CMD_COMP;
-	spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
-
-	mlx5_core_dbg(dev, "vector 0x%llx\n", vector);
-	mlx5_cmd_comp_handler(dev, vector, true);
-	return;
-
-no_trig:
-	spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
-}
-
 static int in_fatal(struct mlx5_core_dev *dev)
 {
 	struct mlx5_core_health *health = &dev->priv.health;
@@ -125,7 +102,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)
 	mlx5_core_err(dev, "start\n");
 	if (pci_channel_offline(dev->pdev) || in_fatal(dev) || force) {
 		dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR;
-		trigger_cmd_completions(dev);
+		mlx5_cmd_trigger_completions(dev);
 	}
 
 	mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 1);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index e06c6e16ffc9..5dd453e47a04 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -127,7 +127,7 @@ int mlx5_destroy_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
 int mlx5_wait_for_vf_pages(struct mlx5_core_dev *dev);
 u64 mlx5_read_internal_timer(struct mlx5_core_dev *dev);
 
-void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced);
+void mlx5_cmd_trigger_completions(struct mlx5_core_dev *dev);
 int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev);
 void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev);
 
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 61088ad33500..a8d638134fc8 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -278,6 +278,8 @@ struct mlx5_cmd_stats {
 };
 
 struct mlx5_cmd {
+	struct mlx5_nb    nb;
+
 	void	       *cmd_alloc_buf;
 	dma_addr_t	alloc_dma;
 	int		alloc_size;
-- 
2.19.1

^ permalink raw reply related

* [PATCH mlx5-next 08/11] net/mlx5: Resource tables, Use async events chain
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Remove the explicit call to QP/SRQ resources events handlers on several FW
events and let resources logic register resources events notifiers via the
new API.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/eq.c  | 29 --------
 drivers/net/ethernet/mellanox/mlx5/core/qp.c  | 68 +++++++++++++++----
 drivers/net/ethernet/mellanox/mlx5/core/srq.c | 55 +++++++++++++--
 include/linux/mlx5/driver.h                   |  6 +-
 4 files changed, 108 insertions(+), 50 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index b28869aa1a4e..0cf448575ebd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -324,7 +324,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 	struct mlx5_eqe *eqe;
 	int set_ci = 0;
 	u32 cqn = -1;
-	u32 rsn;
 	u8 port;
 
 	dev = eq->dev;
@@ -340,34 +339,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 		mlx5_core_dbg(eq->dev, "eqn %d, eqe type %s\n",
 			      eq->eqn, eqe_type_str(eqe->type));
 		switch (eqe->type) {
-		case MLX5_EVENT_TYPE_DCT_DRAINED:
-			rsn = be32_to_cpu(eqe->data.dct.dctn) & 0xffffff;
-			rsn |= (MLX5_RES_DCT << MLX5_USER_INDEX_LEN);
-			mlx5_rsc_event(dev, rsn, eqe->type);
-			break;
-		case MLX5_EVENT_TYPE_PATH_MIG:
-		case MLX5_EVENT_TYPE_COMM_EST:
-		case MLX5_EVENT_TYPE_SQ_DRAINED:
-		case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
-		case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
-		case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
-		case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
-		case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
-			rsn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff;
-			rsn |= (eqe->data.qp_srq.type << MLX5_USER_INDEX_LEN);
-			mlx5_core_dbg(dev, "event %s(%d) arrived on resource 0x%x\n",
-				      eqe_type_str(eqe->type), eqe->type, rsn);
-			mlx5_rsc_event(dev, rsn, eqe->type);
-			break;
-
-		case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
-		case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
-			rsn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff;
-			mlx5_core_dbg(dev, "SRQ event %s(%d): srqn 0x%x\n",
-				      eqe_type_str(eqe->type), eqe->type, rsn);
-			mlx5_srq_event(dev, rsn, eqe->type);
-			break;
-
 		case MLX5_EVENT_TYPE_PORT_CHANGE:
 			port = (eqe->data.port.port >> 4) & 0xf;
 			switch (eqe->sub_type) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
index cba4a435043a..28726c63101f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
@@ -38,11 +38,11 @@
 #include <linux/mlx5/transobj.h>
 
 #include "mlx5_core.h"
+#include "lib/eq.h"
 
-static struct mlx5_core_rsc_common *mlx5_get_rsc(struct mlx5_core_dev *dev,
-						 u32 rsn)
+static struct mlx5_core_rsc_common *
+mlx5_get_rsc(struct mlx5_qp_table *table, u32 rsn)
 {
-	struct mlx5_qp_table *table = &dev->priv.qp_table;
 	struct mlx5_core_rsc_common *common;
 
 	spin_lock(&table->lock);
@@ -53,11 +53,6 @@ static struct mlx5_core_rsc_common *mlx5_get_rsc(struct mlx5_core_dev *dev,
 
 	spin_unlock(&table->lock);
 
-	if (!common) {
-		mlx5_core_warn(dev, "Async event for bogus resource 0x%x\n",
-			       rsn);
-		return NULL;
-	}
 	return common;
 }
 
@@ -120,14 +115,52 @@ static bool is_event_type_allowed(int rsc_type, int event_type)
 	}
 }
 
-void mlx5_rsc_event(struct mlx5_core_dev *dev, u32 rsn, int event_type)
+static int rsc_event_notifier(struct notifier_block *nb,
+			      unsigned long type, void *data)
 {
-	struct mlx5_core_rsc_common *common = mlx5_get_rsc(dev, rsn);
+	struct mlx5_core_rsc_common *common;
+	struct mlx5_qp_table *table;
+	struct mlx5_core_dev *dev;
 	struct mlx5_core_dct *dct;
+	u8 event_type = (u8)type;
 	struct mlx5_core_qp *qp;
+	struct mlx5_priv *priv;
+	struct mlx5_eqe *eqe;
+	u32 rsn;
+
+	switch (event_type) {
+	case MLX5_EVENT_TYPE_DCT_DRAINED:
+		eqe = data;
+		rsn = be32_to_cpu(eqe->data.dct.dctn) & 0xffffff;
+		rsn |= (MLX5_RES_DCT << MLX5_USER_INDEX_LEN);
+		break;
+	case MLX5_EVENT_TYPE_PATH_MIG:
+	case MLX5_EVENT_TYPE_COMM_EST:
+	case MLX5_EVENT_TYPE_SQ_DRAINED:
+	case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+	case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+	case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+	case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+	case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+		eqe = data;
+		rsn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff;
+		rsn |= (eqe->data.qp_srq.type << MLX5_USER_INDEX_LEN);
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	table = mlx5_nb_cof(nb, struct mlx5_qp_table, nb);
+	priv  = container_of(table, struct mlx5_priv, qp_table);
+	dev   = container_of(priv, struct mlx5_core_dev, priv);
 
-	if (!common)
-		return;
+	mlx5_core_dbg(dev, "event (%d) arrived on resource 0x%x\n", eqe->type, rsn);
+
+	common = mlx5_get_rsc(table, rsn);
+	if (!common) {
+		mlx5_core_warn(dev, "Async event for bogus resource 0x%x\n", rsn);
+		return NOTIFY_OK;
+	}
 
 	if (!is_event_type_allowed((rsn >> MLX5_USER_INDEX_LEN), event_type)) {
 		mlx5_core_warn(dev, "event 0x%.2x is not allowed on resource 0x%.8x\n",
@@ -152,6 +185,8 @@ void mlx5_rsc_event(struct mlx5_core_dev *dev, u32 rsn, int event_type)
 	}
 out:
 	mlx5_core_put_rsc(common);
+
+	return NOTIFY_OK;
 }
 
 static int create_resource_common(struct mlx5_core_dev *dev,
@@ -487,10 +522,16 @@ void mlx5_init_qp_table(struct mlx5_core_dev *dev)
 	spin_lock_init(&table->lock);
 	INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
 	mlx5_qp_debugfs_init(dev);
+
+	MLX5_NB_INIT(&table->nb, rsc_event_notifier, NOTIFY_ANY);
+	mlx5_eq_notifier_register(dev, &table->nb);
 }
 
 void mlx5_cleanup_qp_table(struct mlx5_core_dev *dev)
 {
+	struct mlx5_qp_table *table = &dev->priv.qp_table;
+
+	mlx5_eq_notifier_unregister(dev, &table->nb);
 	mlx5_qp_debugfs_cleanup(dev);
 }
 
@@ -676,8 +717,9 @@ struct mlx5_core_rsc_common *mlx5_core_res_hold(struct mlx5_core_dev *dev,
 						enum mlx5_res_type res_type)
 {
 	u32 rsn = res_num | (res_type << MLX5_USER_INDEX_LEN);
+	struct mlx5_qp_table *table = &dev->priv.qp_table;
 
-	return mlx5_get_rsc(dev, rsn);
+	return mlx5_get_rsc(table, rsn);
 }
 EXPORT_SYMBOL_GPL(mlx5_core_res_hold);
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c
index 6a6fc9be01e6..0563866c13f2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c
@@ -36,13 +36,25 @@
 #include <linux/mlx5/cmd.h>
 #include <linux/mlx5/srq.h>
 #include <rdma/ib_verbs.h>
-#include "mlx5_core.h"
 #include <linux/mlx5/transobj.h>
+#include "mlx5_core.h"
+#include "lib/eq.h"
 
-void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type)
+static int srq_event_notifier(struct mlx5_srq_table *table,
+			      unsigned long type, void *data)
 {
-	struct mlx5_srq_table *table = &dev->priv.srq_table;
+	struct mlx5_core_dev *dev;
 	struct mlx5_core_srq *srq;
+	struct mlx5_priv *priv;
+	struct mlx5_eqe *eqe;
+	u32 srqn;
+
+	priv  = container_of(table, struct mlx5_priv, srq_table);
+	dev   = container_of(priv, struct mlx5_core_dev, priv);
+
+	eqe = data;
+	srqn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff;
+	mlx5_core_dbg(dev, "SRQ event (%d): srqn 0x%x\n", eqe->type, srqn);
 
 	spin_lock(&table->lock);
 
@@ -54,13 +66,35 @@ void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type)
 
 	if (!srq) {
 		mlx5_core_warn(dev, "Async event for bogus SRQ 0x%08x\n", srqn);
-		return;
+		return NOTIFY_OK;
 	}
 
-	srq->event(srq, event_type);
+	srq->event(srq, eqe->type);
 
 	if (atomic_dec_and_test(&srq->refcount))
 		complete(&srq->free);
+
+	return NOTIFY_OK;
+}
+
+static int catas_err_notifier(struct notifier_block *nb,
+			      unsigned long type, void *data)
+{
+	struct mlx5_srq_table *table;
+
+	table = mlx5_nb_cof(nb, struct mlx5_srq_table, catas_err_nb);
+	/* type == MLX5_EVENT_TYPE_SRQ_CATAS_ERROR */
+	return srq_event_notifier(table, type, data);
+}
+
+static int rq_limit_notifier(struct notifier_block *nb,
+			     unsigned long type, void *data)
+{
+	struct mlx5_srq_table *table;
+
+	table = mlx5_nb_cof(nb, struct mlx5_srq_table, rq_limit_nb);
+	/* type == MLX5_EVENT_TYPE_SRQ_RQ_LIMIT */
+	return srq_event_notifier(table, type, data);
 }
 
 static int get_pas_size(struct mlx5_srq_attr *in)
@@ -708,9 +742,18 @@ void mlx5_init_srq_table(struct mlx5_core_dev *dev)
 	memset(table, 0, sizeof(*table));
 	spin_lock_init(&table->lock);
 	INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+
+	MLX5_NB_INIT(&table->catas_err_nb, catas_err_notifier, SRQ_CATAS_ERROR);
+	mlx5_eq_notifier_register(dev, &table->catas_err_nb);
+
+	MLX5_NB_INIT(&table->rq_limit_nb, rq_limit_notifier, SRQ_RQ_LIMIT);
+	mlx5_eq_notifier_register(dev, &table->rq_limit_nb);
 }
 
 void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev)
 {
-	/* nothing */
+	struct mlx5_srq_table *table = &dev->priv.srq_table;
+
+	mlx5_eq_notifier_unregister(dev, &table->rq_limit_nb);
+	mlx5_eq_notifier_unregister(dev, &table->catas_err_nb);
 }
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index a8d638134fc8..afba0864f45c 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -464,6 +464,8 @@ struct mlx5_core_health {
 };
 
 struct mlx5_qp_table {
+	struct mlx5_nb          nb;
+
 	/* protect radix tree
 	 */
 	spinlock_t		lock;
@@ -471,6 +473,8 @@ struct mlx5_qp_table {
 };
 
 struct mlx5_srq_table {
+	struct mlx5_nb          catas_err_nb;
+	struct mlx5_nb          rq_limit_nb;
 	/* protect radix tree
 	 */
 	spinlock_t		lock;
@@ -978,8 +982,6 @@ void mlx5_unregister_debugfs(void);
 
 void mlx5_fill_page_array(struct mlx5_frag_buf *buf, __be64 *pas);
 void mlx5_fill_page_frag_array(struct mlx5_frag_buf *frag_buf, __be64 *pas);
-void mlx5_rsc_event(struct mlx5_core_dev *dev, u32 rsn, int event_type);
-void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type);
 struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn);
 int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn,
 		    unsigned int *irqn);
-- 
2.19.1

^ permalink raw reply related

* [PATCH mlx5-next 09/11] net/mlx5: CQ ERR, Use async events chain
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Remove the explicit call to mlx5_eq_cq_event on MLX5_EVENT_TYPE_CQ_ERROR
and register a specific CQ ERROR handler via the new API.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/eq.c | 66 +++++++++++++-------
 1 file changed, 44 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 0cf448575ebd..4e3febbf639d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -74,6 +74,9 @@ struct mlx5_eq_table {
 
 	struct atomic_notifier_head nh[MLX5_EVENT_TYPE_MAX];
 
+	/* Since CQ DB is stored in async_eq */
+	struct mlx5_nb          cq_err_nb;
+
 	struct mutex            lock; /* sync async eqs creations */
 	int			num_comp_vectors;
 	struct mlx5_irq_info	*irq_info;
@@ -235,20 +238,6 @@ static struct mlx5_core_cq *mlx5_eq_cq_get(struct mlx5_eq *eq, u32 cqn)
 	return cq;
 }
 
-static void mlx5_eq_cq_event(struct mlx5_eq *eq, u32 cqn, int event_type)
-{
-	struct mlx5_core_cq *cq = mlx5_eq_cq_get(eq, cqn);
-
-	if (unlikely(!cq)) {
-		mlx5_core_warn(eq->dev, "Async event for bogus CQ 0x%x\n", cqn);
-		return;
-	}
-
-	cq->event(cq, event_type);
-
-	mlx5_cq_put(cq);
-}
-
 static irqreturn_t mlx5_eq_comp_int(int irq, void *eq_ptr)
 {
 	struct mlx5_eq_comp *eq_comp = eq_ptr;
@@ -323,7 +312,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 	struct mlx5_core_dev *dev;
 	struct mlx5_eqe *eqe;
 	int set_ci = 0;
-	u32 cqn = -1;
 	u8 port;
 
 	dev = eq->dev;
@@ -358,12 +346,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 					       port, eqe->sub_type);
 			}
 			break;
-		case MLX5_EVENT_TYPE_CQ_ERROR:
-			cqn = be32_to_cpu(eqe->data.cq_err.cqn) & 0xffffff;
-			mlx5_core_warn(dev, "CQ error on CQN 0x%x, syndrome 0x%x\n",
-				       cqn, eqe->data.cq_err.syndrome);
-			mlx5_eq_cq_event(eq, cqn, eqe->type);
-			break;
 
 		case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
 			mlx5_port_module_event(dev, eqe);
@@ -639,6 +621,38 @@ static int destroy_async_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
 	return err;
 }
 
+static int cq_err_event_notifier(struct notifier_block *nb,
+				 unsigned long type, void *data)
+{
+	struct mlx5_eq_table *eqt;
+	struct mlx5_core_cq *cq;
+	struct mlx5_eqe *eqe;
+	struct mlx5_eq *eq;
+	u32 cqn;
+
+	/* type == MLX5_EVENT_TYPE_CQ_ERROR */
+
+	eqt = mlx5_nb_cof(nb, struct mlx5_eq_table, cq_err_nb);
+	eq  = &eqt->async_eq;
+	eqe = data;
+
+	cqn = be32_to_cpu(eqe->data.cq_err.cqn) & 0xffffff;
+	mlx5_core_warn(eq->dev, "CQ error on CQN 0x%x, syndrome 0x%x\n",
+		       cqn, eqe->data.cq_err.syndrome);
+
+	cq = mlx5_eq_cq_get(eq, cqn);
+	if (unlikely(!cq)) {
+		mlx5_core_warn(eq->dev, "Async event for bogus CQ 0x%x\n", cqn);
+		return NOTIFY_OK;
+	}
+
+	cq->event(cq, type);
+
+	mlx5_cq_put(cq);
+
+	return NOTIFY_OK;
+}
+
 static u64 gather_async_events_mask(struct mlx5_core_dev *dev)
 {
 	u64 async_event_mask = MLX5_ASYNC_EVENT_MASK;
@@ -679,6 +693,9 @@ static int create_async_eqs(struct mlx5_core_dev *dev)
 	struct mlx5_eq_param param = {};
 	int err;
 
+	MLX5_NB_INIT(&table->cq_err_nb, cq_err_event_notifier, CQ_ERROR);
+	mlx5_eq_notifier_register(dev, &table->cq_err_nb);
+
 	param = (struct mlx5_eq_param) {
 		.index = MLX5_EQ_CMD_IDX,
 		.mask = 1ull << MLX5_EVENT_TYPE_CMD,
@@ -689,7 +706,7 @@ static int create_async_eqs(struct mlx5_core_dev *dev)
 	err = create_async_eq(dev, "mlx5_cmd_eq", &table->cmd_eq, &param);
 	if (err) {
 		mlx5_core_warn(dev, "failed to create cmd EQ %d\n", err);
-		return err;
+		goto err0;
 	}
 
 	mlx5_cmd_use_events(dev);
@@ -728,6 +745,8 @@ static int create_async_eqs(struct mlx5_core_dev *dev)
 err1:
 	mlx5_cmd_use_polling(dev);
 	destroy_async_eq(dev, &table->cmd_eq);
+err0:
+	mlx5_eq_notifier_unregister(dev, &table->cq_err_nb);
 	return err;
 }
 
@@ -745,12 +764,15 @@ static void destroy_async_eqs(struct mlx5_core_dev *dev)
 	if (err)
 		mlx5_core_err(dev, "failed to destroy async eq, err(%d)\n",
 			      err);
+
 	mlx5_cmd_use_polling(dev);
 
 	err = destroy_async_eq(dev, &table->cmd_eq);
 	if (err)
 		mlx5_core_err(dev, "failed to destroy command eq, err(%d)\n",
 			      err);
+
+	mlx5_eq_notifier_unregister(dev, &table->cq_err_nb);
 }
 
 struct mlx5_eq *mlx5_get_async_eq(struct mlx5_core_dev *dev)
-- 
2.19.1

^ permalink raw reply related

* [PATCH mlx5-next 11/11] net/mlx5: Improve core device events handling
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Register a separate handler per event type, rather than listening for all
events and looking for the events to handle in a switch case.

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/events.c  | 223 +++++++++++-------
 1 file changed, 136 insertions(+), 87 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/events.c b/drivers/net/ethernet/mellanox/mlx5/core/events.c
index d3ab86bd394b..3ad004af37d7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/events.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/events.c
@@ -2,15 +2,41 @@
 // Copyright (c) 2018 Mellanox Technologies
 
 #include <linux/mlx5/driver.h>
+
 #include "mlx5_core.h"
 #include "lib/eq.h"
 #include "lib/mlx5.h"
 
+struct mlx5_event_nb {
+	struct mlx5_nb  nb;
+	void           *ctx;
+};
+
+/* General events handlers for the low level mlx5_core driver
+ *
+ * Other Major feature specific events such as
+ * clock/eswitch/fpga/FW trace and many others, are handled elsewhere, with
+ * separate notifiers callbacks, specifically by those mlx5 components.
+ */
+static int any_notifier(struct notifier_block *, unsigned long, void *);
+static int port_change(struct notifier_block *, unsigned long, void *);
+static int general_event(struct notifier_block *, unsigned long, void *);
+static int temp_warn(struct notifier_block *, unsigned long, void *);
+static int port_module(struct notifier_block *, unsigned long, void *);
+
+static struct mlx5_nb events_nbs_ref[] = {
+	{.nb.notifier_call = any_notifier,  .event_type = MLX5_EVENT_TYPE_NOTIFY_ANY },
+	{.nb.notifier_call = port_change,   .event_type = MLX5_EVENT_TYPE_PORT_CHANGE },
+	{.nb.notifier_call = general_event, .event_type = MLX5_EVENT_TYPE_GENERAL_EVENT },
+	{.nb.notifier_call = temp_warn,     .event_type = MLX5_EVENT_TYPE_TEMP_WARN_EVENT },
+	{.nb.notifier_call = port_module,   .event_type = MLX5_EVENT_TYPE_PORT_MODULE_EVENT },
+};
+
 struct mlx5_events {
-	struct mlx5_nb        nb;
 	struct mlx5_core_dev *dev;
+	struct mlx5_event_nb  notifiers[ARRAY_SIZE(events_nbs_ref)];
 
-	/* port module evetns stats */
+	/* port module events stats */
 	struct mlx5_pme_stats pme_stats;
 };
 
@@ -80,6 +106,19 @@ static const char *eqe_type_str(u8 type)
 	}
 }
 
+/* handles all FW events, type == eqe->type */
+static int any_notifier(struct notifier_block *nb,
+			unsigned long type, void *data)
+{
+	struct mlx5_event_nb *event_nb = mlx5_nb_cof(nb, struct mlx5_event_nb, nb);
+	struct mlx5_events   *events   = event_nb->ctx;
+	struct mlx5_eqe      *eqe      = data;
+
+	mlx5_core_dbg(events->dev, "Async eqe type %s, subtype (%d)\n",
+		      eqe_type_str(eqe->type), eqe->sub_type);
+	return NOTIFY_OK;
+}
+
 static enum mlx5_dev_event port_subtype2dev(u8 subtype)
 {
 	switch (subtype) {
@@ -101,19 +140,92 @@ static enum mlx5_dev_event port_subtype2dev(u8 subtype)
 	return -1;
 }
 
-static void temp_warning_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe)
+/* type == MLX5_EVENT_TYPE_PORT_CHANGE */
+static int port_change(struct notifier_block *nb,
+		       unsigned long type, void *data)
 {
+	struct mlx5_event_nb *event_nb = mlx5_nb_cof(nb, struct mlx5_event_nb, nb);
+	struct mlx5_events   *events   = event_nb->ctx;
+	struct mlx5_core_dev *dev      = events->dev;
+
+	bool dev_event_dispatch = false;
+	enum mlx5_dev_event dev_event;
+	unsigned long dev_event_data;
+	struct mlx5_eqe *eqe = data;
+	u8 port = (eqe->data.port.port >> 4) & 0xf;
+
+	switch (eqe->sub_type) {
+	case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
+	case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
+	case MLX5_PORT_CHANGE_SUBTYPE_LID:
+	case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
+	case MLX5_PORT_CHANGE_SUBTYPE_GUID:
+	case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
+	case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
+		dev_event = port_subtype2dev(eqe->sub_type);
+		dev_event_data = (unsigned long)port;
+		dev_event_dispatch = true;
+		break;
+	default:
+		mlx5_core_warn(dev, "Port event with unrecognized subtype: port %d, sub_type %d\n",
+			       port, eqe->sub_type);
+	}
+
+	if (dev->event && dev_event_dispatch)
+		dev->event(dev, dev_event, dev_event_data);
+
+	return NOTIFY_OK;
+}
+
+/* type == MLX5_EVENT_TYPE_GENERAL_EVENT */
+static int general_event(struct notifier_block *nb, unsigned long type, void *data)
+{
+	struct mlx5_event_nb *event_nb = mlx5_nb_cof(nb, struct mlx5_event_nb, nb);
+	struct mlx5_events   *events   = event_nb->ctx;
+	struct mlx5_core_dev *dev      = events->dev;
+
+	bool dev_event_dispatch = false;
+	enum mlx5_dev_event dev_event;
+	unsigned long dev_event_data;
+	struct mlx5_eqe *eqe = data;
+
+	switch (eqe->sub_type) {
+	case MLX5_GENERAL_SUBTYPE_DELAY_DROP_TIMEOUT:
+		dev_event = MLX5_DEV_EVENT_DELAY_DROP_TIMEOUT;
+		dev_event_data = 0;
+		dev_event_dispatch = true;
+		break;
+	default:
+		mlx5_core_dbg(dev, "General event with unrecognized subtype: sub_type %d\n",
+			      eqe->sub_type);
+	}
+
+	if (dev->event && dev_event_dispatch)
+		dev->event(dev, dev_event, dev_event_data);
+
+	return NOTIFY_OK;
+}
+
+/* type == MLX5_EVENT_TYPE_TEMP_WARN_EVENT */
+static int temp_warn(struct notifier_block *nb, unsigned long type, void *data)
+{
+	struct mlx5_event_nb *event_nb = mlx5_nb_cof(nb, struct mlx5_event_nb, nb);
+	struct mlx5_events   *events   = event_nb->ctx;
+	struct mlx5_eqe      *eqe      = data;
 	u64 value_lsb;
 	u64 value_msb;
 
 	value_lsb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_lsb);
 	value_msb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_msb);
 
-	mlx5_core_warn(dev,
+	mlx5_core_warn(events->dev,
 		       "High temperature on sensors with bit set %llx %llx",
 		       value_msb, value_lsb);
+
+	return NOTIFY_OK;
 }
 
+/* MLX5_EVENT_TYPE_PORT_MODULE_EVENT */
 static const char *mlx5_pme_status[MLX5_MODULE_STATUS_NUM] = {
 	"Cable plugged",   /* MLX5_MODULE_STATUS_PLUGGED    = 0x1 */
 	"Cable unplugged", /* MLX5_MODULE_STATUS_UNPLUGGED  = 0x2 */
@@ -132,12 +244,16 @@ static const char *mlx5_pme_error[MLX5_MODULE_EVENT_ERROR_NUM] = {
 	"Unknown status",
 };
 
-static void port_module_event(struct mlx5_events *events, struct mlx5_eqe *eqe)
+/* type == MLX5_EVENT_TYPE_PORT_MODULE_EVENT */
+static int port_module(struct notifier_block *nb, unsigned long type, void *data)
 {
+	struct mlx5_event_nb *event_nb = mlx5_nb_cof(nb, struct mlx5_event_nb, nb);
+	struct mlx5_events   *events   = event_nb->ctx;
+	struct mlx5_eqe      *eqe      = data;
+
 	enum port_module_event_status_type module_status;
 	enum port_module_event_error_type error_type;
 	struct mlx5_eqe_port_module *module_event_eqe;
-	struct mlx5_core_dev *dev = events->dev;
 	u8 module_num;
 
 	module_event_eqe = &eqe->data.port_module;
@@ -146,7 +262,6 @@ static void port_module_event(struct mlx5_events *events, struct mlx5_eqe *eqe)
 			PORT_MODULE_EVENT_MODULE_STATUS_MASK;
 	error_type = module_event_eqe->error_type &
 		     PORT_MODULE_EVENT_ERROR_TYPE_MASK;
-
 	if (module_status < MLX5_MODULE_STATUS_ERROR) {
 		events->pme_stats.status_counters[module_status - 1]++;
 	} else if (module_status == MLX5_MODULE_STATUS_ERROR) {
@@ -157,18 +272,20 @@ static void port_module_event(struct mlx5_events *events, struct mlx5_eqe *eqe)
 	}
 
 	if (!printk_ratelimit())
-		return;
+		return NOTIFY_OK;
 
 	if (module_status < MLX5_MODULE_STATUS_ERROR)
-		mlx5_core_info(dev,
+		mlx5_core_info(events->dev,
 			       "Port module event: module %u, %s\n",
 			       module_num, mlx5_pme_status[module_status - 1]);
 
 	else if (module_status == MLX5_MODULE_STATUS_ERROR)
-		mlx5_core_info(dev,
+		mlx5_core_info(events->dev,
 			       "Port module event[error]: module %u, %s, %s\n",
 			       module_num, mlx5_pme_status[module_status - 1],
 			       mlx5_pme_error[error_type]);
+
+	return NOTIFY_OK;
 }
 
 void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats)
@@ -176,80 +293,6 @@ void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats)
 	*stats = dev->priv.events->pme_stats;
 }
 
-/* Event handler for the low level mlx5_core driver.
- * This handler will process/filter _some_ events and sometimes dispatch
- * the equivalent mlx5_dev_event to the HCA interfaces (mlx5_ib and mlx5e)
- *
- * Other Major feature specific events such as
- * clock/eswitch/fpga/FW trace and many others, are handled elsewhere, with
- * separate notifiers callbacks, specifically by those mlx5 components.
- */
-static int events_notifier(struct notifier_block *nb,
-			   unsigned long type, void *data)
-{
-	bool dev_event_dispatch = false;
-	enum mlx5_dev_event dev_event;
-	unsigned long dev_event_data;
-
-	struct mlx5_eqe *eqe = data;
-	struct mlx5_events *events;
-	struct mlx5_core_dev *dev;
-	u8 port;
-
-	events = mlx5_nb_cof(nb, struct mlx5_events, nb);
-	dev = events->dev;
-
-	mlx5_core_dbg(dev, "Async eqe type %s, subtype (%d)\n",
-		      eqe_type_str(eqe->type), eqe->sub_type);
-	switch (eqe->type) {
-	case MLX5_EVENT_TYPE_PORT_CHANGE:
-		port = (eqe->data.port.port >> 4) & 0xf;
-		switch (eqe->sub_type) {
-		case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
-		case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
-		case MLX5_PORT_CHANGE_SUBTYPE_LID:
-		case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
-		case MLX5_PORT_CHANGE_SUBTYPE_GUID:
-		case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
-		case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
-			dev_event = port_subtype2dev(eqe->sub_type);
-			dev_event_data = (unsigned long)port;
-			dev_event_dispatch = true;
-			break;
-		default:
-			mlx5_core_warn(dev, "Port event with unrecognized subtype: port %d, sub_type %d\n",
-				       port, eqe->sub_type);
-		}
-		break;
-	case MLX5_EVENT_TYPE_GENERAL_EVENT:
-		switch (eqe->sub_type) {
-		case MLX5_GENERAL_SUBTYPE_DELAY_DROP_TIMEOUT:
-			dev_event = MLX5_DEV_EVENT_DELAY_DROP_TIMEOUT;
-			dev_event_data = 0;
-			dev_event_dispatch = true;
-			break;
-		default:
-			mlx5_core_dbg(dev, "General event with unrecognized subtype: sub_type %d\n",
-				      eqe->sub_type);
-		}
-		break;
-
-	case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
-		port_module_event(events, eqe);
-		break;
-	case MLX5_EVENT_TYPE_TEMP_WARN_EVENT:
-		temp_warning_event(dev, eqe);
-		break;
-	default:
-		return NOTIFY_DONE;
-	}
-
-	if (dev->event && dev_event_dispatch)
-		dev->event(dev, dev_event, dev_event_data);
-
-	return NOTIFY_OK;
-}
-
 int mlx5_events_init(struct mlx5_core_dev *dev)
 {
 	struct mlx5_events *events = kzalloc(sizeof(*events), GFP_KERNEL);
@@ -270,14 +313,20 @@ void mlx5_events_cleanup(struct mlx5_core_dev *dev)
 void mlx5_events_start(struct mlx5_core_dev *dev)
 {
 	struct mlx5_events *events = dev->priv.events;
+	int i;
 
-	MLX5_NB_INIT(&events->nb, events_notifier, NOTIFY_ANY);
-	mlx5_eq_notifier_register(dev, &events->nb);
+	for (i = 0; i < ARRAY_SIZE(events_nbs_ref); i++) {
+		events->notifiers[i].nb  = events_nbs_ref[i];
+		events->notifiers[i].ctx = events;
+		mlx5_eq_notifier_register(dev, &events->notifiers[i].nb);
+	}
 }
 
 void mlx5_events_stop(struct mlx5_core_dev *dev)
 {
 	struct mlx5_events *events = dev->priv.events;
+	int i;
 
-	mlx5_eq_notifier_unregister(dev, &events->nb);
+	for (i = ARRAY_SIZE(events_nbs_ref) - 1; i >= 0 ; i--)
+		mlx5_eq_notifier_unregister(dev, &events->notifiers[i].nb);
 }
-- 
2.19.1

^ permalink raw reply related

* [PATCH mlx5-next 10/11] net/mlx5: Device events, Use async events chain
From: Saeed Mahameed @ 2018-11-20 22:12 UTC (permalink / raw)
  To: Leon Romanovsky, saeedm; +Cc: netdev, linux-rdma, Jason Gunthorpe
In-Reply-To: <20181120221228.18365-1-saeedm@mellanox.com>

Move all the generic async events handling into new specific events
handling file events.c to keep eq.c file clean from concrete event logic
handling.

Use new API to register for NOTIFY_ANY to handle generic events and
dispatch allowed events to mlx5_core consumers (mlx5_ib and mlx5e)

Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/Makefile  |   2 +-
 .../ethernet/mellanox/mlx5/core/en_stats.c    |   9 +-
 drivers/net/ethernet/mellanox/mlx5/core/eq.c  | 157 ----------
 .../net/ethernet/mellanox/mlx5/core/events.c  | 283 ++++++++++++++++++
 .../ethernet/mellanox/mlx5/core/lib/mlx5.h    |  34 +++
 .../net/ethernet/mellanox/mlx5/core/main.c    |  16 +-
 .../ethernet/mellanox/mlx5/core/mlx5_core.h   |   6 +-
 .../net/ethernet/mellanox/mlx5/core/port.c    |  57 ----
 include/linux/mlx5/driver.h                   |  29 +-
 include/linux/mlx5/port.h                     |   3 -
 10 files changed, 344 insertions(+), 252 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/events.c

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index d324a3884462..26afe0779a0c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -14,7 +14,7 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
 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 wq.o lib/gid.o  \
+		fs_counters.o rl.o lag.o dev.o events.o wq.o lib/gid.o \
 		diag/fs_tracepoint.o diag/fw_tracer.o
 
 #
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index 1e55b9c27ffc..748d23806391 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -30,6 +30,7 @@
  * SOFTWARE.
  */
 
+#include "lib/mlx5.h"
 #include "en.h"
 #include "en_accel/ipsec.h"
 #include "en_accel/tls.h"
@@ -1120,15 +1121,17 @@ static int mlx5e_grp_pme_fill_strings(struct mlx5e_priv *priv, u8 *data,
 static int mlx5e_grp_pme_fill_stats(struct mlx5e_priv *priv, u64 *data,
 				    int idx)
 {
-	struct mlx5_priv *mlx5_priv = &priv->mdev->priv;
+	struct mlx5_pme_stats pme_stats;
 	int i;
 
+	mlx5_get_pme_stats(priv->mdev, &pme_stats);
+
 	for (i = 0; i < NUM_PME_STATUS_STATS; i++)
-		data[idx++] = MLX5E_READ_CTR64_CPU(mlx5_priv->pme_stats.status_counters,
+		data[idx++] = MLX5E_READ_CTR64_CPU(pme_stats.status_counters,
 						   mlx5e_pme_status_desc, i);
 
 	for (i = 0; i < NUM_PME_ERR_STATS; i++)
-		data[idx++] = MLX5E_READ_CTR64_CPU(mlx5_priv->pme_stats.error_counters,
+		data[idx++] = MLX5E_READ_CTR64_CPU(pme_stats.error_counters,
 						   mlx5e_pme_error_desc, i);
 
 	return idx;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
index 4e3febbf639d..4aa39a1fe23f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c
@@ -108,121 +108,6 @@ static int mlx5_cmd_destroy_eq(struct mlx5_core_dev *dev, u8 eqn)
 	return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 }
 
-static const char *eqe_type_str(u8 type)
-{
-	switch (type) {
-	case MLX5_EVENT_TYPE_COMP:
-		return "MLX5_EVENT_TYPE_COMP";
-	case MLX5_EVENT_TYPE_PATH_MIG:
-		return "MLX5_EVENT_TYPE_PATH_MIG";
-	case MLX5_EVENT_TYPE_COMM_EST:
-		return "MLX5_EVENT_TYPE_COMM_EST";
-	case MLX5_EVENT_TYPE_SQ_DRAINED:
-		return "MLX5_EVENT_TYPE_SQ_DRAINED";
-	case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
-		return "MLX5_EVENT_TYPE_SRQ_LAST_WQE";
-	case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
-		return "MLX5_EVENT_TYPE_SRQ_RQ_LIMIT";
-	case MLX5_EVENT_TYPE_CQ_ERROR:
-		return "MLX5_EVENT_TYPE_CQ_ERROR";
-	case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
-		return "MLX5_EVENT_TYPE_WQ_CATAS_ERROR";
-	case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
-		return "MLX5_EVENT_TYPE_PATH_MIG_FAILED";
-	case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
-		return "MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR";
-	case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
-		return "MLX5_EVENT_TYPE_WQ_ACCESS_ERROR";
-	case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
-		return "MLX5_EVENT_TYPE_SRQ_CATAS_ERROR";
-	case MLX5_EVENT_TYPE_INTERNAL_ERROR:
-		return "MLX5_EVENT_TYPE_INTERNAL_ERROR";
-	case MLX5_EVENT_TYPE_PORT_CHANGE:
-		return "MLX5_EVENT_TYPE_PORT_CHANGE";
-	case MLX5_EVENT_TYPE_GPIO_EVENT:
-		return "MLX5_EVENT_TYPE_GPIO_EVENT";
-	case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
-		return "MLX5_EVENT_TYPE_PORT_MODULE_EVENT";
-	case MLX5_EVENT_TYPE_TEMP_WARN_EVENT:
-		return "MLX5_EVENT_TYPE_TEMP_WARN_EVENT";
-	case MLX5_EVENT_TYPE_REMOTE_CONFIG:
-		return "MLX5_EVENT_TYPE_REMOTE_CONFIG";
-	case MLX5_EVENT_TYPE_DB_BF_CONGESTION:
-		return "MLX5_EVENT_TYPE_DB_BF_CONGESTION";
-	case MLX5_EVENT_TYPE_STALL_EVENT:
-		return "MLX5_EVENT_TYPE_STALL_EVENT";
-	case MLX5_EVENT_TYPE_CMD:
-		return "MLX5_EVENT_TYPE_CMD";
-	case MLX5_EVENT_TYPE_PAGE_REQUEST:
-		return "MLX5_EVENT_TYPE_PAGE_REQUEST";
-	case MLX5_EVENT_TYPE_PAGE_FAULT:
-		return "MLX5_EVENT_TYPE_PAGE_FAULT";
-	case MLX5_EVENT_TYPE_PPS_EVENT:
-		return "MLX5_EVENT_TYPE_PPS_EVENT";
-	case MLX5_EVENT_TYPE_NIC_VPORT_CHANGE:
-		return "MLX5_EVENT_TYPE_NIC_VPORT_CHANGE";
-	case MLX5_EVENT_TYPE_FPGA_ERROR:
-		return "MLX5_EVENT_TYPE_FPGA_ERROR";
-	case MLX5_EVENT_TYPE_FPGA_QP_ERROR:
-		return "MLX5_EVENT_TYPE_FPGA_QP_ERROR";
-	case MLX5_EVENT_TYPE_GENERAL_EVENT:
-		return "MLX5_EVENT_TYPE_GENERAL_EVENT";
-	case MLX5_EVENT_TYPE_DEVICE_TRACER:
-		return "MLX5_EVENT_TYPE_DEVICE_TRACER";
-	default:
-		return "Unrecognized event";
-	}
-}
-
-static enum mlx5_dev_event port_subtype_event(u8 subtype)
-{
-	switch (subtype) {
-	case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
-		return MLX5_DEV_EVENT_PORT_DOWN;
-	case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
-		return MLX5_DEV_EVENT_PORT_UP;
-	case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
-		return MLX5_DEV_EVENT_PORT_INITIALIZED;
-	case MLX5_PORT_CHANGE_SUBTYPE_LID:
-		return MLX5_DEV_EVENT_LID_CHANGE;
-	case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
-		return MLX5_DEV_EVENT_PKEY_CHANGE;
-	case MLX5_PORT_CHANGE_SUBTYPE_GUID:
-		return MLX5_DEV_EVENT_GUID_CHANGE;
-	case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
-		return MLX5_DEV_EVENT_CLIENT_REREG;
-	}
-	return -1;
-}
-
-static void general_event_handler(struct mlx5_core_dev *dev,
-				  struct mlx5_eqe *eqe)
-{
-	switch (eqe->sub_type) {
-	case MLX5_GENERAL_SUBTYPE_DELAY_DROP_TIMEOUT:
-		if (dev->event)
-			dev->event(dev, MLX5_DEV_EVENT_DELAY_DROP_TIMEOUT, 0);
-		break;
-	default:
-		mlx5_core_dbg(dev, "General event with unrecognized subtype: sub_type %d\n",
-			      eqe->sub_type);
-	}
-}
-
-static void mlx5_temp_warning_event(struct mlx5_core_dev *dev,
-				    struct mlx5_eqe *eqe)
-{
-	u64 value_lsb;
-	u64 value_msb;
-
-	value_lsb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_lsb);
-	value_msb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_msb);
-
-	mlx5_core_warn(dev,
-		       "High temperature on sensors with bit set %llx %llx",
-		       value_msb, value_lsb);
-}
-
 /* caller must eventually call mlx5_cq_put on the returned cq */
 static struct mlx5_core_cq *mlx5_eq_cq_get(struct mlx5_eq *eq, u32 cqn)
 {
@@ -312,7 +197,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 	struct mlx5_core_dev *dev;
 	struct mlx5_eqe *eqe;
 	int set_ci = 0;
-	u8 port;
 
 	dev = eq->dev;
 	eqt = dev->priv.eq_table;
@@ -324,47 +208,6 @@ static irqreturn_t mlx5_eq_async_int(int irq, void *eq_ptr)
 		 */
 		dma_rmb();
 
-		mlx5_core_dbg(eq->dev, "eqn %d, eqe type %s\n",
-			      eq->eqn, eqe_type_str(eqe->type));
-		switch (eqe->type) {
-		case MLX5_EVENT_TYPE_PORT_CHANGE:
-			port = (eqe->data.port.port >> 4) & 0xf;
-			switch (eqe->sub_type) {
-			case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
-			case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
-			case MLX5_PORT_CHANGE_SUBTYPE_LID:
-			case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
-			case MLX5_PORT_CHANGE_SUBTYPE_GUID:
-			case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
-			case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
-				if (dev->event)
-					dev->event(dev, port_subtype_event(eqe->sub_type),
-						   (unsigned long)port);
-				break;
-			default:
-				mlx5_core_warn(dev, "Port event with unrecognized subtype: port %d, sub_type %d\n",
-					       port, eqe->sub_type);
-			}
-			break;
-
-		case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
-			mlx5_port_module_event(dev, eqe);
-			break;
-
-		case MLX5_EVENT_TYPE_TEMP_WARN_EVENT:
-			mlx5_temp_warning_event(dev, eqe);
-			break;
-
-		case MLX5_EVENT_TYPE_GENERAL_EVENT:
-			general_event_handler(dev, eqe);
-			break;
-
-		default:
-			mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n",
-				       eqe->type, eq->eqn);
-			break;
-		}
-
 		if (likely(eqe->type < MLX5_EVENT_TYPE_MAX))
 			atomic_notifier_call_chain(&eqt->nh[eqe->type], eqe->type, eqe);
 		else
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/events.c b/drivers/net/ethernet/mellanox/mlx5/core/events.c
new file mode 100644
index 000000000000..d3ab86bd394b
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/events.c
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2018 Mellanox Technologies
+
+#include <linux/mlx5/driver.h>
+#include "mlx5_core.h"
+#include "lib/eq.h"
+#include "lib/mlx5.h"
+
+struct mlx5_events {
+	struct mlx5_nb        nb;
+	struct mlx5_core_dev *dev;
+
+	/* port module evetns stats */
+	struct mlx5_pme_stats pme_stats;
+};
+
+static const char *eqe_type_str(u8 type)
+{
+	switch (type) {
+	case MLX5_EVENT_TYPE_COMP:
+		return "MLX5_EVENT_TYPE_COMP";
+	case MLX5_EVENT_TYPE_PATH_MIG:
+		return "MLX5_EVENT_TYPE_PATH_MIG";
+	case MLX5_EVENT_TYPE_COMM_EST:
+		return "MLX5_EVENT_TYPE_COMM_EST";
+	case MLX5_EVENT_TYPE_SQ_DRAINED:
+		return "MLX5_EVENT_TYPE_SQ_DRAINED";
+	case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+		return "MLX5_EVENT_TYPE_SRQ_LAST_WQE";
+	case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
+		return "MLX5_EVENT_TYPE_SRQ_RQ_LIMIT";
+	case MLX5_EVENT_TYPE_CQ_ERROR:
+		return "MLX5_EVENT_TYPE_CQ_ERROR";
+	case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+		return "MLX5_EVENT_TYPE_WQ_CATAS_ERROR";
+	case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+		return "MLX5_EVENT_TYPE_PATH_MIG_FAILED";
+	case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+		return "MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR";
+	case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+		return "MLX5_EVENT_TYPE_WQ_ACCESS_ERROR";
+	case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
+		return "MLX5_EVENT_TYPE_SRQ_CATAS_ERROR";
+	case MLX5_EVENT_TYPE_INTERNAL_ERROR:
+		return "MLX5_EVENT_TYPE_INTERNAL_ERROR";
+	case MLX5_EVENT_TYPE_PORT_CHANGE:
+		return "MLX5_EVENT_TYPE_PORT_CHANGE";
+	case MLX5_EVENT_TYPE_GPIO_EVENT:
+		return "MLX5_EVENT_TYPE_GPIO_EVENT";
+	case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
+		return "MLX5_EVENT_TYPE_PORT_MODULE_EVENT";
+	case MLX5_EVENT_TYPE_TEMP_WARN_EVENT:
+		return "MLX5_EVENT_TYPE_TEMP_WARN_EVENT";
+	case MLX5_EVENT_TYPE_REMOTE_CONFIG:
+		return "MLX5_EVENT_TYPE_REMOTE_CONFIG";
+	case MLX5_EVENT_TYPE_DB_BF_CONGESTION:
+		return "MLX5_EVENT_TYPE_DB_BF_CONGESTION";
+	case MLX5_EVENT_TYPE_STALL_EVENT:
+		return "MLX5_EVENT_TYPE_STALL_EVENT";
+	case MLX5_EVENT_TYPE_CMD:
+		return "MLX5_EVENT_TYPE_CMD";
+	case MLX5_EVENT_TYPE_PAGE_REQUEST:
+		return "MLX5_EVENT_TYPE_PAGE_REQUEST";
+	case MLX5_EVENT_TYPE_PAGE_FAULT:
+		return "MLX5_EVENT_TYPE_PAGE_FAULT";
+	case MLX5_EVENT_TYPE_PPS_EVENT:
+		return "MLX5_EVENT_TYPE_PPS_EVENT";
+	case MLX5_EVENT_TYPE_NIC_VPORT_CHANGE:
+		return "MLX5_EVENT_TYPE_NIC_VPORT_CHANGE";
+	case MLX5_EVENT_TYPE_FPGA_ERROR:
+		return "MLX5_EVENT_TYPE_FPGA_ERROR";
+	case MLX5_EVENT_TYPE_FPGA_QP_ERROR:
+		return "MLX5_EVENT_TYPE_FPGA_QP_ERROR";
+	case MLX5_EVENT_TYPE_GENERAL_EVENT:
+		return "MLX5_EVENT_TYPE_GENERAL_EVENT";
+	case MLX5_EVENT_TYPE_DEVICE_TRACER:
+		return "MLX5_EVENT_TYPE_DEVICE_TRACER";
+	default:
+		return "Unrecognized event";
+	}
+}
+
+static enum mlx5_dev_event port_subtype2dev(u8 subtype)
+{
+	switch (subtype) {
+	case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
+		return MLX5_DEV_EVENT_PORT_DOWN;
+	case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
+		return MLX5_DEV_EVENT_PORT_UP;
+	case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
+		return MLX5_DEV_EVENT_PORT_INITIALIZED;
+	case MLX5_PORT_CHANGE_SUBTYPE_LID:
+		return MLX5_DEV_EVENT_LID_CHANGE;
+	case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
+		return MLX5_DEV_EVENT_PKEY_CHANGE;
+	case MLX5_PORT_CHANGE_SUBTYPE_GUID:
+		return MLX5_DEV_EVENT_GUID_CHANGE;
+	case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
+		return MLX5_DEV_EVENT_CLIENT_REREG;
+	}
+	return -1;
+}
+
+static void temp_warning_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe)
+{
+	u64 value_lsb;
+	u64 value_msb;
+
+	value_lsb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_lsb);
+	value_msb = be64_to_cpu(eqe->data.temp_warning.sensor_warning_msb);
+
+	mlx5_core_warn(dev,
+		       "High temperature on sensors with bit set %llx %llx",
+		       value_msb, value_lsb);
+}
+
+static const char *mlx5_pme_status[MLX5_MODULE_STATUS_NUM] = {
+	"Cable plugged",   /* MLX5_MODULE_STATUS_PLUGGED    = 0x1 */
+	"Cable unplugged", /* MLX5_MODULE_STATUS_UNPLUGGED  = 0x2 */
+	"Cable error",     /* MLX5_MODULE_STATUS_ERROR      = 0x3 */
+};
+
+static const char *mlx5_pme_error[MLX5_MODULE_EVENT_ERROR_NUM] = {
+	"Power budget exceeded",
+	"Long Range for non MLNX cable",
+	"Bus stuck(I2C or data shorted)",
+	"No EEPROM/retry timeout",
+	"Enforce part number list",
+	"Unknown identifier",
+	"High Temperature",
+	"Bad or shorted cable/module",
+	"Unknown status",
+};
+
+static void port_module_event(struct mlx5_events *events, struct mlx5_eqe *eqe)
+{
+	enum port_module_event_status_type module_status;
+	enum port_module_event_error_type error_type;
+	struct mlx5_eqe_port_module *module_event_eqe;
+	struct mlx5_core_dev *dev = events->dev;
+	u8 module_num;
+
+	module_event_eqe = &eqe->data.port_module;
+	module_num = module_event_eqe->module;
+	module_status = module_event_eqe->module_status &
+			PORT_MODULE_EVENT_MODULE_STATUS_MASK;
+	error_type = module_event_eqe->error_type &
+		     PORT_MODULE_EVENT_ERROR_TYPE_MASK;
+
+	if (module_status < MLX5_MODULE_STATUS_ERROR) {
+		events->pme_stats.status_counters[module_status - 1]++;
+	} else if (module_status == MLX5_MODULE_STATUS_ERROR) {
+		if (error_type >= MLX5_MODULE_EVENT_ERROR_UNKNOWN)
+			/* Unknown error type */
+			error_type = MLX5_MODULE_EVENT_ERROR_UNKNOWN;
+		events->pme_stats.error_counters[error_type]++;
+	}
+
+	if (!printk_ratelimit())
+		return;
+
+	if (module_status < MLX5_MODULE_STATUS_ERROR)
+		mlx5_core_info(dev,
+			       "Port module event: module %u, %s\n",
+			       module_num, mlx5_pme_status[module_status - 1]);
+
+	else if (module_status == MLX5_MODULE_STATUS_ERROR)
+		mlx5_core_info(dev,
+			       "Port module event[error]: module %u, %s, %s\n",
+			       module_num, mlx5_pme_status[module_status - 1],
+			       mlx5_pme_error[error_type]);
+}
+
+void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats)
+{
+	*stats = dev->priv.events->pme_stats;
+}
+
+/* Event handler for the low level mlx5_core driver.
+ * This handler will process/filter _some_ events and sometimes dispatch
+ * the equivalent mlx5_dev_event to the HCA interfaces (mlx5_ib and mlx5e)
+ *
+ * Other Major feature specific events such as
+ * clock/eswitch/fpga/FW trace and many others, are handled elsewhere, with
+ * separate notifiers callbacks, specifically by those mlx5 components.
+ */
+static int events_notifier(struct notifier_block *nb,
+			   unsigned long type, void *data)
+{
+	bool dev_event_dispatch = false;
+	enum mlx5_dev_event dev_event;
+	unsigned long dev_event_data;
+
+	struct mlx5_eqe *eqe = data;
+	struct mlx5_events *events;
+	struct mlx5_core_dev *dev;
+	u8 port;
+
+	events = mlx5_nb_cof(nb, struct mlx5_events, nb);
+	dev = events->dev;
+
+	mlx5_core_dbg(dev, "Async eqe type %s, subtype (%d)\n",
+		      eqe_type_str(eqe->type), eqe->sub_type);
+	switch (eqe->type) {
+	case MLX5_EVENT_TYPE_PORT_CHANGE:
+		port = (eqe->data.port.port >> 4) & 0xf;
+		switch (eqe->sub_type) {
+		case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
+		case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
+		case MLX5_PORT_CHANGE_SUBTYPE_LID:
+		case MLX5_PORT_CHANGE_SUBTYPE_PKEY:
+		case MLX5_PORT_CHANGE_SUBTYPE_GUID:
+		case MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG:
+		case MLX5_PORT_CHANGE_SUBTYPE_INITIALIZED:
+			dev_event = port_subtype2dev(eqe->sub_type);
+			dev_event_data = (unsigned long)port;
+			dev_event_dispatch = true;
+			break;
+		default:
+			mlx5_core_warn(dev, "Port event with unrecognized subtype: port %d, sub_type %d\n",
+				       port, eqe->sub_type);
+		}
+		break;
+	case MLX5_EVENT_TYPE_GENERAL_EVENT:
+		switch (eqe->sub_type) {
+		case MLX5_GENERAL_SUBTYPE_DELAY_DROP_TIMEOUT:
+			dev_event = MLX5_DEV_EVENT_DELAY_DROP_TIMEOUT;
+			dev_event_data = 0;
+			dev_event_dispatch = true;
+			break;
+		default:
+			mlx5_core_dbg(dev, "General event with unrecognized subtype: sub_type %d\n",
+				      eqe->sub_type);
+		}
+		break;
+
+	case MLX5_EVENT_TYPE_PORT_MODULE_EVENT:
+		port_module_event(events, eqe);
+		break;
+	case MLX5_EVENT_TYPE_TEMP_WARN_EVENT:
+		temp_warning_event(dev, eqe);
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	if (dev->event && dev_event_dispatch)
+		dev->event(dev, dev_event, dev_event_data);
+
+	return NOTIFY_OK;
+}
+
+int mlx5_events_init(struct mlx5_core_dev *dev)
+{
+	struct mlx5_events *events = kzalloc(sizeof(*events), GFP_KERNEL);
+
+	if (!events)
+		return -ENOMEM;
+
+	events->dev = dev;
+	dev->priv.events = events;
+	return 0;
+}
+
+void mlx5_events_cleanup(struct mlx5_core_dev *dev)
+{
+	kvfree(dev->priv.events);
+}
+
+void mlx5_events_start(struct mlx5_core_dev *dev)
+{
+	struct mlx5_events *events = dev->priv.events;
+
+	MLX5_NB_INIT(&events->nb, events_notifier, NOTIFY_ANY);
+	mlx5_eq_notifier_register(dev, &events->nb);
+}
+
+void mlx5_events_stop(struct mlx5_core_dev *dev)
+{
+	struct mlx5_events *events = dev->priv.events;
+
+	mlx5_eq_notifier_unregister(dev, &events->nb);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
index 7550b1cc8c6a..23317e328b0b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h
@@ -33,6 +33,8 @@
 #ifndef __LIB_MLX5_H__
 #define __LIB_MLX5_H__
 
+#include "mlx5_core.h"
+
 void mlx5_init_reserved_gids(struct mlx5_core_dev *dev);
 void mlx5_cleanup_reserved_gids(struct mlx5_core_dev *dev);
 int  mlx5_core_reserve_gids(struct mlx5_core_dev *dev, unsigned int count);
@@ -40,4 +42,36 @@ void mlx5_core_unreserve_gids(struct mlx5_core_dev *dev, unsigned int count);
 int  mlx5_core_reserved_gid_alloc(struct mlx5_core_dev *dev, int *gid_index);
 void mlx5_core_reserved_gid_free(struct mlx5_core_dev *dev, int gid_index);
 
+/* TODO move to lib/events.h */
+
+#define PORT_MODULE_EVENT_MODULE_STATUS_MASK 0xF
+#define PORT_MODULE_EVENT_ERROR_TYPE_MASK    0xF
+
+enum port_module_event_status_type {
+	MLX5_MODULE_STATUS_PLUGGED   = 0x1,
+	MLX5_MODULE_STATUS_UNPLUGGED = 0x2,
+	MLX5_MODULE_STATUS_ERROR     = 0x3,
+	MLX5_MODULE_STATUS_NUM       = 0x3,
+};
+
+enum  port_module_event_error_type {
+	MLX5_MODULE_EVENT_ERROR_POWER_BUDGET_EXCEEDED,
+	MLX5_MODULE_EVENT_ERROR_LONG_RANGE_FOR_NON_MLNX_CABLE_MODULE,
+	MLX5_MODULE_EVENT_ERROR_BUS_STUCK,
+	MLX5_MODULE_EVENT_ERROR_NO_EEPROM_RETRY_TIMEOUT,
+	MLX5_MODULE_EVENT_ERROR_ENFORCE_PART_NUMBER_LIST,
+	MLX5_MODULE_EVENT_ERROR_UNKNOWN_IDENTIFIER,
+	MLX5_MODULE_EVENT_ERROR_HIGH_TEMPERATURE,
+	MLX5_MODULE_EVENT_ERROR_BAD_CABLE,
+	MLX5_MODULE_EVENT_ERROR_UNKNOWN,
+	MLX5_MODULE_EVENT_ERROR_NUM,
+};
+
+struct mlx5_pme_stats {
+	u64 status_counters[MLX5_MODULE_STATUS_NUM];
+	u64 error_counters[MLX5_MODULE_EVENT_ERROR_NUM];
+};
+
+void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats);
+
 #endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 9e4cd2757ea8..e56278ead4eb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -735,10 +735,16 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
 		goto out;
 	}
 
+	err = mlx5_events_init(dev);
+	if (err) {
+		dev_err(&pdev->dev, "failed to initialize events\n");
+		goto err_eq_cleanup;
+	}
+
 	err = mlx5_cq_debugfs_init(dev);
 	if (err) {
 		dev_err(&pdev->dev, "failed to initialize cq debugfs\n");
-		goto err_eq_cleanup;
+		goto err_events_cleanup;
 	}
 
 	mlx5_init_qp_table(dev);
@@ -801,7 +807,8 @@ static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
 	mlx5_cleanup_srq_table(dev);
 	mlx5_cleanup_qp_table(dev);
 	mlx5_cq_debugfs_cleanup(dev);
-
+err_events_cleanup:
+	mlx5_events_cleanup(dev);
 err_eq_cleanup:
 	mlx5_eq_table_cleanup(dev);
 
@@ -824,6 +831,7 @@ static void mlx5_cleanup_once(struct mlx5_core_dev *dev)
 	mlx5_cleanup_srq_table(dev);
 	mlx5_cleanup_qp_table(dev);
 	mlx5_cq_debugfs_cleanup(dev);
+	mlx5_events_cleanup(dev);
 	mlx5_eq_table_cleanup(dev);
 }
 
@@ -947,6 +955,7 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 		goto err_get_uars;
 	}
 
+	mlx5_events_start(dev);
 	mlx5_pagealloc_start(dev);
 
 	err = mlx5_eq_table_create(dev);
@@ -1036,6 +1045,7 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 
 err_eq_table:
 	mlx5_pagealloc_stop(dev);
+	mlx5_events_stop(dev);
 	mlx5_put_uars_page(dev, priv->uar);
 
 err_get_uars:
@@ -1095,8 +1105,8 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
 	mlx5_fw_tracer_cleanup(dev->tracer);
 	mlx5_eq_table_destroy(dev);
 	mlx5_pagealloc_stop(dev);
+	mlx5_events_stop(dev);
 	mlx5_put_uars_page(dev, priv->uar);
-
 	if (cleanup)
 		mlx5_cleanup_once(dev);
 	mlx5_stop_health_poll(dev, cleanup);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 5dd453e47a04..c70bd94e18d6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -105,7 +105,6 @@ int mlx5_cmd_fast_teardown_hca(struct mlx5_core_dev *dev);
 
 void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
 		     unsigned long param);
-void mlx5_port_module_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe);
 void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force);
 void mlx5_disable_device(struct mlx5_core_dev *dev);
 void mlx5_recover_device(struct mlx5_core_dev *dev);
@@ -141,6 +140,11 @@ int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
 void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev);
 void mlx5_lag_remove(struct mlx5_core_dev *dev);
 
+int mlx5_events_init(struct mlx5_core_dev *dev);
+void mlx5_events_cleanup(struct mlx5_core_dev *dev);
+void mlx5_events_start(struct mlx5_core_dev *dev);
+void mlx5_events_stop(struct mlx5_core_dev *dev);
+
 void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv);
 void mlx5_remove_device(struct mlx5_interface *intf, struct mlx5_priv *priv);
 void mlx5_attach_device(struct mlx5_core_dev *dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c
index 31a9cbd85689..2b82f35f4c35 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c
@@ -915,63 +915,6 @@ void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
 	*enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
 }
 
-static const char *mlx5_pme_status[MLX5_MODULE_STATUS_NUM] = {
-	"Cable plugged",   /* MLX5_MODULE_STATUS_PLUGGED    = 0x1 */
-	"Cable unplugged", /* MLX5_MODULE_STATUS_UNPLUGGED  = 0x2 */
-	"Cable error",     /* MLX5_MODULE_STATUS_ERROR      = 0x3 */
-};
-
-static const char *mlx5_pme_error[MLX5_MODULE_EVENT_ERROR_NUM] = {
-	"Power budget exceeded",
-	"Long Range for non MLNX cable",
-	"Bus stuck(I2C or data shorted)",
-	"No EEPROM/retry timeout",
-	"Enforce part number list",
-	"Unknown identifier",
-	"High Temperature",
-	"Bad or shorted cable/module",
-	"Unknown status",
-};
-
-void mlx5_port_module_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe)
-{
-	enum port_module_event_status_type module_status;
-	enum port_module_event_error_type error_type;
-	struct mlx5_eqe_port_module *module_event_eqe;
-	struct mlx5_priv *priv = &dev->priv;
-	u8 module_num;
-
-	module_event_eqe = &eqe->data.port_module;
-	module_num = module_event_eqe->module;
-	module_status = module_event_eqe->module_status &
-			PORT_MODULE_EVENT_MODULE_STATUS_MASK;
-	error_type = module_event_eqe->error_type &
-		     PORT_MODULE_EVENT_ERROR_TYPE_MASK;
-
-	if (module_status < MLX5_MODULE_STATUS_ERROR) {
-		priv->pme_stats.status_counters[module_status - 1]++;
-	} else if (module_status == MLX5_MODULE_STATUS_ERROR) {
-		if (error_type >= MLX5_MODULE_EVENT_ERROR_UNKNOWN)
-			/* Unknown error type */
-			error_type = MLX5_MODULE_EVENT_ERROR_UNKNOWN;
-		priv->pme_stats.error_counters[error_type]++;
-	}
-
-	if (!printk_ratelimit())
-		return;
-
-	if (module_status < MLX5_MODULE_STATUS_ERROR)
-		mlx5_core_info(dev,
-			       "Port module event: module %u, %s\n",
-			       module_num, mlx5_pme_status[module_status - 1]);
-
-	else if (module_status == MLX5_MODULE_STATUS_ERROR)
-		mlx5_core_info(dev,
-			       "Port module event[error]: module %u, %s, %s\n",
-			       module_num, mlx5_pme_status[module_status - 1],
-			       mlx5_pme_error[error_type]);
-}
-
 int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
 {
 	u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index afba0864f45c..ba64ecf72478 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -514,6 +514,7 @@ struct mlx5_fc_stats {
 	unsigned long sampling_interval; /* jiffies */
 };
 
+struct mlx5_events;
 struct mlx5_mpfs;
 struct mlx5_eswitch;
 struct mlx5_lag;
@@ -540,31 +541,6 @@ struct mlx5_rl_table {
 	struct mlx5_rl_entry   *rl_entry;
 };
 
-enum port_module_event_status_type {
-	MLX5_MODULE_STATUS_PLUGGED   = 0x1,
-	MLX5_MODULE_STATUS_UNPLUGGED = 0x2,
-	MLX5_MODULE_STATUS_ERROR     = 0x3,
-	MLX5_MODULE_STATUS_NUM       = 0x3,
-};
-
-enum  port_module_event_error_type {
-	MLX5_MODULE_EVENT_ERROR_POWER_BUDGET_EXCEEDED,
-	MLX5_MODULE_EVENT_ERROR_LONG_RANGE_FOR_NON_MLNX_CABLE_MODULE,
-	MLX5_MODULE_EVENT_ERROR_BUS_STUCK,
-	MLX5_MODULE_EVENT_ERROR_NO_EEPROM_RETRY_TIMEOUT,
-	MLX5_MODULE_EVENT_ERROR_ENFORCE_PART_NUMBER_LIST,
-	MLX5_MODULE_EVENT_ERROR_UNKNOWN_IDENTIFIER,
-	MLX5_MODULE_EVENT_ERROR_HIGH_TEMPERATURE,
-	MLX5_MODULE_EVENT_ERROR_BAD_CABLE,
-	MLX5_MODULE_EVENT_ERROR_UNKNOWN,
-	MLX5_MODULE_EVENT_ERROR_NUM,
-};
-
-struct mlx5_port_module_event_stats {
-	u64 status_counters[MLX5_MODULE_STATUS_NUM];
-	u64 error_counters[MLX5_MODULE_EVENT_ERROR_NUM];
-};
-
 struct mlx5_priv {
 	char			name[MLX5_MAX_NAME_LEN];
 	struct mlx5_eq_table	*eq_table;
@@ -614,6 +590,7 @@ struct mlx5_priv {
 
 	struct list_head	waiting_events_list;
 	bool			is_accum_events;
+	struct mlx5_events     *events;
 
 	struct mlx5_flow_steering *steering;
 	struct mlx5_mpfs        *mpfs;
@@ -624,8 +601,6 @@ struct mlx5_priv {
 	struct mlx5_fc_stats		fc_stats;
 	struct mlx5_rl_table            rl_table;
 
-	struct mlx5_port_module_event_stats  pme_stats;
-
 	struct mlx5_bfreg_data		bfregs;
 	struct mlx5_uars_page	       *uar;
 };
diff --git a/include/linux/mlx5/port.h b/include/linux/mlx5/port.h
index 34aed6032f86..bf4bc01ffb0c 100644
--- a/include/linux/mlx5/port.h
+++ b/include/linux/mlx5/port.h
@@ -107,9 +107,6 @@ enum mlx5e_connector_type {
 
 #define MLX5E_PROT_MASK(link_mode) (1 << link_mode)
 
-#define PORT_MODULE_EVENT_MODULE_STATUS_MASK 0xF
-#define PORT_MODULE_EVENT_ERROR_TYPE_MASK         0xF
-
 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps);
 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
 			 int ptys_size, int proto_mask, u8 local_port);
-- 
2.19.1

^ permalink raw reply related

* Re: [PATCH net] MAINTAINERS: add myself as co-maintainer for r8169
From: David Miller @ 2018-11-20 22:23 UTC (permalink / raw)
  To: hkallweit1; +Cc: nic_swsd, netdev
In-Reply-To: <90669d40-3b14-a306-572e-228fd93b1b4f@gmail.com>

From: Heiner Kallweit <hkallweit1@gmail.com>
Date: Tue, 20 Nov 2018 21:22:50 +0100

> Meanwhile I know the driver quite well and I refactored bigger parts
> of it. As a result people contact me already with r8169 questions.
> Therefore I'd volunteer to become co-maintainer of the driver also
> officially.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>

I honestly thought we had done this already :-)

Applied, thanks.

^ permalink raw reply

* Re: [PATCH v3 0/5] phy: core: rework phy_set_mode to accept phy mode and submode
From: Kishon Vijay Abraham I @ 2018-11-21  8:55 UTC (permalink / raw)
  To: Grygorii Strashko, David S. Miller, Antoine Tenart,
	Quentin Schulz, Russell King - ARM Linux, Maxime Chevallier
  Cc: netdev, Sekhar Nori, linux-kernel, linux-arm-kernel,
	Tony Lindgren, linux-amlogic, linux-mediatek, Alexandre Belloni,
	Vivek Gautam, Maxime Ripard, Chen-Yu Tsai, Carlo Caione,
	Chunfeng Yun, Matthias Brugger, Manu Gautam
In-Reply-To: <20181120012424.11802-1-grygorii.strashko@ti.com>



On 20/11/18 6:54 AM, Grygorii Strashko wrote:
> Hi Kishon, All,
> 
> Thank you for your review.
> I've not added "Tested-by"/"Acked-by" tags due to code changes in v3.

merged after adding the required ACKs.

Thanks
Kishon
> 
> As was discussed in [1] I'm posting series which introduces rework of
> phy_set_mode to accept phy mode and submode. I've dropped TI specific patches as
> this change is pretty big by itself.
> 
> Patch 1 is cumulative change which refactors PHY framework code to
> support dual level PHYs mode configuration - PHY mode and PHY submode. It
> extends .set_mode() callback to support additional parameter "int submode"
> and converts all corresponding PHY drivers to support new .set_mode()
> callback declaration.
> The new extended PHY API
>  int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode)
> is introduced to support dual level PHYs mode configuration and existing
> phy_set_mode() API is converted to macros, so PHY framework consumers do
> not need to be changed (~21 matches).
> 
> Patches 2-4: Add new PHY's mode to be used by Ethernet PHY interface drivers or
> multipurpose PHYs like serdes and convert ocelot-serdes and mvebu-cp110-comphy
> PHY drivers to use recently introduced PHY_MODE_ETHERNET and phy_set_mode_ext().
> 
> Patch 5 - removes unused, ethernet specific phy modes from enum phy_mode.
> 
> Testing:
>  - series tested on TI am335x/am437x/am5(dra7) paltforms.
>  - other driver build tested.
> 
> changes in v3:
> - mux tables for PHY ocelot-serdes driver updated to store PHY mode and submode
> - mux tables for PHY mvebu-cp110-comphy driver updated to store PHY mode
>   and submode
> changes in v2:
> - marvell PHY and net drivers updated as recommended by Russell King
> 
> v2: https://lkml.org/lkml/2018/11/10/220
> v1: https://lkml.org/lkml/2018/11/8/260
> 
> [1] https://lkml.org/lkml/2018/10/25/366
> 
> Grygorii Strashko (5):
>   phy: core: rework phy_set_mode to accept phy mode and submode
>   phy: core: add PHY_MODE_ETHERNET
>   phy: ocelot-serdes: convert to use eth phy mode and submode
>   phy: mvebu-cp110-comphy: convert to use eth phy mode and submode
>   phy: core: clean up unused ethernet specific phy modes
> 
>  drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 19 +----
>  drivers/net/ethernet/mscc/ocelot.c              |  9 +--
>  drivers/phy/allwinner/phy-sun4i-usb.c           |  3 +-
>  drivers/phy/amlogic/phy-meson-gxl-usb2.c        |  5 +-
>  drivers/phy/amlogic/phy-meson-gxl-usb3.c        |  5 +-
>  drivers/phy/marvell/phy-mvebu-cp110-comphy.c    | 93 ++++++++++++++-----------
>  drivers/phy/mediatek/phy-mtk-tphy.c             |  2 +-
>  drivers/phy/mediatek/phy-mtk-xsphy.c            |  2 +-
>  drivers/phy/mscc/phy-ocelot-serdes.c            | 24 +++++--
>  drivers/phy/phy-core.c                          |  6 +-
>  drivers/phy/qualcomm/phy-qcom-qmp.c             |  3 +-
>  drivers/phy/qualcomm/phy-qcom-qusb2.c           |  3 +-
>  drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c    |  3 +-
>  drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c    |  3 +-
>  drivers/phy/qualcomm/phy-qcom-usb-hs.c          |  3 +-
>  drivers/phy/ti/phy-da8xx-usb.c                  |  3 +-
>  drivers/phy/ti/phy-tusb1210.c                   |  2 +-
>  include/linux/phy/phy.h                         | 18 +++--
>  18 files changed, 111 insertions(+), 95 deletions(-)
> 

^ permalink raw reply

* Re: [PATCH iproute2 22/22] rdma: make local functions static
From: David Ahern @ 2018-11-20 22:26 UTC (permalink / raw)
  To: Stephen Hemminger, netdev
In-Reply-To: <20181115223640.411-23-stephen@networkplumber.org>

On 11/15/18 3:36 PM, Stephen Hemminger wrote:
> Several functions only used inside utils.c
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  rdma/rdma.h  | 11 -----------
>  rdma/utils.c | 12 ++++++------
>  2 files changed, 6 insertions(+), 17 deletions(-)
> 

this patch breaks builds for me on Debian stretch:

rdma
    CC       rdma.o
    CC       utils.o
    CC       dev.o
    CC       link.o
dev.c: In function 'dev_set_name':
dev.c:248:6: warning: implicit declaration of function 'rd_no_arg'
[-Wimplicit-function-declaration]
  if (rd_no_arg(rd)) {
      ^~~~~~~~~
dev.c:256:55: warning: implicit declaration of function 'rd_argv'
[-Wimplicit-function-declaration]
  mnl_attr_put_strz(rd->nlh, RDMA_NLDEV_ATTR_DEV_NAME, rd_argv(rd));
                                                       ^~~~~~~
dev.c:256:55: warning: passing argument 3 of 'mnl_attr_put_strz' makes
pointer from integer without a cast [-Wint-conversion]
In file included from rdma.h:19:0,
                 from dev.c:12:
/usr/include/libmnl/libmnl.h:103:13: note: expected 'const char *' but
argument is of type 'int'
 extern void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type,
const char *data);


Reverting the patch fixes it.

^ permalink raw reply

* Re: [PATCH net v2] net/sched: act_police: fix race condition on state variables
From: Cong Wang @ 2018-11-20 22:29 UTC (permalink / raw)
  To: Davide Caratti
  Cc: Eric Dumazet, Jamal Hadi Salim, Jiri Pirko, David Miller,
	Linux Kernel Network Developers, Ivan Vecera
In-Reply-To: <541a3b91af953326fa8f8fe046f0c284274377ff.1542748323.git.dcaratti@redhat.com>

On Tue, Nov 20, 2018 at 1:19 PM Davide Caratti <dcaratti@redhat.com> wrote:
>
> after 'police' configuration parameters were converted to use RCU instead
> of spinlock, the state variables used to compute the traffic rate (namely
> 'tcfp_toks', 'tcfp_ptoks' and 'tcfp_t_c') are erroneously read/updated in
> the traffic path without any protection.
>
> Use a dedicated spinlock to avoid race conditions on these variables, and
> ensure proper cache-line alignment. In this way, 'police' is still faster
> than what we observed when 'tcf_lock' was used in the traffic path _ i.e.
> reverting commit 2d550dbad83c ("net/sched: act_police: don't use spinlock
> in the data path"). Moreover, we preserve the throughput improvement that
> was obtained after 'police' started using per-cpu counters, when 'avrate'
> is used instead of 'rate'.
>
> Changes since v1 (thanks to Eric Dumazet):
> - call ktime_get_ns() before acquiring the lock in the traffic path
> - use a dedicated spinlock instead of tcf_lock

Do you initialize this dedicated spinlock?

^ permalink raw reply

* Re: [PATCH v2 3/4] libbpf: require size hint in bpf_prog_test_run
From: Alexei Starovoitov @ 2018-11-20 22:51 UTC (permalink / raw)
  To: Lorenz Bauer
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, linux-api, Y Song
In-Reply-To: <CACAyw993bwvo5obLgvWXbG_S6xRHXKZ9M1vX5=y1RB-R24LYdQ@mail.gmail.com>

On Tue, Nov 20, 2018 at 07:43:57PM +0000, Lorenz Bauer wrote:
> On Tue, 20 Nov 2018 at 19:18, Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Tue, Nov 20, 2018 at 03:43:05PM +0000, Lorenz Bauer wrote:
> > > Require size_out to be non-NULL if data_out is given. This prevents
> > > accidental overwriting of process memory after the output buffer.
> > >
> > > Adjust callers of bpf_prog_test_run to this behaviour.
> > >
> > > Signed-off-by: Lorenz Bauer <lmb@cloudflare.com>
> > > ---
> > >  tools/lib/bpf/bpf.c                      |  7 ++++++-
> > >  tools/testing/selftests/bpf/test_progs.c | 10 ++++++++++
> > >  2 files changed, 16 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> > > index 961e1b9fc592..1a835ff27486 100644
> > > --- a/tools/lib/bpf/bpf.c
> > > +++ b/tools/lib/bpf/bpf.c
> > > @@ -407,15 +407,20 @@ int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,
> > >       union bpf_attr attr;
> > >       int ret;
> > >
> > > +     if (data_out && !size_out)
> > > +             return -EINVAL;
> > > +
> > >       bzero(&attr, sizeof(attr));
> > >       attr.test.prog_fd = prog_fd;
> > >       attr.test.data_in = ptr_to_u64(data);
> > >       attr.test.data_out = ptr_to_u64(data_out);
> > >       attr.test.data_size_in = size;
> > > +     if (data_out)
> > > +             attr.test.data_size_out = *size_out;
> > >       attr.test.repeat = repeat;
> > >
> > >       ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
> > > -     if (size_out)
> > > +     if (data_out)
> > >               *size_out = attr.test.data_size_out;
> > >       if (retval)
> > >               *retval = attr.test.retval;
> > > diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
> > > index c1e688f61061..299938603cb6 100644
> > > --- a/tools/testing/selftests/bpf/test_progs.c
> > > +++ b/tools/testing/selftests/bpf/test_progs.c
> > > @@ -150,6 +150,7 @@ static void test_xdp(void)
> > >       bpf_map_update_elem(map_fd, &key4, &value4, 0);
> > >       bpf_map_update_elem(map_fd, &key6, &value6, 0);
> > >
> > > +     size = sizeof(buf);
> > >       err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
> > >                               buf, &size, &retval, &duration);
> > >
> > > @@ -158,6 +159,7 @@ static void test_xdp(void)
> > >             "err %d errno %d retval %d size %d\n",
> > >             err, errno, retval, size);
> > >
> > > +     size = sizeof(buf);
> > >       err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6),
> > >                               buf, &size, &retval, &duration);
> >
> > This will surely break existing bpf_prog_test_run users.
> > Like it will break our testing framework.
> > we can fix out stuff and libbpf is a user space library, but I don't
> > think that this is the case to invoke such pain.
> > libbpf's bpf_prog_test_run() should be a simple wrapper on top of syscall.
> > I don't think it should be making such restrictions on api.
> >
> > btw patch 1 looks good to me.
> >
> 
> What if I add bpf_prog_test_run_safe or similar, with the behaviour
> proposed in the patch?
> Makes sense that you don't want to break existing users of libbpf
> outside the kernel, OTOH
> user space really should specify the output buffer length (or be given
> the choice).

+     if (data_out && !size_out)
+             return -EINVAL;
+
+     if (data_out)
+             attr.test.data_size_out = *size_out;

this is actually worse than I thought, since it will cause sporadic
failures in the test frameworks that don't init size_out.
Like test_progs.c will be randomly passing/failing depending
on the state of uninit bytes in the stack.

Also consider that during bpf uconf folks have requested to extend
prog_test_run with __sk_buff in/out argument, so no only packet data,
but skb related fields can be tested as well.
I think that was a valid request and prog_test_run should be extended.
So soon such libbpf's bpf_prog_test_run_safe() will not be enough.
I think it's the best to use _xattr approach we did for map_create
and prog_load.
This new bpf_prog_test_run_xattr() will be able to do the check
you're proposing:
+     if (data_out && !size_out)
+             return -EINVAL;
+
+     if (data_out)
+             attr.test.data_size_out = *size_out;
it can also check that both size and size_out are sane
with similar check to kernel:
if (size < ETH_HLEN || size > PAGE_SIZE - headroom - tailroom);

and will be extendable in the near future with __sk_buff in/out.

^ permalink raw reply

* Re: [PATCH nvme-cli v2 15/14] nvme: Add TCP transport
From: Sagi Grimberg @ 2018-11-20 22:56 UTC (permalink / raw)
  To: Arend van Spriel, linux-nvme
  Cc: linux-block, netdev, David S. Miller, Keith Busch,
	Christoph Hellwig
In-Reply-To: <e04487c8-a4a8-bd4f-2ec7-8f67f0f1a49e@broadcom.com>


>> @@ -703,11 +704,13 @@ retry:
>>          /* we can safely ignore the rest of the entries */
>>          break;
>>      case NVMF_TRTYPE_RDMA:
>> +    case NVMF_TRTYPE_TCP:
>>          switch (e->adrfam) {
>>          case NVMF_ADDR_FAMILY_IP4:
>>          case NVMF_ADDR_FAMILY_IP6:
>>              /* FALLTHRU */
>> -            len = sprintf(p, ",transport=rdma");
>> +            len = sprintf(p, ",transport=%s",
>> +                e->trtype == NVMF_TRTYPE_RDMA ? "rdma" : "tcp");
> 
> So why not just use the trtypes array above?

We can use that...

^ permalink raw reply

* Re: [iproute2-next PATCH v3 2/2] man: tc-flower: Add explanation for range option
From: David Ahern @ 2018-11-20 22:56 UTC (permalink / raw)
  To: Amritha Nambiar, stephen, netdev
  Cc: jakub.kicinski, sridhar.samudrala, jhs, xiyou.wangcong, jiri
In-Reply-To: <154232971889.10668.16009642596079446767.stgit@anamhost.jf.intel.com>

On 11/15/18 5:55 PM, Amritha Nambiar wrote:
> Add details explaining filtering based on port ranges.
> 
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> ---
>  man/man8/tc-flower.8 |   12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
> index 8be8882..768bfa1 100644
> --- a/man/man8/tc-flower.8
> +++ b/man/man8/tc-flower.8
> @@ -56,8 +56,10 @@ flower \- flow based traffic control filter
>  .IR MASKED_IP_TTL " | { "
>  .BR dst_ip " | " src_ip " } "
>  .IR PREFIX " | { "
> -.BR dst_port " | " src_port " } "
> -.IR port_number " } | "
> +.BR dst_port " | " src_port " } { "
> +.IR port_number " | "
> +.B range
> +.IR min_port_number-max_port_number " } | "
>  .B tcp_flags
>  .IR MASKED_TCP_FLAGS " | "
>  .B type
> @@ -227,6 +229,12 @@ Match on layer 4 protocol source or destination port number. Only available for
>  .BR ip_proto " values " udp ", " tcp  " and " sctp
>  which have to be specified in beforehand.
>  .TP
> +.BI range " MIN_VALUE-MAX_VALUE"
> +Match on a range of layer 4 protocol source or destination port number. Only
> +available for
> +.BR ip_proto " values " udp ", " tcp  " and " sctp
> +which have to be specified in beforehand.
> +.TP
>  .BI tcp_flags " MASKED_TCP_FLAGS"
>  Match on TCP flags represented as 12bit bitfield in in hexadecimal format.
>  A mask may be optionally provided to limit the bits which are matched. A mask
> 

This prints as:

dst_port NUMBER
src_port NUMBER
      Match  on  layer  4  protocol source or destination port number.
      Only available for ip_proto values udp, tcp and sctp which  have
      to be specified in beforehand.

range MIN_VALUE-MAX_VALUE
      Match  on a range of layer 4 protocol source or destination port
      number. Only available for ip_proto values  udp,  tcp  and  sctp
      which have to be specified in beforehand.

###

That makes it look like range is a standalone option - independent of
dst_port/src_port.

It seems to me the dst_port / src_port should be updated to:

dst_port {NUMBER | range MIN_VALUE-MAX_VALUE}

with the description updated for both options and indented under
dst_port / src_port

^ permalink raw reply

* Re: Kernel 4.19 network performance - forwarding/routing normal users traffic
From: Paweł Staszewski @ 2018-11-20 23:00 UTC (permalink / raw)
  To: David Ahern, Jesper Dangaard Brouer; +Cc: netdev, Yoel Caspersen
In-Reply-To: <807987d8-be15-d249-25be-4397e6f75104@gmail.com>


W dniu 19.11.2018 o 22:59, David Ahern pisze:
> On 11/9/18 5:06 PM, David Ahern wrote:
>> On 11/9/18 9:21 AM, David Ahern wrote:
>>>> Is there possible to add only counters from xdp for vlans ?
>>>> This will help me in testing.
>>> I will take a look today at adding counters that you can dump using
>>> bpftool. It will be a temporary solution for this xdp program only.
>>>
>> Same tree, kernel-tables-wip-02 branch. Compile kernel and install.
>> Compile samples as before.
> new version:
>      https://github.com/dsahern/linux.git bpf/kernel-tables-wip-03
>
> This one prototypes incrementing counters for VLAN devices (rx/tx,
> packets and bytes). Counters for netdevices representing physical ports
> should be managed by the NIC driver.

Will test it today


Thanks

Paweł





>
> I will look at what can be done for packet captures (e.g., xdpdump and
> https://github.com/facebookincubator/katran/tree/master/tools). Most
> likely a project for next week.
>

^ permalink raw reply

* Re: [iproute2-next PATCH v3 1/2] tc: flower: Classify packets based port ranges
From: David Ahern @ 2018-11-20 23:00 UTC (permalink / raw)
  To: Amritha Nambiar, stephen, netdev
  Cc: jakub.kicinski, sridhar.samudrala, jhs, xiyou.wangcong, jiri
In-Reply-To: <154232971379.10668.16416943966699679792.stgit@anamhost.jf.intel.com>

On 11/15/18 5:55 PM, Amritha Nambiar wrote:
> Added support for filtering based on port ranges.
> UAPI changes have been accepted into net-next.
> 
> Example:
> 1. Match on a port range:
> -------------------------
> $ tc filter add dev enp4s0 protocol ip parent ffff:\
>   prio 1 flower ip_proto tcp dst_port range 20-30 skip_hw\
>   action drop
> 
> $ tc -s filter show dev enp4s0 parent ffff:
> filter protocol ip pref 1 flower chain 0
> filter protocol ip pref 1 flower chain 0 handle 0x1
>   eth_type ipv4
>   ip_proto tcp
>   dst_port range 20-30
>   skip_hw
>   not_in_hw
>         action order 1: gact action drop
>          random type none pass val 0
>          index 1 ref 1 bind 1 installed 85 sec used 3 sec
>         Action statistics:
>         Sent 460 bytes 10 pkt (dropped 10, overlimits 0 requeues 0)
>         backlog 0b 0p requeues 0
> 
> 2. Match on IP address and port range:
> --------------------------------------
> $ tc filter add dev enp4s0 protocol ip parent ffff:\
>   prio 1 flower dst_ip 192.168.1.1 ip_proto tcp dst_port range 100-200\
>   skip_hw action drop
> 
> $ tc -s filter show dev enp4s0 parent ffff:
> filter protocol ip pref 1 flower chain 0 handle 0x2
>   eth_type ipv4
>   ip_proto tcp
>   dst_ip 192.168.1.1
>   dst_port range 100-200
>   skip_hw
>   not_in_hw
>         action order 1: gact action drop
>          random type none pass val 0
>          index 2 ref 1 bind 1 installed 58 sec used 2 sec
>         Action statistics:
>         Sent 920 bytes 20 pkt (dropped 20, overlimits 0 requeues 0)
>         backlog 0b 0p requeues 0
> 
> v3:
> Modified flower_port_range_attr_type calls.
> 
> v2:
> Addressed Jiri's comment to sync output format with input
> 
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> ---
>  include/uapi/linux/pkt_cls.h |    7 ++
>  tc/f_flower.c                |  143 +++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 140 insertions(+), 10 deletions(-)
> 

applied to iproute2-next. Thanks

^ permalink raw reply

* Re: [PATCH bpf-next] bpf: libbpf: retry program creation without the name
From: Alexei Starovoitov @ 2018-11-20 23:04 UTC (permalink / raw)
  To: Stanislav Fomichev; +Cc: Stanislav Fomichev, netdev, daniel, ast, vladum
In-Reply-To: <20181120211905.cg4nkrc4mcv7rxsq@mini-arch.hsd1.ca.comcast.net>

On Tue, Nov 20, 2018 at 01:19:05PM -0800, Stanislav Fomichev wrote:
> On 11/20, Alexei Starovoitov wrote:
> > On Mon, Nov 19, 2018 at 04:46:25PM -0800, Stanislav Fomichev wrote:
> > > [Recent commit 23499442c319 ("bpf: libbpf: retry map creation without
> > > the name") fixed this issue for maps, let's do the same for programs.]
> > > 
> > > Since commit 88cda1c9da02 ("bpf: libbpf: Provide basic API support
> > > to specify BPF obj name"), libbpf unconditionally sets bpf_attr->name
> > > for programs. Pre v4.14 kernels don't know about programs names and
> > > return an error about unexpected non-zero data. Retry sys_bpf without
> > > a program name to cover older kernels.
> > > 
> > > Signed-off-by: Stanislav Fomichev <sdf@google.com>
> > > ---
> > >  tools/lib/bpf/bpf.c | 10 ++++++++++
> > >  1 file changed, 10 insertions(+)
> > > 
> > > diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> > > index 961e1b9fc592..cbe9d757c646 100644
> > > --- a/tools/lib/bpf/bpf.c
> > > +++ b/tools/lib/bpf/bpf.c
> > > @@ -212,6 +212,16 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
> > >  	if (fd >= 0 || !log_buf || !log_buf_sz)
> > >  		return fd;
> > >  
> > > +	if (fd < 0 && errno == E2BIG && load_attr->name) {
> > > +		/* Retry the same syscall, but without the name.
> > > +		 * Pre v4.14 kernels don't support prog names.
> > > +		 */
> > 
> > I'm afraid that will put unnecessary stress on the kernel.
> > This check needs to be tighter.
> > Like E2BIG and anything in the log_buf probably means that
> > E2BIG came from the verifier and nothing to do with prog_name.
> > Asking kernel to repeat is an unnecessary work.
> > 
> > In general we need to think beyond this single prog_name field.
> > There are bunch of other fields in bpf_load_program_xattr() and older kernels
> > won't support them. Are we going to zero them out one by one
> > and retry? I don't think that would be practical.
> I general, we don't want to zero anything out. However,
> for this particular problem the rationale is the following:
> In commit 88cda1c9da02 we started unconditionally setting {prog,map}->name
> from the 'higher' libbpfc layer which breaks users on the older kernels.
> 
> > Also libbpf silently ignoring prog_name is not great for debugging.
> > A warning is needed.
> > But it cannot be done out of lib/bpf/bpf.c, since it's a set of syscall
> > wrappers.
> > Imo such "old kernel -> lets retry" feature should probably be done
> > at lib/bpf/libbpf.c level. inside load_program().
> For maps bpftools calls bpf_create_map_xattr directly, that's why
> for maps I did the retry on the lower level (and why for programs I initially
> thought about doing the same). However, in this case maybe asking
> user to omit 'name' argument might be a better option.
> 
> For program names, I agree, we might think about doing it on the higher
> level (although I'm not sure whether we want to have different API
> expectations, i.e. bpf_create_map_xattr ignoring the name and
> bpf_load_program_xattr not ignoring the name).
> 
> So given that rationale above, what do you think is the best way to
> move forward?
> 1. Same patch, but tighten the retry check inside bpf_load_program_xattr ?
> 2. Move this retry logic into load_program and have different handling
>    for bpf_create_map_xattr vs bpf_load_program_xattr ?
> 3. Do 2 and move the retry check for maps from bpf_create_map_xattr
>    into bpf_object__create_maps ?
> 
> (I'm slightly leaning towards #3)

me too. I think it's cleaner for maps to do it in
bpf_object__create_maps().
Originally bpf.c was envisioned to be a thin layer on top of bpf syscall.
Whereas 'smart bits' would go into libbpf.c
Right now this boundary is unfortunately blurry.
May be as #4 long term option we'll introduce another 'smart' layer
between bpf.c that will assume the latest kernel and libbpf.c that deals
with elf. May be will call this new layer a 'compat' layer?
For now I think doing #3 as you suggested is probably the best short term.

^ permalink raw reply

* Re: [RFC PATCH 5/6] net: marvell: neta: add support for 2500base-X
From: Kishon Vijay Abraham I @ 2018-11-21  9:38 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Mark Rutland, devicetree, Jason Cooper, Andrew Lunn, netdev,
	Gregory Clement, Maxime Chevallier, Rob Herring, Thomas Petazzoni,
	linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <20181114111104.GS30658@n2100.armlinux.org.uk>

Hi,

On 14/11/18 4:41 PM, Russell King - ARM Linux wrote:
> On Wed, Nov 14, 2018 at 02:18:14PM +0530, Kishon Vijay Abraham I wrote:
>> Hi,
>>
>> On 12/11/18 6:01 PM, Russell King wrote:
>>> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
>>> ---
>>>  drivers/net/ethernet/marvell/mvneta.c | 58 ++++++++++++++++++++++++++++++-----
>>>  1 file changed, 51 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
>>> index 5bfd349bf41a..7305d4cc0630 100644
>>> --- a/drivers/net/ethernet/marvell/mvneta.c
>>> +++ b/drivers/net/ethernet/marvell/mvneta.c
>>> @@ -27,6 +27,7 @@
>>>  #include <linux/of_irq.h>
>>>  #include <linux/of_mdio.h>
>>>  #include <linux/of_net.h>
>>> +#include <linux/phy/phy.h>
>>>  #include <linux/phy.h>
>>>  #include <linux/phylink.h>
>>>  #include <linux/platform_device.h>
>>> @@ -437,6 +438,7 @@ struct mvneta_port {
>>>  	struct device_node *dn;
>>>  	unsigned int tx_csum_limit;
>>>  	struct phylink *phylink;
>>> +	struct phy *comphy;
>>>  
>>>  	struct mvneta_bm *bm_priv;
>>>  	struct mvneta_bm_pool *pool_long;
>>> @@ -3150,6 +3152,8 @@ static void mvneta_start_dev(struct mvneta_port *pp)
>>>  {
>>>  	int cpu;
>>>  
>>> +	WARN_ON(phy_power_on(pp->comphy));
>>> +
>>>  	mvneta_max_rx_size_set(pp, pp->pkt_size);
>>>  	mvneta_txq_max_tx_size_set(pp, pp->pkt_size);
>>>  
>>> @@ -3212,6 +3216,8 @@ static void mvneta_stop_dev(struct mvneta_port *pp)
>>>  
>>>  	mvneta_tx_reset(pp);
>>>  	mvneta_rx_reset(pp);
>>> +
>>> +	WARN_ON(phy_power_off(pp->comphy));
>>>  }
>>>  
>>>  static void mvneta_percpu_enable(void *arg)
>>> @@ -3337,6 +3343,7 @@ static int mvneta_set_mac_addr(struct net_device *dev, void *addr)
>>>  static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
>>>  			    struct phylink_link_state *state)
>>>  {
>>> +	struct mvneta_port *pp = netdev_priv(ndev);
>>>  	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
>>>  
>>>  	/* We only support QSGMII, SGMII, 802.3z and RGMII modes */
>>> @@ -3357,14 +3364,14 @@ static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
>>>  	/* Asymmetric pause is unsupported */
>>>  	phylink_set(mask, Pause);
>>>  
>>> -	/* We cannot use 1Gbps when using the 2.5G interface. */
>>> -	if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
>>> -		phylink_set(mask, 2500baseT_Full);
>>> -		phylink_set(mask, 2500baseX_Full);
>>> -	} else {
>>> +	/* Half-duplex at speeds higher than 100Mbit is unsupported */
>>> +	if (pp->comphy || state->interface != PHY_INTERFACE_MODE_2500BASEX) {
>>>  		phylink_set(mask, 1000baseT_Full);
>>>  		phylink_set(mask, 1000baseX_Full);
>>>  	}
>>> +	if (pp->comphy || state->interface == PHY_INTERFACE_MODE_2500BASEX) {
>>> +		phylink_set(mask, 2500baseX_Full);
>>> +	}
>>>  
>>>  	if (!phy_interface_mode_is_8023z(state->interface)) {
>>>  		/* 10M and 100M are only supported in non-802.3z mode */
>>> @@ -3378,6 +3385,11 @@ static void mvneta_validate(struct net_device *ndev, unsigned long *supported,
>>>  		   __ETHTOOL_LINK_MODE_MASK_NBITS);
>>>  	bitmap_and(state->advertising, state->advertising, mask,
>>>  		   __ETHTOOL_LINK_MODE_MASK_NBITS);
>>> +
>>> +	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
>>> +	 * to advertise both, only report advertising at 2500BaseX.
>>> +	 */
>>> +	phylink_helper_basex_speed(state);
>>>  }
>>>  
>>>  static int mvneta_mac_link_state(struct net_device *ndev,
>>> @@ -3389,7 +3401,9 @@ static int mvneta_mac_link_state(struct net_device *ndev,
>>>  	gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS);
>>>  
>>>  	if (gmac_stat & MVNETA_GMAC_SPEED_1000)
>>> -		state->speed = SPEED_1000;
>>> +		state->speed =
>>> +			state->interface == PHY_INTERFACE_MODE_2500BASEX ?
>>> +			SPEED_2500 : SPEED_1000;
>>>  	else if (gmac_stat & MVNETA_GMAC_SPEED_100)
>>>  		state->speed = SPEED_100;
>>>  	else
>>> @@ -3504,12 +3518,32 @@ static void mvneta_mac_config(struct net_device *ndev, unsigned int mode,
>>>  			    MVNETA_GMAC_FORCE_LINK_DOWN);
>>>  	}
>>>  
>>> +
>>>  	/* When at 2.5G, the link partner can send frames with shortened
>>>  	 * preambles.
>>>  	 */
>>>  	if (state->speed == SPEED_2500)
>>>  		new_ctrl4 |= MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE;
>>>  
>>> +	if (pp->comphy) {
>>> +		enum phy_mode mode = PHY_MODE_INVALID;
>>> +
>>> +		switch (state->interface) {
>>> +		case PHY_INTERFACE_MODE_SGMII:
>>> +		case PHY_INTERFACE_MODE_1000BASEX:
>>> +			mode = PHY_MODE_SGMII;
>>> +			break;
>>> +		case PHY_INTERFACE_MODE_2500BASEX:
>>> +			mode = PHY_MODE_2500SGMII;
>>> +			break;
>>> +		default:
>>> +			break;
>>> +		}
>>> +
>>> +		if (mode != PHY_MODE_INVALID)
>>> +			WARN_ON(phy_set_mode(pp->comphy, mode));
>>> +	}
>>> +
>>>  	if (new_ctrl0 != gmac_ctrl0)
>>>  		mvreg_write(pp, MVNETA_GMAC_CTRL_0, new_ctrl0);
>>>  	if (new_ctrl2 != gmac_ctrl2)
>>> @@ -4411,7 +4445,7 @@ static int mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
>>>  	if (phy_mode == PHY_INTERFACE_MODE_QSGMII)
>>>  		mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_QSGMII_SERDES_PROTO);
>>>  	else if (phy_mode == PHY_INTERFACE_MODE_SGMII ||
>>> -		 phy_mode == PHY_INTERFACE_MODE_1000BASEX)
>>> +		 phy_interface_mode_is_8023z(phy_mode))
>>>  		mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
>>>  	else if (!phy_interface_mode_is_rgmii(phy_mode))
>>>  		return -EINVAL;
>>> @@ -4428,6 +4462,7 @@ static int mvneta_probe(struct platform_device *pdev)
>>>  	struct mvneta_port *pp;
>>>  	struct net_device *dev;
>>>  	struct phylink *phylink;
>>> +	struct phy *comphy;
>>>  	const char *dt_mac_addr;
>>>  	char hw_mac_addr[ETH_ALEN];
>>>  	const char *mac_from;
>>> @@ -4453,6 +4488,14 @@ static int mvneta_probe(struct platform_device *pdev)
>>>  		goto err_free_irq;
>>>  	}
>>>  
>>> +	comphy = devm_of_phy_get(&pdev->dev, dn, NULL);
>>> +	if (comphy == ERR_PTR(-EPROBE_DEFER)) {
>>> +		err = -EPROBE_DEFER;
>>> +		goto err_free_irq;
>>> +	} else if (IS_ERR(comphy)) {
>>> +		comphy = NULL;
>>> +	}
>>
>> devm_phy_optional_get can be used here instead.
> 
> I don't think that will work with a NULL string.

That's correct.
> 
> devm_phy_optional_get() ultimately ends up calling phy_get(), which
> in this case would receive a NULL string.  It will pass that NULL
> string to of_property_match_string().

There is a check for (string == NULL), even before of_property_match_string is
invoked in phy_get()
> 
> of_property_match_string() will try to find the "phy-names" property,
> which will not exist, and hence will return -EINVAL.
> 
> phy_get() doesn't check for error conditions, but passes this directly
> to _of_phy_get() as the index.  _of_phy_get() passes that on to
> of_parse_phandle_with_args(), which will fail to find an entry with
> cur_index == -EINVAL (since it counts up from zero.)  Hence,
> _of_phy_get() will return -ENODEV, thereby causing
> devm_phy_optional_get() to return NULL, even if there's a phys=
> property present.
> 
> of_phy_get() and phy_get() have different behaviours when a NULL string
> is passed in - the of_phy_get() family will get the first PHY specified
> in the DT phys= property, whereas the phy_get() family of functions
> will fail.

Agreed. I'll fix this so that we have similar behavior with of_phy_get() and
phy_get().
> 
> Since there is no devm_of_phy_optional_get(), that leads people down
> the path of coding that functionality at the callsites, such as in
> drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c.

Okay.

Thanks
Kishon


> 

^ permalink raw reply

* Re: [RFC PATCH 0/6] Armada 38x comphy driver to support 2.5Gbps networking
From: Kishon Vijay Abraham I @ 2018-11-21  9:41 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Mark Rutland, devicetree, Jason Cooper, Andrew Lunn, netdev,
	Gregory Clement, Maxime Chevallier, Rob Herring, Thomas Petazzoni,
	linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <20181114105606.GR30658@n2100.armlinux.org.uk>

Hi Russell,

On 14/11/18 4:26 PM, Russell King - ARM Linux wrote:
> On Wed, Nov 14, 2018 at 01:39:29PM +0530, Kishon Vijay Abraham I wrote:
>> Hi,
>>
>> On 12/11/18 5:59 PM, Russell King - ARM Linux wrote:
>>> Hi,
>>>
>>> This series adds support for dynamically switching between 1Gbps
>>> and 2.5Gbps networking for the Marvell Armada 38x SoCs, tested on
>>> Armada 388 on the Clearfog platform.
>>>
>>> This is necessary to be able to connect (eg) a Clearfog platform
>>> with a Macchiatobin platform via the SFP sockets, as Clearfog
>>> currently only supports 1Gbps networking via the SFP socket and
>>> Macchiatobin defaults to 2.5Gbps when using Fiberchannel SFPs.
>>>
>>> In order to allow dynamic switching, we need to implement a common
>>> phy driver to switch the ethernet serdes lane speed - 2.5Gbps is
>>> just 1Gbps up-clocked by 2.5x.  We implement a simple comphy
>>> driver to achieve this, which only supports networking.
>>>
>>> With this, we are able to support both Fiberchannel SFPs operating
>>> at 2.5Gbps or 1Gbps, and 1G ethernet SFPs plugged into the Clearfog
>>> platform, dynamically selecting according to the SFPs abilities.
>>>
>>> I'm aware of the proposed changes to the PHY layer, changing
>>> phy_set_mode() to take the ethernet phy interface type, hence why
>>> this is RFC - there's also the question about how this will be
>>> merged.  This series is currently based on 4.20-rc1, but will
>>> likely need to be rebased when the PHY layer changes hit.
>>
>> For this case, I'd prefer the phy_set_mode series and the phy and net changes
>> here (after rebasing) go via linux-phy tree.
> 
> Please let me know when they've hit, thanks.

I've merged the phy_set_mode series to linux-phy -next.

Thanks
Kishon
> 

^ permalink raw reply

* [PATCH bpf-next v2 1/2] bpf: libbpf: retry program creation without the name
From: Stanislav Fomichev @ 2018-11-20 23:15 UTC (permalink / raw)
  To: netdev, ast; +Cc: daniel, Stanislav Fomichev
In-Reply-To: <20181120230445.os6ikxaqhq777xao@ast-mbp.dhcp.thefacebook.com>

[Recent commit 23499442c319 ("bpf: libbpf: retry map creation without
the name") fixed this issue for maps, let's do the same for programs.]

Since commit 88cda1c9da02 ("bpf: libbpf: Provide basic API support
to specify BPF obj name"), libbpf unconditionally sets bpf_attr->name
for programs. Pre v4.14 kernels don't know about programs names and
return an error about unexpected non-zero data. Retry
bpf_load_program_xattr without a program name to cover older kernels.

Signed-off-by: Stanislav Fomichev <sdf@google.com>
---
 tools/lib/bpf/libbpf.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index cb6565d79603..2ea14dfa28fc 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1401,6 +1401,18 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
 
 	ret = bpf_load_program_xattr(&load_attr, log_buf, BPF_LOG_BUF_SIZE);
 
+	if (ret < 0 && errno == E2BIG && load_attr.name) {
+		/* Retry the same operation, but without the name.
+		 * Pre v4.14 kernels don't support prog names.
+		 */
+		cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
+		pr_warning("Error in bpf_load_program_xattr(%s):%s(%d). Retrying without name.\n",
+			   prog->name, cp, errno);
+		load_attr.name = NULL;
+		ret = bpf_load_program_xattr(&load_attr, log_buf,
+					     BPF_LOG_BUF_SIZE);
+	}
+
 	if (ret >= 0) {
 		*pfd = ret;
 		ret = 0;
-- 
2.19.1.1215.g8438c0b245-goog

^ permalink raw reply related

* [PATCH bpf-next v2 2/2] bpf: libbpf: move map name retry into libbpf.c
From: Stanislav Fomichev @ 2018-11-20 23:15 UTC (permalink / raw)
  To: netdev, ast; +Cc: daniel, Stanislav Fomichev
In-Reply-To: <20181120231510.46332-1-sdf@google.com>

To be in line with the previous commit ("bpf: libbpf: retry program
creation without the name"), do the retry at the higher level, not the
syscall level.

Signed-off-by: Stanislav Fomichev <sdf@google.com>
---
 tools/lib/bpf/bpf.c    | 11 +----------
 tools/lib/bpf/libbpf.c | 11 +++++++++++
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 836447bb4f14..ce1822194590 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -69,7 +69,6 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
 {
 	__u32 name_len = create_attr->name ? strlen(create_attr->name) : 0;
 	union bpf_attr attr;
-	int ret;
 
 	memset(&attr, '\0', sizeof(attr));
 
@@ -87,15 +86,7 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
 	attr.map_ifindex = create_attr->map_ifindex;
 	attr.inner_map_fd = create_attr->inner_map_fd;
 
-	ret = sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-	if (ret < 0 && errno == EINVAL && create_attr->name) {
-		/* Retry the same syscall, but without the name.
-		 * Pre v4.14 kernels don't support map names.
-		 */
-		memset(attr.map_name, 0, sizeof(attr.map_name));
-		return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-	}
-	return ret;
+	return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
 }
 
 int bpf_create_map_node(enum bpf_map_type map_type, const char *name,
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 2ea14dfa28fc..c081b5b8f68f 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1184,6 +1184,17 @@ bpf_object__create_maps(struct bpf_object *obj)
 			*pfd = bpf_create_map_xattr(&create_attr);
 		}
 
+		if (*pfd < 0 && errno == EINVAL && create_attr.name) {
+			/* Retry the same operation, but without the name.
+			 * Pre v4.14 kernels don't support map names.
+			 */
+			cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
+			pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without name.\n",
+				   map->name, cp, errno);
+			create_attr.name = NULL;
+			*pfd = bpf_create_map_xattr(&create_attr);
+		}
+
 		if (*pfd < 0) {
 			size_t j;
 
-- 
2.19.1.1215.g8438c0b245-goog

^ permalink raw reply related

* Re: [PATCH iproute2-next 2/8] json: add %hhu helpers
From: David Ahern @ 2018-11-20 23:18 UTC (permalink / raw)
  To: Jakub Kicinski, Stephen Hemminger; +Cc: oss-drivers, netdev
In-Reply-To: <20181119174018.0629445a@cakuba.netronome.com>

On 11/19/18 6:40 PM, Jakub Kicinski wrote:
> On Mon, 19 Nov 2018 17:18:42 -0800, Stephen Hemminger wrote:
>>>  void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
>>>  {
>>>  	jsonw_name(self, prop);  
>>
>> Do you really need this? it turns out that because of C type
>> conversions print_uint should just work?
> 
> I wondered about that for a second, but I took the existence of
> jsonw_hu_field() etc. as a proof that explicit typing is preferred.
> 

Stephen: you ok with the explicit typing version?

^ permalink raw reply


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