Commit 9d1fa4c3 authored by Oleksij Rempel's avatar Oleksij Rempel Committed by Alexandre Belloni

rtc: rv8803: convert spin_lock to mutex_lock

Fix a scheduling while atomic issue caused by rv8803_set_time()
holding a spinlock during the call to i2c_smbus_read_byte_data().
Signed-off-by: default avatarOleksij Rempel <fixed-term.Oleksij.Rempel@de.bosch.com>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
parent 7444845b
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
struct rv8803_data { struct rv8803_data {
struct i2c_client *client; struct i2c_client *client;
struct rtc_device *rtc; struct rtc_device *rtc;
spinlock_t flags_lock; struct mutex flags_lock;
u8 ctrl; u8 ctrl;
}; };
...@@ -63,11 +63,11 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id) ...@@ -63,11 +63,11 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
unsigned long events = 0; unsigned long events = 0;
int flags; int flags;
spin_lock(&rv8803->flags_lock); mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
if (flags <= 0) { if (flags <= 0) {
spin_unlock(&rv8803->flags_lock); mutex_unlock(&rv8803->flags_lock);
return IRQ_NONE; return IRQ_NONE;
} }
...@@ -102,7 +102,7 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id) ...@@ -102,7 +102,7 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
rv8803->ctrl); rv8803->ctrl);
} }
spin_unlock(&rv8803->flags_lock); mutex_unlock(&rv8803->flags_lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -155,7 +155,6 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm) ...@@ -155,7 +155,6 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
struct rv8803_data *rv8803 = dev_get_drvdata(dev); struct rv8803_data *rv8803 = dev_get_drvdata(dev);
u8 date[7]; u8 date[7];
int flags, ret; int flags, ret;
unsigned long irqflags;
if ((tm->tm_year < 100) || (tm->tm_year > 199)) if ((tm->tm_year < 100) || (tm->tm_year > 199))
return -EINVAL; return -EINVAL;
...@@ -173,18 +172,18 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm) ...@@ -173,18 +172,18 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
if (ret < 0) if (ret < 0)
return ret; return ret;
spin_lock_irqsave(&rv8803->flags_lock, irqflags); mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG); flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG);
if (flags < 0) { if (flags < 0) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); mutex_unlock(&rv8803->flags_lock);
return flags; return flags;
} }
ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG,
flags & ~RV8803_FLAG_V2F); flags & ~RV8803_FLAG_V2F);
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); mutex_unlock(&rv8803->flags_lock);
return ret; return ret;
} }
...@@ -226,7 +225,6 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -226,7 +225,6 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
u8 alarmvals[3]; u8 alarmvals[3];
u8 ctrl[2]; u8 ctrl[2];
int ret, err; int ret, err;
unsigned long irqflags;
/* The alarm has no seconds, round up to nearest minute */ /* The alarm has no seconds, round up to nearest minute */
if (alrm->time.tm_sec) { if (alrm->time.tm_sec) {
...@@ -236,11 +234,11 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -236,11 +234,11 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
rtc_time64_to_tm(alarm_time, &alrm->time); rtc_time64_to_tm(alarm_time, &alrm->time);
} }
spin_lock_irqsave(&rv8803->flags_lock, irqflags); mutex_lock(&rv8803->flags_lock);
ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl); ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl);
if (ret != 2) { if (ret != 2) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); mutex_unlock(&rv8803->flags_lock);
return ret < 0 ? ret : -EIO; return ret < 0 ? ret : -EIO;
} }
...@@ -253,14 +251,14 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -253,14 +251,14 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL, err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
rv8803->ctrl); rv8803->ctrl);
if (err) { if (err) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); mutex_unlock(&rv8803->flags_lock);
return err; return err;
} }
} }
ctrl[1] &= ~RV8803_FLAG_AF; ctrl[1] &= ~RV8803_FLAG_AF;
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]); err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]);
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); mutex_unlock(&rv8803->flags_lock);
if (err) if (err)
return err; return err;
...@@ -289,7 +287,6 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled) ...@@ -289,7 +287,6 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct rv8803_data *rv8803 = dev_get_drvdata(dev); struct rv8803_data *rv8803 = dev_get_drvdata(dev);
int ctrl, flags, err; int ctrl, flags, err;
unsigned long irqflags;
ctrl = rv8803->ctrl; ctrl = rv8803->ctrl;
...@@ -305,15 +302,15 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled) ...@@ -305,15 +302,15 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
ctrl &= ~RV8803_CTRL_AIE; ctrl &= ~RV8803_CTRL_AIE;
} }
spin_lock_irqsave(&rv8803->flags_lock, irqflags); mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
if (flags < 0) { if (flags < 0) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); mutex_unlock(&rv8803->flags_lock);
return flags; return flags;
} }
flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF); flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF);
err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags); err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); mutex_unlock(&rv8803->flags_lock);
if (err) if (err)
return err; return err;
...@@ -333,7 +330,6 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) ...@@ -333,7 +330,6 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct rv8803_data *rv8803 = dev_get_drvdata(dev); struct rv8803_data *rv8803 = dev_get_drvdata(dev);
int flags, ret = 0; int flags, ret = 0;
unsigned long irqflags;
switch (cmd) { switch (cmd) {
case RTC_VL_READ: case RTC_VL_READ:
...@@ -355,16 +351,16 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) ...@@ -355,16 +351,16 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
return 0; return 0;
case RTC_VL_CLR: case RTC_VL_CLR:
spin_lock_irqsave(&rv8803->flags_lock, irqflags); mutex_lock(&rv8803->flags_lock);
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
if (flags < 0) { if (flags < 0) {
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); mutex_unlock(&rv8803->flags_lock);
return flags; return flags;
} }
flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F); flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F);
ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags); ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); mutex_unlock(&rv8803->flags_lock);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -441,6 +437,7 @@ static int rv8803_probe(struct i2c_client *client, ...@@ -441,6 +437,7 @@ static int rv8803_probe(struct i2c_client *client,
if (!rv8803) if (!rv8803)
return -ENOMEM; return -ENOMEM;
mutex_init(&rv8803->flags_lock);
rv8803->client = client; rv8803->client = client;
i2c_set_clientdata(client, rv8803); i2c_set_clientdata(client, rv8803);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment