We have SSIF interface present in both DMI and ACPI tables, sometimes ssif_probe is called simultaneously from i2c interface (from ACPI) and while loading ipmi_ssif driver(from DMI table) at kernel boot. Both try to register the same SSIF interface simultaneously, where it hits a race. In this case both send a command and get a currupted response.
This patch adds check to void registering the same device twice. Signed-off-by: Kamlakant Patel <kamlaka...@marvell.com> --- drivers/char/ipmi/ipmi_ssif.c | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index ca9528c4f183..97830d31c5d3 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1146,6 +1146,7 @@ MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the default scan of static DEFINE_MUTEX(ssif_infos_mutex); static LIST_HEAD(ssif_infos); +static LIST_HEAD(ssif_clients); #define IPMI_SSIF_ATTR(name) \ static ssize_t ipmi_##name##_show(struct device *dev, \ @@ -1523,6 +1524,34 @@ static void test_multipart_messages(struct i2c_client *client, #define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \ IPMI_BMC_EVT_MSG_INTR) +static int ssif_is_registered(struct i2c_client *client) +{ + struct ssif_addr_info *info; + int rv = 0; + + mutex_lock(&ssif_infos_mutex); + list_for_each_entry(info, &ssif_clients, link) { + if ((info->binfo.addr == client->addr) && + (!strcmp(info->adapter_name, client->adapter->name))) { + rv = -EEXIST; + goto exit; + } + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info){ + rv = -ENOMEM; + goto exit; + } + + info->adapter_name = client->adapter->name; + info->binfo.addr = client->addr; + list_add_tail(&info->link, &ssif_clients); +exit: + mutex_unlock(&ssif_infos_mutex); + return rv; +} + static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) { unsigned char msg[3]; @@ -1534,6 +1563,10 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) u8 slave_addr = 0; struct ssif_addr_info *addr_info = NULL; + /* Check if the client is already registered. */ + if (ssif_is_registered(client)) + return 0; + resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); if (!resp) return -ENOMEM; @@ -1844,6 +1877,12 @@ static void free_ssif_clients(void) kfree(info->adapter_name); kfree(info); } + + list_for_each_entry_safe(info, tmp, &ssif_clients, link) { + list_del(&info->link); + kfree(info); + } + mutex_unlock(&ssif_infos_mutex); } -- 2.17.1 _______________________________________________ Openipmi-developer mailing list Openipmi-developer@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openipmi-developer