* [patch 2/3] sc16is7x2: use threaded irqs
@ 2010-10-01 21:18 akpm
2010-10-01 23:37 ` Michał Mirosław
2010-10-06 20:20 ` Greg KH
0 siblings, 2 replies; 4+ messages in thread
From: akpm @ 2010-10-01 21:18 UTC (permalink / raw)
To: greg; +Cc: linux-serial, akpm, manuel.stahl
From: Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
Signed-off-by: Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
drivers/serial/sc16is7x2.c | 115 ++++++++++++-----------------------
1 file changed, 40 insertions(+), 75 deletions(-)
diff -puN drivers/serial/sc16is7x2.c~sc16is7x2-use-threaded-irqs drivers/serial/sc16is7x2.c
--- a/drivers/serial/sc16is7x2.c~sc16is7x2-use-threaded-irqs
+++ a/drivers/serial/sc16is7x2.c
@@ -92,28 +92,13 @@ struct sc16is7x2_channel {
struct sc16is7x2_chip {
struct spi_device *spi;
struct gpio_chip gpio;
- struct mutex lock;
struct sc16is7x2_channel channel[2];
- /* for handling irqs: need workqueue since we do spi_sync */
- struct workqueue_struct *workqueue;
- struct work_struct work;
- /* set to 1 to make the workhandler exit as soon as possible */
- int force_end_work;
- /* need to know we are suspending to avoid deadlock on workqueue */
- int suspending;
-
+ /* set to true to make the work thread exit as soon as possible */
+ bool force_end_work;
struct spi_message fifo_message;
-#define UART_BUG_TXEN BIT(1) /* UART has buggy TX IIR status */
-#define UART_BUG_NOMSR BIT(2) /* UART has buggy MSR status bits (Au1x00) */
-#define UART_BUG_THRE BIT(3) /* UART has buggy THRE reassertion */
- u16 bugs; /* port bugs */
-
-#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
- u8 lsr_saved_flags;
-#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
- u8 msr_saved_flags;
+ struct mutex io_lock; /* lock for GPIO functions */
u8 io_dir; /* cache for IODir register */
u8 io_state; /* cache for IOState register */
u8 io_gpio; /* PIN is GPIO */
@@ -451,7 +436,7 @@ static void sc16is7x2_shutdown(struct ua
BUG_ON(!chan);
BUG_ON(!ts);
- if (ts->suspending)
+ if (ts->force_end_work)
return;
/* Disable interrupts from this port */
@@ -639,7 +624,7 @@ static void sc16is7x2_release_port(struc
struct sc16is7x2_chip *ts = chan->chip;
dev_dbg(&ts->spi->dev, "%s\n", __func__);
- ts->force_end_work = 1;
+ ts->force_end_work = true;
}
static int sc16is7x2_request_port(struct uart_port *port)
@@ -709,7 +694,7 @@ static int sc16is7x2_gpio_request(struct
BUG_ON(offset > 8);
dev_dbg(&ts->spi->dev, "%s: offset = %d\n", __func__, offset);
- mutex_lock(&ts->lock);
+ mutex_lock(&ts->io_lock);
/* GPIO 0:3 and 4:7 can only be controlled as block */
ts->io_gpio |= BIT(offset);
@@ -720,7 +705,7 @@ static int sc16is7x2_gpio_request(struct
ret = sc16is7x2_write(ts->spi, REG_IOC, 0, ts->io_control);
}
- mutex_unlock(&ts->lock);
+ mutex_unlock(&ts->io_lock);
return ret;
}
@@ -734,7 +719,7 @@ static void sc16is7x2_gpio_free(struct g
BUG_ON(offset > 8);
- mutex_lock(&ts->lock);
+ mutex_lock(&ts->io_lock);
/* GPIO 0:3 and 4:7 can only be controlled as block */
ts->io_gpio &= ~BIT(offset);
@@ -746,7 +731,7 @@ static void sc16is7x2_gpio_free(struct g
sc16is7x2_write(ts->spi, REG_IOC, 0, ts->io_control);
}
- mutex_unlock(&ts->lock);
+ mutex_unlock(&ts->io_lock);
}
static int sc16is7x2_direction_input(struct gpio_chip *gpio, unsigned offset)
@@ -757,12 +742,12 @@ static int sc16is7x2_direction_input(str
BUG_ON(offset > 8);
- mutex_lock(&ts->lock);
+ mutex_lock(&ts->io_lock);
ts->io_dir &= ~BIT(offset);
io_dir = ts->io_dir;
- mutex_unlock(&ts->lock);
+ mutex_unlock(&ts->io_lock);
return sc16is7x2_write_async(ts->spi, REG_IOD, 0, io_dir);
}
@@ -776,7 +761,7 @@ static int sc16is7x2_direction_output(st
BUG_ON(offset > 8);
- mutex_lock(&ts->lock);
+ mutex_lock(&ts->io_lock);
if (value)
ts->io_state |= BIT(offset);
@@ -791,7 +776,7 @@ static int sc16is7x2_direction_output(st
sc16is7x2_add_write_cmd(&cmds[1], REG_IOD, 0, ts->io_dir);
}
- mutex_unlock(&ts->lock);
+ mutex_unlock(&ts->io_lock);
return sc16is7x2_spi_async(ts->spi, cmds, 2);
}
@@ -804,7 +789,7 @@ static int sc16is7x2_get(struct gpio_chi
BUG_ON(offset > 8);
- mutex_lock(&ts->lock);
+ mutex_lock(&ts->io_lock);
if (ts->io_dir & BIT(offset)) {
/* Output: return cached level */
@@ -818,7 +803,7 @@ static int sc16is7x2_get(struct gpio_chi
}
}
- mutex_unlock(&ts->lock);
+ mutex_unlock(&ts->io_lock);
return level;
}
@@ -831,7 +816,7 @@ static void sc16is7x2_set(struct gpio_ch
BUG_ON(offset > 8);
- mutex_lock(&ts->lock);
+ mutex_lock(&ts->io_lock);
if (value)
ts->io_state |= BIT(offset);
@@ -839,7 +824,7 @@ static void sc16is7x2_set(struct gpio_ch
ts->io_state &= ~BIT(offset);
io_state = ts->io_state;
- mutex_unlock(&ts->lock);
+ mutex_unlock(&ts->io_lock);
sc16is7x2_write_async(ts->spi, REG_IOS, 0, io_state);
}
@@ -971,7 +956,7 @@ static bool sc16is7x2_msg_add_fifo_tx(st
}
txlvl = sc16is7x2_read(ts->spi, REG_TXLVL, ch);
- if (txlvl <= 0) {
+ if (txlvl == 0) {
dev_dbg(&ts->spi->dev, " fifo full\n");
return false;
}
@@ -1066,21 +1051,18 @@ static bool sc16is7x2_handle_channel(str
return (chan->iir & UART_IIR_NO_INT) == 0x00;
}
-static void sc16is7x2_work(struct work_struct *w)
+static irqreturn_t sc16is7x2_work(int irq, void *data)
{
- struct sc16is7x2_chip *ts =
- container_of(w, struct sc16is7x2_chip, work);
+ struct sc16is7x2_chip *ts = (struct sc16is7x2_chip *)data;
unsigned pending = 0;
unsigned ch = 0;
dev_dbg(&ts->spi->dev, "%s\n", __func__);
- BUG_ON(!w);
BUG_ON(!ts);
-
if (ts->force_end_work) {
dev_dbg(&ts->spi->dev, "%s: force end!\n", __func__);
- return;
+ return IRQ_NONE;
}
if (ts->channel[0].active)
@@ -1089,29 +1071,28 @@ static void sc16is7x2_work(struct work_s
pending |= BIT(1);
do {
- mutex_lock(&(ts->channel[ch].lock));
if (pending & BIT(ch) && ts->channel[ch].active) {
if (!sc16is7x2_handle_channel(ts, ch))
pending &= ~BIT(ch);
}
- mutex_unlock(&(ts->channel[ch].lock));
ch ^= 1; /* switch channel */
- } while (!ts->force_end_work && !freezing(current) && pending);
+ } while (!ts->force_end_work && pending);
dev_dbg(&ts->spi->dev, "%s finished\n", __func__);
+
+ return IRQ_HANDLED;
}
-static irqreturn_t sc16is7x2_interrupt(int irq, void *dev_id)
+static irqreturn_t sc16is7x2_irq(int irq, void *data)
{
- struct sc16is7x2_chip *ts = dev_id;
-
- dev_dbg(&ts->spi->dev, "%s\n", __func__);
+ struct sc16is7x2_chip *ts = (struct sc16is7x2_channel *)data;
- if (!ts->force_end_work && !work_pending(&ts->work) &&
- !freezing(current) && !ts->suspending)
- queue_work(ts->workqueue, &ts->work);
-
- return IRQ_HANDLED;
+ /* It takes too long to read the regs over SPI,
+ * so just wake up the thread */
+ if (ts->channel[0].active || ts->channel[1].active)
+ return IRQ_WAKE_THREAD;
+ else
+ return IRQ_NONE;
}
/* ******************************** INIT ********************************* */
@@ -1229,16 +1210,16 @@ static int __devinit sc16is7x2_probe(str
if (!ts)
return -ENOMEM;
- mutex_init(&ts->lock);
+ mutex_init(&ts->io_lock);
spi_set_drvdata(spi, ts);
ts->spi = spi;
- ts->force_end_work = 1;
+ ts->force_end_work = true;
/* Reset the chip TODO: and disable IRQ output */
sc16is7x2_write(spi, REG_IOC, 0, IOC_SRESET);
- ret = request_irq(spi->irq, sc16is7x2_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_SHARED, "sc16is7x2", ts);
+ ret = request_threaded_irq(spi->irq, sc16is7x2_irq, sc16is7x2_work,
+ IRQF_TRIGGER_FALLING | IRQF_SHARED, DRIVER_NAME, ts);
if (ret) {
dev_warn(&ts->spi->dev, "cannot register interrupt\n");
goto exit_destroy;
@@ -1255,14 +1236,7 @@ static int __devinit sc16is7x2_probe(str
if (ret)
goto exit_uart1;
- ts->workqueue = create_freezeable_workqueue(DRIVER_NAME);
- if (!ts->workqueue) {
- dev_warn(&ts->spi->dev, "cannot create workqueue\n");
- ret = -EBUSY;
- goto exit_gpio;
- }
- INIT_WORK(&ts->work, sc16is7x2_work);
- ts->force_end_work = 0;
+ ts->force_end_work = false;
printk(KERN_INFO DRIVER_NAME " at CS%d (irq %d), 2 UARTs, 8 GPIOs\n"
" eser%d, eser%d, gpiochip%d\n",
@@ -1272,9 +1246,6 @@ static int __devinit sc16is7x2_probe(str
return ret;
-exit_gpio:
- ret = gpiochip_remove(&ts->gpio);
-
exit_uart1:
sc16is7x2_unregister_uart_port(ts, 1);
@@ -1286,7 +1257,7 @@ exit_irq:
exit_destroy:
dev_set_drvdata(&spi->dev, NULL);
- mutex_destroy(&ts->lock);
+ mutex_destroy(&ts->io_lock);
kfree(ts);
return ret;
}
@@ -1299,14 +1270,8 @@ static int __devexit sc16is7x2_remove(st
if (ts == NULL)
return -ENODEV;
+ ts->force_end_work = true;
free_irq(spi->irq, ts);
- ts->force_end_work = 1;
-
- if (ts->workqueue) {
- flush_workqueue(ts->workqueue);
- destroy_workqueue(ts->workqueue);
- ts->workqueue = NULL;
- }
ret = sc16is7x2_unregister_uart_port(ts, 0);
if (ret)
@@ -1321,7 +1286,7 @@ static int __devexit sc16is7x2_remove(st
goto exit_error;
}
- mutex_destroy(&ts->lock);
+ mutex_destroy(&ts->io_lock);
kfree(ts);
exit_error:
_
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [patch 2/3] sc16is7x2: use threaded irqs
2010-10-01 21:18 [patch 2/3] sc16is7x2: use threaded irqs akpm
@ 2010-10-01 23:37 ` Michał Mirosław
2010-10-04 22:18 ` Andrew Morton
2010-10-06 20:20 ` Greg KH
1 sibling, 1 reply; 4+ messages in thread
From: Michał Mirosław @ 2010-10-01 23:37 UTC (permalink / raw)
To: manuel.stahl; +Cc: akpm, greg, linux-serial
On Fri, Oct 01, 2010 at 02:18:04PM -0700, akpm@linux-foundation.org wrote:
> From: Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
>
> Signed-off-by: Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
> Cc: Greg KH <greg@kroah.com>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
>
> drivers/serial/sc16is7x2.c | 115 ++++++++++++-----------------------
> 1 file changed, 40 insertions(+), 75 deletions(-)
>
> diff -puN drivers/serial/sc16is7x2.c~sc16is7x2-use-threaded-irqs drivers/serial/sc16is7x2.c
> --- a/drivers/serial/sc16is7x2.c~sc16is7x2-use-threaded-irqs
> +++ a/drivers/serial/sc16is7x2.c
[...]
> @@ -1066,21 +1051,18 @@ static bool sc16is7x2_handle_channel(str
> return (chan->iir & UART_IIR_NO_INT) == 0x00;
> }
>
> -static void sc16is7x2_work(struct work_struct *w)
> +static irqreturn_t sc16is7x2_work(int irq, void *data)
> {
> - struct sc16is7x2_chip *ts =
> - container_of(w, struct sc16is7x2_chip, work);
> + struct sc16is7x2_chip *ts = (struct sc16is7x2_chip *)data;
You don't need to cast from (void *).
[...]
>
> -static irqreturn_t sc16is7x2_interrupt(int irq, void *dev_id)
> +static irqreturn_t sc16is7x2_irq(int irq, void *data)
> {
> - struct sc16is7x2_chip *ts = dev_id;
> -
> - dev_dbg(&ts->spi->dev, "%s\n", __func__);
> + struct sc16is7x2_chip *ts = (struct sc16is7x2_channel *)data;
This cast seems wrong. Better to just drop it, like in sc16is7x2_work().
>
> - if (!ts->force_end_work && !work_pending(&ts->work) &&
> - !freezing(current) && !ts->suspending)
> - queue_work(ts->workqueue, &ts->work);
> -
> - return IRQ_HANDLED;
> + /* It takes too long to read the regs over SPI,
> + * so just wake up the thread */
> + if (ts->channel[0].active || ts->channel[1].active)
> + return IRQ_WAKE_THREAD;
> + else
> + return IRQ_NONE;
> }
>
[...]
Since this is fixing up patch #1, wouldn't it be better to merge the two?
Best Regards,
Michał Mirosław
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [patch 2/3] sc16is7x2: use threaded irqs
2010-10-01 23:37 ` Michał Mirosław
@ 2010-10-04 22:18 ` Andrew Morton
0 siblings, 0 replies; 4+ messages in thread
From: Andrew Morton @ 2010-10-04 22:18 UTC (permalink / raw)
To: Michał Mirosław; +Cc: manuel.stahl, greg, linux-serial
On Sat, 2 Oct 2010 01:37:53 +0200
Micha__ Miros__aw <mirq@rere.qmqm.pl> wrote:
> On Fri, Oct 01, 2010 at 02:18:04PM -0700, akpm@linux-foundation.org wrote:
> > From: Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
> >
> > Signed-off-by: Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
> > Cc: Greg KH <greg@kroah.com>
> > Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> > ---
> >
> > drivers/serial/sc16is7x2.c | 115 ++++++++++++-----------------------
> > 1 file changed, 40 insertions(+), 75 deletions(-)
> >
> > diff -puN drivers/serial/sc16is7x2.c~sc16is7x2-use-threaded-irqs drivers/serial/sc16is7x2.c
> > --- a/drivers/serial/sc16is7x2.c~sc16is7x2-use-threaded-irqs
> > +++ a/drivers/serial/sc16is7x2.c
> [...]
> > @@ -1066,21 +1051,18 @@ static bool sc16is7x2_handle_channel(str
> > return (chan->iir & UART_IIR_NO_INT) == 0x00;
> > }
> >
> > -static void sc16is7x2_work(struct work_struct *w)
> > +static irqreturn_t sc16is7x2_work(int irq, void *data)
> > {
> > - struct sc16is7x2_chip *ts =
> > - container_of(w, struct sc16is7x2_chip, work);
> > + struct sc16is7x2_chip *ts = (struct sc16is7x2_chip *)data;
>
> You don't need to cast from (void *).
>
> [...]
> >
> > -static irqreturn_t sc16is7x2_interrupt(int irq, void *dev_id)
> > +static irqreturn_t sc16is7x2_irq(int irq, void *data)
> > {
> > - struct sc16is7x2_chip *ts = dev_id;
> > -
> > - dev_dbg(&ts->spi->dev, "%s\n", __func__);
> > + struct sc16is7x2_chip *ts = (struct sc16is7x2_channel *)data;
>
> This cast seems wrong. Better to just drop it, like in sc16is7x2_work().
>
> >
> > - if (!ts->force_end_work && !work_pending(&ts->work) &&
> > - !freezing(current) && !ts->suspending)
> > - queue_work(ts->workqueue, &ts->work);
> > -
> > - return IRQ_HANDLED;
> > + /* It takes too long to read the regs over SPI,
> > + * so just wake up the thread */
> > + if (ts->channel[0].active || ts->channel[1].active)
> > + return IRQ_WAKE_THREAD;
> > + else
> > + return IRQ_NONE;
> > }
> >
> [...]
>
> Since this is fixing up patch #1, wouldn't it be better to merge the two?
I think I'll drop them both and will ask for a resend.
I have a note here that Greg mentioned the need to #define
PORT_SC16IS7X2 - please ensure that that is addressed in the next
version, thanks.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [patch 2/3] sc16is7x2: use threaded irqs
2010-10-01 21:18 [patch 2/3] sc16is7x2: use threaded irqs akpm
2010-10-01 23:37 ` Michał Mirosław
@ 2010-10-06 20:20 ` Greg KH
1 sibling, 0 replies; 4+ messages in thread
From: Greg KH @ 2010-10-06 20:20 UTC (permalink / raw)
To: akpm; +Cc: linux-serial, manuel.stahl
On Fri, Oct 01, 2010 at 02:18:04PM -0700, akpm@linux-foundation.org wrote:
> From: Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
>
> Signed-off-by: Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
> Cc: Greg KH <greg@kroah.com>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
>
> drivers/serial/sc16is7x2.c | 115 ++++++++++++-----------------------
As I can't take the first patch, I can't take this one either :(
thanks,
greg k-h
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2010-10-06 20:47 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-01 21:18 [patch 2/3] sc16is7x2: use threaded irqs akpm
2010-10-01 23:37 ` Michał Mirosław
2010-10-04 22:18 ` Andrew Morton
2010-10-06 20:20 ` Greg KH
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox