From: Zinc Lim Reading an hwmon sensor issues a TSENE firmware mailbox transaction that uses a shared completion slot. Concurrent reads (e.g. parallel "cat .../temp1_input" or a monitoring agent polling all attributes) race over that slot, and the second transmit fails because a completion is already pending: fbnic 0000:41:00.0: Failed to transmit TSENE read msg, err -17 Serialize the hwmon read path with a per-device mutex so only one TSENE transaction is in flight at a time. Fixes: 880630734102 ("eth: fbnic: Add hardware monitoring support via HWMON interface") Signed-off-by: Zinc Lim --- drivers/net/ethernet/meta/fbnic/fbnic.h | 2 ++ drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h index d0715695c43e..e31d6f88b746 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ struct fbnic_dev { struct net_device *netdev; struct dentry *dbg_fbd; struct device *hwmon; + struct mutex hwmon_mutex; /* Serializes hwmon sensor reads */ struct devlink_health_reporter *fw_reporter; struct devlink_health_reporter *otp_reporter; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c index def8598aceec..ac1b4a422677 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c @@ -33,10 +33,17 @@ static int fbnic_hwmon_read(struct device *dev, enum hwmon_sensor_types type, { struct fbnic_dev *fbd = dev_get_drvdata(dev); const struct fbnic_mac *mac = fbd->mac; - int id; + int id, err; id = fbnic_hwmon_sensor_id(type); - return id < 0 ? id : mac->get_sensor(fbd, id, val); + if (id < 0) + return id; + + mutex_lock(&fbd->hwmon_mutex); + err = mac->get_sensor(fbd, id, val); + mutex_unlock(&fbd->hwmon_mutex); + + return err; } static const struct hwmon_ops fbnic_hwmon_ops = { @@ -60,6 +67,8 @@ void fbnic_hwmon_register(struct fbnic_dev *fbd) if (!IS_REACHABLE(CONFIG_HWMON)) return; + mutex_init(&fbd->hwmon_mutex); + fbd->hwmon = hwmon_device_register_with_info(fbd->dev, "fbnic", fbd, &fbnic_chip_info, NULL); @@ -68,6 +77,7 @@ void fbnic_hwmon_register(struct fbnic_dev *fbd) "Failed to register hwmon device %pe\n", fbd->hwmon); fbd->hwmon = NULL; + mutex_destroy(&fbd->hwmon_mutex); } } @@ -78,4 +88,5 @@ void fbnic_hwmon_unregister(struct fbnic_dev *fbd) hwmon_device_unregister(fbd->hwmon); fbd->hwmon = NULL; + mutex_destroy(&fbd->hwmon_mutex); } -- 2.53.0-Meta