sonic-buildimage/platform/mellanox/non-upstream-patches/patches/0153-mlxsw-i2c-Add-support-for-system-events-handling.patch
Kebo Liu 27f15d40e1 [Mellanox] Update HW-MGMT package to new version V.7.0030.1011 (#16239)
- Why I did it
1. Update Mellanox HW-MGMT package to newer version V.7.0030.1011
2. Replace the SONiC PMON Thermal control algorithm with the one inside the HW-MGMT package on all Nvidia platforms
3. Support Spectrum-4 systems

- How I did it
1. Update the HW-MGMT package version number and submodule pointer
2. Remove the thermal control algorithm implementation from Mellanox platform API
3. Revise the patch to HW-MGMT package which will disable HW-MGMT from running on SIMX
4. Update the downstream kernel patch list

Signed-off-by: Kebo Liu <kebol@nvidia.com>
2023-09-21 18:34:07 +08:00

200 lines
6.1 KiB
Diff

From 8d7807e7b8326c537aa7db4fe31b2ca183d32248 Mon Sep 17 00:00:00 2001
From: Vadim Pasternak <vadimp@nvidia.com>
Date: Sun, 19 Dec 2021 09:12:58 +0000
Subject: [PATCH backport v5.10.164 1/1] mlxsw: i2c: Add support for system
events handling
Extend i2c bus driver with interrupt handler to support system specific
hotplug events, related to line card state change.
Provide system IRQ line for interrupt handler. Line Id could be
provided through the platform data if available, or could be set to the
default value.
Handler is supposed to be set by "mlxsw" driver through bus driver init()
call.
Signed-off-by: Vadim Pasternak <vadimp@nvidia.com>
---
drivers/net/ethernet/mellanox/mlxsw/i2c.c | 110 ++++++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
index cc99ec3f4e96..02f5733cfcc6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
@@ -9,6 +9,7 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
+#include <linux/platform_data/mlxreg.h>
#include <linux/slab.h>
#include "cmd.h"
@@ -51,6 +52,12 @@
#define MLXSW_I2C_TIMEOUT_MSECS 5000
#define MLXSW_I2C_MAX_DATA_SIZE 256
+#define MLXSW_I2C_WORK_ARMED 1
+#define MLXSW_I2C_WORK_CLOSED GENMASK(31, 0)
+#define MLXSW_I2C_WORK_DELAY (usecs_to_jiffies(100))
+#define MLXSW_I2C_DEFAULT_IRQ 17
+#define MLXSW_I2C_VIRT_SLAVE 0x37
+
/**
* struct mlxsw_i2c - device private data:
* @cmd: command attributes;
@@ -63,6 +70,12 @@
* @core: switch core pointer;
* @bus_info: bus info block;
* @block_size: maximum block size allowed to pass to under layer;
+ * @pdata: device platform data;
+ * @dwork_irq: interrupts delayed work queue;
+ * @lock - lock for interrupts sync;
+ * @sys_event_handler: system events handler callback;
+ * @irq: IRQ line number;
+ * @irq_unhandled_count: number of unhandled interrupts;
* @status: status to indicate chip reset or in-service update;
*/
struct mlxsw_i2c {
@@ -77,6 +90,12 @@ struct mlxsw_i2c {
struct mlxsw_core *core;
struct mlxsw_bus_info bus_info;
u16 block_size;
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct delayed_work dwork_irq;
+ spinlock_t lock; /* sync with interrupt */
+ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core);
+ int irq;
+ atomic_t irq_unhandled_count;
u8 status;
};
@@ -537,6 +556,7 @@ mlxsw_i2c_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
int err;
mlxsw_i2c->core = mlxsw_core;
+ mlxsw_i2c->sys_event_handler = sys_event_handler;
mbox = mlxsw_cmd_mbox_alloc();
if (!mbox)
@@ -567,6 +587,87 @@ static void mlxsw_i2c_fini(void *bus_priv)
mlxsw_i2c->core = NULL;
}
+static void mlxsw_i2c_work_handler(struct work_struct *work)
+{
+ struct mlxsw_i2c *mlxsw_i2c;
+ unsigned long flags;
+
+ mlxsw_i2c = container_of(work, struct mlxsw_i2c, dwork_irq.work);
+
+ if (atomic_read(&mlxsw_i2c->irq_unhandled_count)) {
+ if (atomic_dec_and_test(&mlxsw_i2c->irq_unhandled_count))
+ return;
+ }
+
+ mlxsw_i2c->sys_event_handler(mlxsw_i2c->core);
+
+ spin_lock_irqsave(&mlxsw_i2c->lock, flags);
+
+ /* It is possible, that some signals have been inserted, while
+ * interrupts has been masked. In this case such signals could be missed.
+ * In order to handle these signals delayed work is canceled and work task
+ * re-scheduled for immediate execution. It allows to handle missed
+ * signals, if any. In other case work handler just validates that no new
+ * signals have been received during masking.
+ */
+ cancel_delayed_work(&mlxsw_i2c->dwork_irq);
+ schedule_delayed_work(&mlxsw_i2c->dwork_irq, MLXSW_I2C_WORK_DELAY);
+
+ spin_unlock_irqrestore(&mlxsw_i2c->lock, flags);
+
+ if (!atomic_read(&mlxsw_i2c->irq_unhandled_count))
+ atomic_set(&mlxsw_i2c->irq_unhandled_count, MLXSW_I2C_WORK_ARMED);
+}
+
+static irqreturn_t mlxsw_i2c_irq_handler(int irq, void *dev)
+{
+ struct mlxsw_i2c *mlxsw_i2c = (struct mlxsw_i2c *)dev;
+
+ /* Schedule work task for immediate execution.*/
+ schedule_delayed_work(&mlxsw_i2c->dwork_irq, 0);
+
+ return IRQ_NONE;
+}
+
+static int mlxsw_i2c_event_handler_register(struct mlxsw_i2c *mlxsw_i2c)
+{
+ int err;
+
+ /* Initialize interrupt handler if system hotplug driver is reachable
+ * and platform data is available.
+ */
+ if (!IS_REACHABLE(CONFIG_MLXREG_HOTPLUG))
+ return 0;
+
+ if (mlxsw_i2c->pdata && mlxsw_i2c->pdata->irq)
+ mlxsw_i2c->irq = mlxsw_i2c->pdata->irq;
+
+ if (!mlxsw_i2c->irq)
+ return 0;
+
+ err = request_irq(mlxsw_i2c->irq, mlxsw_i2c_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_SHARED, "mlxsw-i2c",
+ mlxsw_i2c);
+ if (err) {
+ dev_err(mlxsw_i2c->bus_info.dev, "Failed to request irq: %d\n",
+ err);
+ return err;
+ }
+
+ spin_lock_init(&mlxsw_i2c->lock);
+ INIT_DELAYED_WORK(&mlxsw_i2c->dwork_irq, mlxsw_i2c_work_handler);
+
+ return 0;
+}
+
+static void mlxsw_i2c_event_handler_unregister(struct mlxsw_i2c *mlxsw_i2c)
+{
+ if (!IS_REACHABLE(CONFIG_MLXREG_HOTPLUG) || !mlxsw_i2c->irq)
+ return;
+ cancel_delayed_work_sync(&mlxsw_i2c->dwork_irq);
+ free_irq(mlxsw_i2c->irq, mlxsw_i2c);
+}
+
static const struct mlxsw_bus mlxsw_i2c_bus = {
.kind = "i2c",
.init = mlxsw_i2c_init,
@@ -661,6 +762,7 @@ static int mlxsw_i2c_probe(struct i2c_client *client,
mlxsw_i2c->bus_info.dev = &client->dev;
mlxsw_i2c->bus_info.low_frequency = true;
mlxsw_i2c->dev = &client->dev;
+ mlxsw_i2c->pdata = client->dev.platform_data;
err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info,
&mlxsw_i2c_bus, mlxsw_i2c, false,
@@ -670,6 +772,12 @@ static int mlxsw_i2c_probe(struct i2c_client *client,
return err;
}
+ if (client->addr == MLXSW_I2C_VIRT_SLAVE)
+ mlxsw_i2c->irq = MLXSW_I2C_DEFAULT_IRQ;
+ err = mlxsw_i2c_event_handler_register(mlxsw_i2c);
+ if (err)
+ return err;
+
return 0;
errout:
@@ -683,6 +791,8 @@ static int mlxsw_i2c_remove(struct i2c_client *client)
{
struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
+ atomic_set(&mlxsw_i2c->irq_unhandled_count, MLXSW_I2C_WORK_CLOSED);
+ mlxsw_i2c_event_handler_unregister(mlxsw_i2c);
mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false);
mutex_destroy(&mlxsw_i2c->cmd.lock);
--
2.20.1