From: Marc Kleine-Budde <mkl@pengutronix.de>
To: David Jander <david@protonic.nl>
Cc: Wolfgang Grandegger <wg@grandegger.com>,
linux-can@vger.kernel.org,
Alexander Stein <alexander.stein@systec-electronic.com>
Subject: Re: [PATCH 07/15] can: rx-fifo: Change to do controller off-load in interrupt and NAPI poll
Date: Mon, 03 Nov 2014 12:10:17 +0100 [thread overview]
Message-ID: <54576299.6080907@pengutronix.de> (raw)
In-Reply-To: <20141020090613.63044885@archvile>
[-- Attachment #1: Type: text/plain, Size: 7515 bytes --]
On 10/20/2014 09:06 AM, David Jander wrote:
>>> +static int can_rx_fifo_napi_poll(struct napi_struct *napi, int quota)
>>> +{
>>> + struct can_rx_fifo *fifo = container_of(napi, struct can_rx_fifo,
>>> napi);
>>> + int work_done = 0;
>>> + int ret;
>>> + unsigned int head;
>>> + unsigned int tail;
>>> +
>>> +restart_poll:
>>> + /* handle mailboxes */
>>> + head = smp_load_acquire(&fifo->ring_head);
>>> + tail = fifo->ring_tail;
>>> + while ((CIRC_CNT(head, tail, fifo->ring_size) >= 1) &&
>>> + (work_done < quota)) {
>>> + ret = can_rx_fifo_read_napi_frame(fifo, tail);
>>> + work_done += ret;
>>> + tail = (tail + 1) & (fifo->ring_size -1);
>>> + smp_store_release(&fifo->ring_tail, tail);
>>> + }
>>> +
>>> + if (work_done < quota) {
>>> + napi_complete(napi);
>>> +
>>> + /* Check if there was another interrupt */
>>> + head = smp_load_acquire(&fifo->ring_head);
>>> + if ((CIRC_CNT(head, tail, fifo->ring_size) >= 1) &&
>>> + napi_reschedule(&fifo->napi))
>>> + goto restart_poll;
>>
>> Hmmm, this looks a bit strange. If I understand the code correctly you ask
>> that napi should be started again, but then jump directly to the beginning.
>
> The documentation seems to say that one should use it like that:
>
> http://www.linuxfoundation.org/collaborate/workgroups/networking/napi
Some drivers do it this way, other don't.
> If you still think it is wrong, then tell me how to re-enable napi and
> continue correctly. AFAIK it is done like this in order to avoid a race when
> the interrupt is called while NAPI polling was underway. napi_schedule() just
> sets a flag, and does _not_ add work to a queue...
I think your code is correct. There are several aspects to it, as far as
I understand the NAPI code:
- NAPI_STATE_SCHED means a poll is scheduled
- napi_reschedule(): if NAPI_STATE_SCHED is already set it will return
false. Otherwise NAPI_STATE_SCHED will be set and a sofirq will be
raised, true is returned.
- I think the "goto restart_poll" is an optimisation, as the softirq
will schedule the poll function again. But AFAICS it's fine, as
napi_complete() checks for NAPI_STATE_SCHED set.
- The above code is needed for devices on an edge triggered interrupt
line. As there is a race window between checking the RX buffer and
enabling the interrupt line. As we don't have an interrupt here at
all, we must have this code. Good work!
>>> + }
>>> +
>>> + return work_done;
>>> +}
>>> +
>>> int can_rx_fifo_add(struct net_device *dev, struct can_rx_fifo *fifo)
>>> {
>>> + unsigned int weight;
>>> fifo->dev = dev;
>>>
>>> if ((fifo->low_first < fifo->high_first) &&
>>> - (fifo->high_first < fifo->high_last))
>>> + (fifo->high_first < fifo->high_last)) {
>>> fifo->inc = true;
>>> - else if ((fifo->low_first > fifo->high_first) &&
>>> - (fifo->high_first > fifo->high_last))
>>> + weight = fifo->high_last - fifo->low_first;
>>> + } else if ((fifo->low_first > fifo->high_first) &&
>>> + (fifo->high_first > fifo->high_last)) {
>>> fifo->inc = false;
>>> - else
>>> + weight = fifo->low_first - fifo->high_last;
>>> + } else
>>> return -EINVAL;
>>
>> Please but { } at every branch of the if else.
>
> Ok, will do.
>
>>>
>>> - if (!fifo->read_pending || !fifo->mailbox_enable_mask ||
>>> - !fifo->mailbox_disable || !fifo->mailbox_receive)
>>> + if (!fifo->mailbox_enable_mask || !fifo->mailbox_move_to_buffer ||
>>> + !fifo->mailbox_enable)
>>> return -EINVAL;
>>>
>>> + /* Make ring-buffer a sensible size that is a power of 2 */
>>> + fifo->ring_size = (2 << fls(weight));
>>> + fifo->ring = kzalloc(sizeof(struct can_frame) * fifo->ring_size,
>>> + GFP_KERNEL);
>>> + if (!fifo->ring)
>>> + return -ENOMEM;
>>> +
>>> + fifo->ring_head = fifo->ring_tail = 0;
>>> +
>>> + /* Take care of NAPI handling */
>>> + netif_napi_add(dev, &fifo->napi, can_rx_fifo_napi_poll, weight);
>>
>> I'm not sure, if the rx-fifo should take care of the whole NAPI, I think it's
>> better to provide helper functions instead.
>
> Why not? We are removing the messages from the CAN controller in the IRQ
> already, so why would the CAN driver have to even care about NAPI which
> happens _after_ all that? Can you come up with an example where this may not
> be desirable?
If NAPI is handled by the rx-fifo exclusively, everything else i.e.
tx-complete and error handling cannot be done in NAPI. Thinking more
about this and looking at the above discussed code, maybe it's better to
have the napi in the rx-fifo code.
> Can you illustrate your idea with helper functions?
Something like can_rx_fifo_napi_poll() would be our helper function,
it's supposed to be called from the NAPI handler the driver has
registered. But the driver has to take care about the napi_complete()
and napi_reschedule(), which is probably quite fragile.... So keep it as
it is.
>
>>> +
>>> /* init variables */
>>> fifo->mask_low = can_rx_fifo_mask_low(fifo);
>>> fifo->mask_high = can_rx_fifo_mask_high(fifo);
>>> - fifo->next = fifo->low_first;
>>> + fifo->second_first = false;
>>> fifo->active = fifo->mask_low | fifo->mask_high;
>>> fifo->mailbox_enable_mask(fifo, fifo->active);
>>>
>>> @@ -338,60 +420,95 @@ int can_rx_fifo_add(struct net_device *dev, struct
>>> can_rx_fifo *fifo) }
>>> EXPORT_SYMBOL_GPL(can_rx_fifo_add);
>>>
>>> -int can_rx_fifo_poll(struct can_rx_fifo *fifo, int quota)
>>> +static unsigned int can_rx_fifo_offload_if_full(struct can_rx_fifo *fifo,
>>> unsigned int n) +{
>>> + unsigned int head = fifo->ring_head;
>>> + unsigned int tail = ACCESS_ONCE(fifo->ring_tail);
>>> + unsigned int ret = 0;
>>> +
>>> + if (CIRC_SPACE(head, tail, fifo->ring_size) >= 1) {
>>> + ret = fifo->mailbox_move_to_buffer(fifo,
>>> &fifo->ring[head], n);
>>> + if (ret)
>>> + smp_store_release(&fifo->ring_head,
>>> + (head + 1) & (fifo->ring_size - 1));
>>> + } else {
>>> + ret = fifo->mailbox_move_to_buffer(fifo, &fifo->overflow,
>>> n);
>>> + if (ret)
>>> + fifo->dev->stats.rx_dropped++;
>>> + }
>>
>> That's the purpose of the overflow mailbox? fifo-> overflow seems to be write
>> only?
>
> Yes.
> The idea is to simplify the code for the user. mailbox_move_to_buffer() should
> just move the corresponding can message to the provided buffer and do all
> interrupt-flag clearing and stuff the driver needs to do in order to free the
> MB. Its just that in the case we don't have space in the circular buffer, I
> don't want to complicate things for the driver and tell him that this message
> should be discarded. Just think of fifo->overflow as a sort of /dev/null.
> Of course I could just pass NULL to that function, but IMHO that's dangerous
> because since it happens only very seldom, a missing check for NULL in that
> function may bite you when it is already too late (i.e. the driver already hit
> mainline).
Okay, got it, nice idea. Can you put a comment in the struct rx-fifo.
Can you also document the requirements on the mailbox_move_to_buffer()
callback, I remember you've written this in some email....
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
next prev parent reply other threads:[~2014-11-03 11:10 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-10-10 15:46 [RFC PATCH V3 00/15] CAN: Add rx-fifo support and port flexcan to it David Jander
2014-10-10 15:46 ` [PATCH 01/15] can: flexcan: add documentation about mailbox organizaiton David Jander
2014-10-10 15:46 ` [PATCH 02/15] can: flexcan: rename crl2 -> ctrl2 David Jander
2014-10-10 15:46 ` [PATCH 03/15] can: flexcan: replace open coded mailbox code by proper defines David Jander
2014-10-10 15:46 ` [PATCH 04/15] can: flexcan: Re-write receive path to use MB queue instead of FIFO David Jander
2014-10-10 15:46 ` [PATCH 05/15] can: dev: add preliminary rx-fifo David Jander
2014-10-10 15:46 ` [PATCH 06/15] can: rx-fifo: Increase MB size limit from 32 to 64 David Jander
2014-10-19 21:25 ` Marc Kleine-Budde
2014-10-20 6:14 ` David Jander
2014-10-10 15:46 ` [PATCH 07/15] can: rx-fifo: Change to do controller off-load in interrupt and NAPI poll David Jander
2014-10-19 22:09 ` Marc Kleine-Budde
2014-10-20 7:06 ` David Jander
2014-11-03 11:10 ` Marc Kleine-Budde [this message]
2014-11-03 12:44 ` David Jander
2014-10-10 15:46 ` [PATCH 08/15] can: rx-fifo: fix long lines David Jander
2014-10-19 21:18 ` Marc Kleine-Budde
2014-10-20 7:09 ` David Jander
2014-10-10 15:46 ` [PATCH 09/15] can: rx-fifo: Add can_rx_fifo_reset() function David Jander
2014-11-03 11:16 ` Marc Kleine-Budde
2014-11-03 12:46 ` David Jander
2014-11-03 12:51 ` Marc Kleine-Budde
2014-10-10 15:46 ` [PATCH 10/15] can: rx-fifo: remove obsolete comment David Jander
2014-10-10 15:46 ` [PATCH 11/15] can: rx-fifo: Add support for can state tracking and error polling David Jander
2014-11-03 11:24 ` Marc Kleine-Budde
2014-11-03 12:51 ` David Jander
2014-11-03 12:58 ` Marc Kleine-Budde
2014-11-03 13:09 ` David Jander
2014-11-03 13:24 ` Marc Kleine-Budde
2014-11-05 17:16 ` David Jander
2014-11-06 10:20 ` Marc Kleine-Budde
2014-11-06 11:07 ` David Jander
2014-10-10 15:46 ` [PATCH 12/15] can: flexcan: Add support for RX-FIFO David Jander
2014-11-03 11:26 ` Marc Kleine-Budde
2014-11-03 12:55 ` David Jander
2014-11-03 13:34 ` Marc Kleine-Budde
2014-10-10 15:46 ` [PATCH 13/15] can: rx-fifo: Add support for simple irq offloading David Jander
2014-11-03 11:59 ` Marc Kleine-Budde
2014-10-10 15:46 ` [PATCH 14/15] can: flexcan: Add MB/Fifo specific column to comment table of IP versions David Jander
2014-10-10 15:47 ` [PATCH 15/15] can: flexcan: Re-enable RTR reception support for older flexcan IPs David Jander
2014-11-03 12:02 ` Marc Kleine-Budde
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=54576299.6080907@pengutronix.de \
--to=mkl@pengutronix.de \
--cc=alexander.stein@systec-electronic.com \
--cc=david@protonic.nl \
--cc=linux-can@vger.kernel.org \
--cc=wg@grandegger.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.