From: Jonathan Cameron <jic23@cam.ac.uk>
To: Arnd Bergmann <arnd@arndb.de>
Cc: michael.hennerich@analog.com,
"linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"tglx@linutronix.de" <tglx@linutronix.de>,
"device-drivers-devel@blackfin.uclinux.org"
<device-drivers-devel@blackfin.uclinux.org>
Subject: Re: [RFC PATCH 00/21] IIO: Channel registration rework, buffer chardev combining and rewrite of triggers as 'virtual' irq_chips.
Date: Mon, 04 Apr 2011 18:51:06 +0100 [thread overview]
Message-ID: <4D9A050A.3060209@cam.ac.uk> (raw)
In-Reply-To: <201104041649.24309.arnd@arndb.de>
On 04/04/11 15:49, Arnd Bergmann wrote:
> On Monday 04 April 2011, Jonathan Cameron wrote:
>> On 04/04/11 13:02, Michael Hennerich wrote:
>>>> 2) Flattening together of (some) of the chardevs (buffer related ones).
>>>> As Arnd pointed out, there is really a use case for having multiple
>>>> watershed type events from ring buffers. Much better to have a
>>>> single one (be that at a controllable point). Firstly this removes
>>>> the need for the event escalation code. Second, this single 'event'
>>>> can then be indicated to user space purely using polling on the
>>>> access chrdev. This approach does need an additional attribute to
>>>> tell user space what the poll succeeding indicates (tbd).
>>>>
>>>> I haven't for now merged the ring handling with the more general
>>>> event handling as Arnd suggested. This is for two reasons
>>>> 1) It's much easier to debug this done in a couple of steps
>>>> 2) The approach Arnd suggested may work well, but it is rather
>>>> different to how other bits of the kernel pass event type data
>>>> to user space. It's an interesting idea, but I'd rather any
>>>> discussion of that approach was separate from the obviously
>>>> big gains seen here.
>>>>
>>>> Patches 4, 5, 6, 7, 17
>>>>
>>> I appreciate the removal of the buffer event chardev. Adding support for
>>> poll is also a good thing to do.
>>> However support for a blocking read might also fit some use cases.
>> Good point. I guess blocking on any content and poll for the watershead
>> gives the best of both worlds. The blocking read is more down to the
>> individual implementations than a core feature though - so one to do
>> after this patch set.
>
7> You should implement both blocking and non-blocking read in the core, IMO.
> This is how pipes generally work and what the opn()/read() man pages say it
> works.
I misphrased what I said above. The key thing here is that this is partly
core support and partly a matter of individual buffer implementations being
able to support this. Note we are playing unconventional games with poll
as the poll will only succeed when a threshold on how much data is in the
buffer is passed (not this threshold may be 1, but usually isn't).
In some buffers we don't know if there is new data until this value is passed
or a hardware read occurs.
My feeling is we should have blocking reads block on the absense of any data not
on the threshold as we are doing with poll. Thus not all buffers will support
blocking reads - if they don't the core should fail on the attempt to open
the character devicce.
Anyhow, all I was really suggesting is that this is postponed for now
and handled in a later patch set. I'm far from keen to keep adding stuff
to ring_sw given I want to ditch the thing entirely! What we have in this
series to handle poll in that buffer implementation is a pretty dirty hack.
>
>>>> 3) Reworking the triggering infrastructure to use 'virtual' irq_chips
>>>> This approach was suggested by Thomas Gleixner.
>>>> Before we had explicit trigger consumer lists. This made for a very
>>>> clunky implementation when we considered moving things over to
>>>> threaded interrupts. Thomas pointed out we were reinventing the
>>>> wheel and suggested more or less what we have here (I hope ;)
>>>>
>>> Using threaded interrupts, greatly reduces use of additional workqueues
>>> and excessive interrupt enable and disables.
>> There is a nasty side issue here. What do we do if we are getting triggers
>> faster than all of the consumers can work at? Right now things tend to
>> stall. I think we just want to gracefully stop the relevant trigger
>> if this happens. I'm not quite sure how we can notify userspace that this
>> has happened... Perhaps POLLERR?
>
> I'd say use POLLERR to signal to user space that something bad has happened,
> then return the status in an ioctl().
Yup, that's what I had in mind. Again, may be in a later patch set. This one
is pretty unmanageable as it is!
>
>>>> Patches 9 and 10 are minor rearrangements of code in the one
>>>> driver I know of where the physical interrupt line for events
>>>> is the same as that for data ready signals (though not at the
>>>> same time).
>>>>
>>> I wouldn't consider this being a corner case. I know quite a few devices
>>> that trigger data availability,
>>> and other events from the same physical interrupt line, and they may do
>>> it at the same time.
>> If they do it at the same time things may get a bit nasty. Things are somewhat
>> simpler after some of the later patches, as the irq requests are entirely
>> handled in the drivers. Thus the driver could have one interrupt handler.
>> The restriction will be that it would only be able to do nested irq calls
>> limiting us to not having a top half for anything triggered from such an
>> interrupt. This is because identifying whether we have a dataready or
>> other event will require querying the device and hence sleeping. Note
>> the sysfs trigger driver will also have this restriction (as posted yesterday).
>>
>> For devices where they share the line but cannot happen at the same time I'd
>> prefer to do what we have in the lis3l02dq and completely separate the two
>> uses of the interrupt line.
>
> Can't you just have callback functions in the core that get called for a
> specific event, and let the device driver take care of seperating the
> sources?
>
That's more or less what is happening currently, it's just occurring via two
separate interrupt handlers only one of which is active at a time. This was
mainly done because it allowed me to separate the rewriting of the buffer
handling entirely from that of the events.
To summarize the situation for the lis3l02dq
1) If dataready is enabled no other events are generated (hardware constraint).
2) Other events require a bus read to identify them (hence sleep). Technically
the driver can know if there is only one such event, but it still needs to
acknowledge it.
The dataready acts as an input to the irq_chip based trigger demultiplexing.
As no sleep is needed, we can do non nested irqs, thus allowing other devices
that trigger off this to have top halves. These top halves are typically used
for flipping gpio connected 'capture now' lines. If the device doesn't have one
of these it typically only has a thread function. Note, if you need to sleep,
to trigger a hardware capture pin then it defeats the object anyway!
Thus by the end of the set this thread contains, the event interrupt and the
dataready interrupts were treated as two separate entities that just happened
to use the same physical wire (but not at the same time).
An alternative is the following applied on top of this series (more or less,
it's on my working tree so there might be some fuzz).
I guess this is marginally cleaner so might as well go with it. Technically
I had the events as oneshot before and they aren't any more. They didn't
actually need to be.
[PATCH] staging:iio:lis3l02dq remerge the two interrupt handlers.
Does add a small burden to both handlers, but the gain is somewhat
simpler code.
Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
---
drivers/staging/iio/accel/lis3l02dq.h | 5 +++
drivers/staging/iio/accel/lis3l02dq_core.c | 50 +++++++++++----------------
drivers/staging/iio/accel/lis3l02dq_ring.c | 29 +++++++---------
3 files changed, 38 insertions(+), 46 deletions(-)
diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h
index e7f64bd..b0ace13 100644
--- a/drivers/staging/iio/accel/lis3l02dq.h
+++ b/drivers/staging/iio/accel/lis3l02dq.h
@@ -162,6 +162,7 @@ struct lis3l02dq_state {
u8 *tx;
u8 *rx;
struct mutex buf_lock;
+ bool trigger_on;
};
#define lis3l02dq_h_to_s(_h) \
@@ -202,7 +203,11 @@ void lis3l02dq_unconfigure_ring(struct iio_dev *indio_dev);
#define lis3l02dq_alloc_buf iio_kfifo_allocate
#define lis3l02dq_register_buf_funcs iio_kfifo_register_funcs
#endif
+irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private);
+#define lis3l02dq_th lis3l02dq_data_rdy_trig_poll
+
#else /* CONFIG_IIO_RING_BUFFER */
+#define lis3l02dq_th lis3l02dq_noring
static inline void lis3l02dq_remove_trigger(struct iio_dev *indio_dev)
{
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index 46f0633..9a2f870 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -37,6 +37,11 @@
* It's in the likely to be added comment at the top of spi.h.
* This means that use cannot be made of spi_write etc.
*/
+/* direct copy of the irq_default_primary_handler */
+static irqreturn_t lis3l02dq_noring(int irq, void *private)
+{
+ return IRQ_WAKE_THREAD;
+}
/**
* lis3l02dq_spi_read_reg_8() - read single byte from a single register
@@ -533,19 +538,13 @@ static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev,
int lis3l02dq_disable_all_events(struct iio_dev *indio_dev)
{
- struct iio_sw_ring_helper_state *h
- = iio_dev_get_devdata(indio_dev);
- struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
int ret;
u8 control, val;
- bool irqtofree;
ret = lis3l02dq_spi_read_reg_8(indio_dev,
LIS3L02DQ_REG_CTRL_2_ADDR,
&control);
- irqtofree = !!(control & LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT);
-
control &= ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT;
ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_CTRL_2_ADDR,
@@ -566,9 +565,6 @@ int lis3l02dq_disable_all_events(struct iio_dev *indio_dev)
if (ret)
goto error_ret;
- if (irqtofree)
- free_irq(st->us->irq, indio_dev);
-
ret = control;
error_ret:
return ret;
@@ -578,9 +574,6 @@ static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
int event_code,
int state)
{
- struct iio_sw_ring_helper_state *h
- = iio_dev_get_devdata(indio_dev);
- struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
int ret = 0;
u8 val, control;
u8 currentlyset;
@@ -612,18 +605,6 @@ static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
}
if (changed) {
- if (!(control & LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT)) {
- ret = request_threaded_irq(st->us->irq,
- NULL,
- &lis3l02dq_event_handler,
- IRQF_TRIGGER_RISING |
- IRQF_ONESHOT,
- "lis3l02dq_event",
- indio_dev);
- if (ret)
- goto error_ret;
- }
-
ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
&val);
@@ -637,10 +618,6 @@ static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
&control);
if (ret)
goto error_ret;
-
- /* remove interrupt handler if nothing is still on */
- if (!(val & 0x3f))
- free_irq(st->us->irq, indio_dev);
}
error_ret:
@@ -725,9 +702,18 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
}
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
- ret = lis3l02dq_probe_trigger(st->help.indio_dev);
+ ret = request_threaded_irq(st->us->irq,
+ &lis3l02dq_th,
+ &lis3l02dq_event_handler,
+ IRQF_TRIGGER_RISING,
+ "lis3l02dq",
+ st->help.indio_dev);
if (ret)
goto error_uninitialize_ring;
+
+ ret = lis3l02dq_probe_trigger(st->help.indio_dev);
+ if (ret)
+ goto error_free_interrupt;
}
/* Get the device into a sane initial state */
@@ -739,6 +725,9 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
error_remove_trigger:
if (st->help.indio_dev->modes & INDIO_RING_TRIGGERED)
lis3l02dq_remove_trigger(st->help.indio_dev);
+error_free_interrupt:
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ free_irq(st->us->irq, st->help.indio_dev);
error_uninitialize_ring:
iio_ring_buffer_unregister(st->help.indio_dev->ring);
error_unreg_ring_funcs:
@@ -801,7 +790,8 @@ static int lis3l02dq_remove(struct spi_device *spi)
goto err_ret;
flush_scheduled_work();
-
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+ free_irq(st->us->irq, indio_dev);
lis3l02dq_remove_trigger(indio_dev);
iio_ring_buffer_unregister(indio_dev->ring);
lis3l02dq_unconfigure_ring(indio_dev);
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index a611778..de2c602 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -31,11 +31,17 @@ static inline u16 combine_8_to_16(u8 lower, u8 upper)
/**
* lis3l02dq_data_rdy_trig_poll() the event handler for the data rdy trig
**/
-static irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private)
+irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private)
{
- iio_trigger_poll(private, iio_get_time_ns());
+ struct iio_dev *indio_dev = private;
+ struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
- return IRQ_HANDLED;
+ if (st->trigger_on) {
+ iio_trigger_poll(st->trig, iio_get_time_ns());
+ return IRQ_HANDLED;
+ } else
+ return IRQ_WAKE_THREAD;
}
/**
@@ -203,8 +209,7 @@ __lis3l02dq_write_data_ready_config(struct device *dev, bool state)
&valold);
if (ret)
goto error_ret;
-
- free_irq(st->us->irq, st->trig);
+ st->trigger_on = false;
/* Enable requested */
} else if (state && !currentlyset) {
/* if not set, enable requested */
@@ -215,22 +220,13 @@ __lis3l02dq_write_data_ready_config(struct device *dev, bool state)
valold = ret |
LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION;
- ret = request_irq(st->us->irq,
- lis3l02dq_data_rdy_trig_poll,
- IRQF_TRIGGER_RISING, "lis3l02dq_datardy",
- st->trig);
- if (ret)
- goto error_ret;
-
+ st->trigger_on = true;
ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_CTRL_2_ADDR,
&valold);
- if (ret) {
- free_irq(st->us->irq, st->trig);
+ if (ret)
goto error_ret;
- }
}
return 0;
--
1.7.3.4
next prev parent reply other threads:[~2011-04-04 17:49 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-03-31 14:53 [RFC PATCH 00/21] IIO: Channel registration rework, buffer chardev combining and rewrite of triggers as 'virtual' irq_chips Jonathan Cameron
2011-03-31 14:53 ` [PATCH 01/21] staging:iio: allow channels to be set up using a table of iio_channel_spec structures Jonathan Cameron
2011-03-31 14:53 ` [PATCH 02/21] staging:iio:lis3l02dq - experimental move to new channel_spec approach Jonathan Cameron
2011-03-31 14:53 ` [PATCH 03/21] staging:iio:max1363 - experimental move to channel_spec registration Jonathan Cameron
2011-03-31 14:53 ` [PATCH 04/21] staging:iio: remove ability to escalate events Jonathan Cameron
2011-03-31 14:53 ` [PATCH 05/21] staging:iio: Add polling of events on the ring access chrdev Jonathan Cameron
2011-03-31 14:54 ` [PATCH 06/21] staging:iio: remove legacy event chrdev for the buffers Jonathan Cameron
2011-03-31 14:54 ` [PATCH 07/21] staging:iio: Buffer device flattening Jonathan Cameron
2011-03-31 14:54 ` [PATCH 08/21] staging:iio:lis3l02dq: General cleanup Jonathan Cameron
2011-03-31 14:54 ` [PATCH 09/21] staging:iio: Push interrupt setup down into the drivers for event lines Jonathan Cameron
2011-03-31 14:54 ` [PATCH 10/21] staging:iio: lis3l02dq - separate entirely interrupt handling for thesholds from that for the datardy signal Jonathan Cameron
2011-03-31 14:54 ` [PATCH 11/21] staging:iio: Remove legacy event handling Jonathan Cameron
2011-03-31 14:54 ` [PATCH 12/21] staging:iio:lis3l02dq make threshold interrupt threaded Jonathan Cameron
2011-03-31 14:54 ` [PATCH 13/21] arm: irq: export set flags Jonathan Cameron
2011-03-31 15:48 ` Thomas Gleixner
2011-03-31 14:54 ` [PATCH 14/21] irq: export handle_simple_irq and irq_to_desc to allow for virtual irqs in IIO Jonathan Cameron
2011-03-31 14:54 ` [PATCH 15/21] staging:iio: Add infrastructure for irq_chip based triggers Jonathan Cameron
2011-04-02 18:34 ` Jonathan Cameron
2011-03-31 14:54 ` [PATCH 16/21] stargate2 - add an IIO interrupt pool Jonathan Cameron
2011-03-31 14:54 ` [PATCH 17/21] staging:iio:Documentation generic_buffer.c update to new abi for buffers Jonathan Cameron
2011-03-31 14:54 ` [PATCH 18/21] staging:iio:ring_sw add function needed for threaded irq Jonathan Cameron
2011-03-31 14:54 ` [PATCH 19/21] staging:iio:lis3l02dq move to threaded trigger handling Jonathan Cameron
2011-03-31 14:54 ` [PATCH 20/21] staging:iio:trigger remove legacy pollfunc elements Jonathan Cameron
2011-03-31 14:54 ` [PATCH 21/21] staging:iio: rip out scan_el attributes. Now handled as iio_dev_attrs like everything else Jonathan Cameron
2011-03-31 15:28 ` [RFC PATCH 00/21] IIO: Channel registration rework, buffer chardev combining and rewrite of triggers as 'virtual' irq_chips Arnd Bergmann
2011-04-04 12:02 ` Michael Hennerich
2011-04-04 13:17 ` Jonathan Cameron
2011-04-04 13:26 ` Jonathan Cameron
2011-04-04 14:44 ` Michael Hennerich
2011-04-04 18:09 ` Jonathan Cameron
2011-04-04 14:49 ` Arnd Bergmann
2011-04-04 17:51 ` Jonathan Cameron [this message]
2011-04-11 18:38 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4D9A050A.3060209@cam.ac.uk \
--to=jic23@cam.ac.uk \
--cc=arnd@arndb.de \
--cc=device-drivers-devel@blackfin.uclinux.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michael.hennerich@analog.com \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox