tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: if_txtimer API to replace (*if_watchdog)()
On Wed, Jan 22, 2020 at 9:22 AM Jason Thorpe <thorpej%me.com@localhost> wrote:
>
>
> > On Jan 20, 2020, at 2:48 PM, Jason Thorpe <thorpej%me.com@localhost> wrote:
> >
> > Folks --
> >
> > The legacy (*if_watchdog)() interface has a couple of problems:
> >
> > 1- It does not have any way to represent multiple hardware-managed transmit queues.
> >
> > 2- It's not easy to make MP-safe because it relies on modifying the ifnet structure periodically outside of the normal locking mechanisms.
> >
> > The wm(4) driver solved the problem in a reasonable way, and to make it easier for the other drivers in the tree to adopt it's strategy, I re-factored it into a new if_txtimer structure and API.
> >
> > So save typing, I'll paste the relevant section of <net/if.h>:
>
> I spent some time thinking about this a little more, especially around making it easier to convert drivers that don't have a periodic tick already (this is mainly drivers that don't use MII), so I added some extra support for such drivers and as a proof of concept, converted the SGI "sq" driver. You can see that it's a very easy mechanical conversion for legacy drivers, that still gives them a simple NET_MPSAFE migration path (there's a provision for providing a tx queue interlock to the timer expiration callback).
>
> If there is consensus that this is a reasonable direction, then I'll start migrating drivers and, when complete, remove the legacy (*if_watchdog)() and if_timer fields from struct ifnet.
No objection to the direction. Thank you for the effort!
I have two comments of the API. See below.
>
> For completeness, here's the big block comment:
>
> /*
> * if_txtimer --
> *
> * Transmission timer (to replace the legacy ifnet watchdog timer).
> *
> * The driver should allocate one if_txtimer per hardware-managed
> * transmission queue. There are two different ways to allocate
> * the and use the timer, based on the driver's structure.
> *
> * DRIVERS THAT PROVIDE THEIR OWN PERIODIC CALLOUT
> * ===============================================
> *
> * ==> Allocate timers using if_txtimer_alloc().
> * ==> In the periodic callout, check for txtimer expiration using
> * if_txtimer_is_expired() or if_txtimer_is_expired_explicit()
> * (see below).
> *
> * DRIVERS THAT DO NOT PROVIDE THEIR OWN PERIODIC CALLOUT
> * ======================================================
> *
> * ==> Allocate timers using if_txtimer_alloc_with_callback().
> * This variant allocates a callout and provides a facility
> * for the callout to invoke a driver-provided callack when
> * the timer expires, with an optional interlock (typically
> * the transmit queue mutex).
> *
> * If an interlock is provided, the interlock will be acquired
> * before checking for timer expiration, and will invoke the
> * callback with the interlock held if the timer has expired.
> * NOTE: the callback is responsible for releasing the interlock.
Why? I think we should keep lock/unlock in the same place,
at least in the same layer, as much as possible unless there is
a critical reason to do so.
> * If an interlock is NOT provided, then IPL will be raised to
> * splnet() before checking for timer expiration and invoking
> * the callback. In this case, the IPL will be restored on
> * the callback's behalf when it returns.
> * ==> In the driver's (*if_init)() routine, the timer's callout
> * should be started with if_txtimer_start(). In the driver's
> * (*if_stop)() routine, the timer's callout should be stopped
> * with if_txtimer_stop() or if_txtimer_halt() (see callout(9)
> * for the difference between stop and halt).
We need to teach if_txtimer_tick not to call callout_schedule
somehow on destruction, otherwise if_txtimer_tick can continue
to run even after calling callout_halt. wm avoids the flaw by
checking sc_core_stopping at the beginning of wm_tick.
ozaki-r
> *
> * In both cases, all locking of the if_txtimer is the responsibility
> * of the driver. The if_txtimer should be protected by the same lock
> * that protects the associated transmission queue. The queue
> * associated with the timer should be locked when arming and disarming
> * the timer and when checking the timer for expiration.
> *
> * When the driver gives packets to the hardware to transmit, it should
> * arm the timer by calling if_txtimer_arm(). When it is sweeping up
> * completed transmit jobs, it should disarm the timer by calling
> * if_txtimer_disarm() if there are no outstanding jobs remaining.
> *
> * If a driver needs to check multiple transmission queues, an
> * optimization is available that avoids repeated calls to fetch
> * the compare time. In this case, the driver can get the compare
> * time by calling if_txtimer_now() and can check for timer expiration
> * using if_txtimer_is_expired_explicit().
> *
> * The granularity of the if_txtimer is 1 second.
> */
>
>
>
> -- thorpej
>
Home |
Main Index |
Thread Index |
Old Index