sx150x-pinctrl: Avoid i2c transfer during kexec
machine_crash_shutdown() calls irq_bus_sync_unlock() with local irq disabled. sx150x_irq_bus_sync tries to transfer over i2c bus and hangs because of disabled irqs. Add panic handler, so that sx150x_irq_bus_sync_unlock can return before write to iomap register. Mulitple instances of sx150x device may be present, hence a global flag to indicate machine_crash_shutdown() context. Change-Id: If992f730ba36b81b2a231f3605673e8bae278d16 Signed-off-by: Akshay Adiga <aadiga@codeaurora.org>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2016, BayLibre, SAS. All rights reserved.
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
@@ -40,6 +40,9 @@
|
||||
#include "pinconf.h"
|
||||
#include "pinctrl-utils.h"
|
||||
|
||||
static bool in_kexec_panic;
|
||||
static struct notifier_block *panic_block;
|
||||
|
||||
/* The chip models of sx150x */
|
||||
enum {
|
||||
SX150X_123 = 0,
|
||||
@@ -581,6 +584,14 @@ static void sx150x_irq_bus_sync_unlock(struct irq_data *d)
|
||||
struct sx150x_pinctrl *pctl =
|
||||
gpiochip_get_data(irq_data_get_irq_chip_data(d));
|
||||
|
||||
/* In crash kexec panic path interrupt is disabled.
|
||||
* Writing to regmap will need interrupt/polling mode,
|
||||
* as it goes though i2c.
|
||||
*/
|
||||
if (in_kexec_panic) {
|
||||
mutex_unlock(&pctl->lock);
|
||||
return;
|
||||
}
|
||||
regmap_write(pctl->regmap, pctl->data->reg_irq_mask, pctl->irq.masked);
|
||||
regmap_write(pctl->regmap, pctl->data->reg_sense, pctl->irq.sense);
|
||||
mutex_unlock(&pctl->lock);
|
||||
@@ -1102,6 +1113,14 @@ const struct regmap_config sx150x_regmap_config = {
|
||||
.volatile_reg = sx150x_reg_volatile,
|
||||
};
|
||||
|
||||
static int sx150x_panic_handler(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
if (crash_kexec_post_notifiers)
|
||||
in_kexec_panic = 1;
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int sx150x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@@ -1301,6 +1320,12 @@ static struct i2c_driver sx150x_driver = {
|
||||
|
||||
static int __init sx150x_init(void)
|
||||
{
|
||||
panic_block = kzalloc(sizeof(*panic_block), GFP_KERNEL);
|
||||
if (!panic_block)
|
||||
return -ENOMEM;
|
||||
panic_block->notifier_call = sx150x_panic_handler;
|
||||
atomic_notifier_chain_register(&panic_notifier_list,
|
||||
panic_block);
|
||||
return i2c_add_driver(&sx150x_driver);
|
||||
}
|
||||
subsys_initcall(sx150x_init);
|
||||
|
||||
Reference in New Issue
Block a user