@@ -73,13 +73,12 @@ static int smbus_do_alert(struct device *dev, void *addrp)
* The alert IRQ handler needs to hand work off to a task which can issue
* SMBus calls, because those sleeping calls can't be made in IRQ context.
*/
-static void smbus_alert(struct work_struct *work)
+static irqreturn_t smbus_alert(int irq, void *d)
{
- struct i2c_smbus_alert *alert;
+ struct i2c_smbus_alert *alert = d;
struct i2c_client *ara;
unsigned short prev_addr = 0; /* Not a valid address */
- alert = container_of(work, struct i2c_smbus_alert, alert);
ara = alert->ara;
for (;;) {
@@ -116,6 +115,17 @@ static void smbus_alert(struct work_struct *work)
prev_addr = data.addr;
}
+ return IRQ_HANDLED;
+}
+
+static void smbalert_work(struct work_struct *work)
+{
+ struct i2c_smbus_alert *alert;
+
+ alert = container_of(work, struct i2c_smbus_alert, alert);
+
+ smbus_alert(alert->irq, alert);
+
/* We handled all alerts; re-enable level-triggered IRQs */
if (!alert->alert_edge_triggered)
enable_irq(alert->irq);
@@ -158,12 +168,13 @@ static int smbalert_probe(struct i2c_client *ara,
alert->alert_edge_triggered = (irq_type & IRQ_TYPE_EDGE_BOTH);
}
- INIT_WORK(&alert->alert, smbus_alert);
+ INIT_WORK(&alert->alert, smbalert_work);
alert->ara = ara;
if (alert->irq > 0) {
- res = devm_request_irq(&ara->dev, alert->irq, smbalert_irq,
- 0, "smbus_alert", alert);
+ res = devm_request_threaded_irq(&ara->dev, alert->irq,
+ smbalert_irq, smbus_alert,
+ 0, "smbus_alert", alert);
if (res)
return res;
}
handle_nested_irq calls the threaded irq handler. So if the smbus_alert irq is being generated via this an null address is derefenced. Split IRQ up into separate functions to allow thread / non thread irq to work correctly. Signed-off-by: Phil Reid <preid@electromag.com.au> --- drivers/i2c/i2c-smbus.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)