From: David Jander <david@protonic.nl>
To: Marc Kleine-Budde <mkl@pengutronix.de>
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, 3 Nov 2014 13:44:12 +0100 [thread overview]
Message-ID: <20141103134412.60107f15@archvile> (raw)
In-Reply-To: <54576299.6080907@pengutronix.de>
On Mon, 03 Nov 2014 12:10:17 +0100
Marc Kleine-Budde <mkl@pengutronix.de> wrote:
> 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!
Exactly. Thanks!
> >>> + }
> >>> +
> >>> + 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.
Ok, so we keep it there...
> > 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.
That's what I thought too.
> >
> >>> +
> >>> /* 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....
Ok, will do. It might take a few days until I can post the next version
unfortunately....
Best regards,
--
David Jander
Protonic Holland.
next prev parent reply other threads:[~2014-11-03 12:43 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
2014-11-03 12:44 ` David Jander [this message]
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=20141103134412.60107f15@archvile \
--to=david@protonic.nl \
--cc=alexander.stein@systec-electronic.com \
--cc=linux-can@vger.kernel.org \
--cc=mkl@pengutronix.de \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).