Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 061cfeb8 authored by Akshay Adiga's avatar Akshay Adiga
Browse files

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: default avatarAkshay Adiga <aadiga@codeaurora.org>
parent 9499b3ff
Loading
Loading
Loading
Loading
+26 −1
Original line number Diff line number Diff line
/*
 * 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);