net: Add __napi_sycnhronize() to sync with napi poll
Subsystems (2)
net: Add __napi_sycnhronize() to sync with napi poll
The EMAC driver which needs to handle multiple devices with one NAPI instance implements its own per-channel disable bit. However, when setting such a bit, it needs to synchronize with the poller (that is make sure that any pending poller instance has completed, or is started late enough to see that disable bit).
This implements a low level __napi_synchronize() function to acheive that. The underscores are to emphasis the low level aspect of it and to discourage driver writers who don't know what they are doing to use it (to please DaveM :-)
---
(Use correct address for Stephen this time)
If the approach is accepted, I would like to have this merged now so the EMAC patch to make it work again can follow :-)
Note: I use msleep_interruptible(1); just like napi_disable(). However I'm not too happy that the "hot" loop that results of a pending signal here will spin without even a cpu_relax ... what do you guys think would be the best way to handle this ?
include/linux/netdevice.h +15 -0
@@ -394,6 +394,21 @@ static inline void napi_disable(struct n }/** +* __napi_synchronize - synchronize with a concurrent poll +* @n: napi context +* +* Synchronizes with a concurrent poll. Not to be used in normal +* drivers, mostly useful if you end up with multiple interfaces +* on one NAPI instance. +*/ +static inline void __napi_synchronize (struct napi_struct *n) +{ +smp_mb (); +while (test_bit (NAPI_STATE_SCHED , &n->state)) +msleep_interruptible (1 ); +} + +/** * napi_enable - enable NAPI scheduling * @n: napi context *
Quoted 5 lines · Benjamin Herrenschmidt
Note: I use
msleep_interruptible(1); just likenapi_disable(). However I'm not too happy that the "hot" loop that results of a pending signal here will spin without even acpu_relax... what do you guys think would be the best way to handle this ?
Well since the loop does not check signals at all, it should just use msleep.
Granted the process will end up in the D state and contribute to the load average. But if this loop executes long enough for that to be noticed then we've got bigger problems to worry about.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtQuoted 7 lines · Herbert Xu
Quoted 5 lines · Benjamin Herrenschmidt
Note: I use
msleep_interruptible(1); just likenapi_disable(). However I'm not too happy that the "hot" loop that results of a pending signal here will spin without even acpu_relax... what do you guys think would be the best way to handle this ?
Quoted 7 lines
Well since the loop does not check signals at all, it should just use msleep.
Granted the process will end up in the D state and contribute to the load average. But if this loop executes long enough for that to be noticed then we've got bigger problems to worry about.
If Dave & Stephen agree, I'll send a patch changing napi_disable() too then.
Cheers,
Ben.
David Miller
maintainerFrom: Benjamin Herrenschmidt <[email protected]>
Date: Tue, 16 Oct 2007 17:37:03 +1000
Quoted 12 lines · Herbert Xu
Quoted 10 lines
Quoted 5 lines · Benjamin Herrenschmidt
Note: I use
msleep_interruptible(1); just likenapi_disable(). However I'm not too happy that the "hot" loop that results of a pending signal here will spin without even acpu_relax... what do you guys think would be the best way to handle this ?Well since the loop does not check signals at all, it should just use msleep.
Quoted 7 lines
Quoted 4 lines
Granted the process will end up in the D state and contribute to the load average. But if this loop executes long enough for that to be noticed then we've got bigger problems to worry about.
If Dave & Stephen agree, I'll send a patch changing
napi_disable()too then.
I agree with the msleep() change.
Quoted 18 lines · On Tue, 16 Oct 2007 15:49:52 +1000 Benjamin Herrenschmidt…
net: Add
__napi_sycnhronize()to sync with napi pollThe EMAC driver which needs to handle multiple devices with one NAPI instance implements its own per-channel disable bit. However, when setting such a bit, it needs to synchronize with the poller (that is make sure that any pending poller instance has completed, or is started late enough to see that disable bit).
This implements a low level
__napi_synchronize()function to acheive that. The underscores are to emphasis the low level aspect of it and to discourage driver writers who don't know what they are doing to use it (to please DaveM :-)Signed-off-by Benjamin Herrenschmidt <[email protected]>---
(Use correct address for Stephen this time)
Quoted 7 lines
If the approach is accepted, I would like to have this merged now so the EMAC patch to make it work again can follow :-)
Note: I use
msleep_interruptible(1); just likenapi_disable(). However I'm not too happy that the "hot" loop that results of a pending signal here will spin without even acpu_relax... what do you guys think would be the best way to handle this ?
So this is really just like synchronize_irq()? Using msleep is bogus because you want to spin, you are only waiting for a softirq on the other cpu to finish. If you wait for a whole millisecond and sleep that is far longer than the napi routine should take.
You could even optimize it like synchronize_irq() for the non-SMP case.
Signature · 1 line
Stephen Hemminger <[email protected]>
Quoted 7 lines
So this is really just like
synchronize_irq()? Using msleep is bogus because you want to spin, you are only waiting for a softirq on the other cpu to finish. If you wait for a whole millisecond and sleep that is far longer than the napi routine should take.You could even optimize it like
synchronize_irq()for the non-SMP case.
It's just like synchronize_irq() indeed. I used the mlseep() just like napi_disable() mostly because I use it in a very similar context, for disabling my sub-channels on things like link change etc... where I need to reconfigure parts of the chip.
I prefer sleeping in my case but I agree that if somebody else was going to use for something else more performance critical, it might be an issue. On the other hand, spinning will not be nice for my usage scenario :-)
I agree about the SMP optimisation though again, in my usage pattern, it's very unimportant (similar code path as napi_disable)
I'll respin later today though.
Cheers,
Ben.
napi: use non-interruptible sleep in napi_disable
The current napi_disable() uses msleep_interruptible() but doesn't (and can't) exit in case there's a signal, thus ending up doing a hot spin without a cpu_relax. Use uninterruptible sleep instead.
---
include/linux/netdevice.h +1 -1
@@ -390,7 +390,7 @@ static inline void napi_complete(structstatic inline void napi_disable (struct napi_struct *n) {while (test_and_set_bit (NAPI_STATE_SCHED , &n->state)) -msleep_interruptible (1 ); +msleep (1 ); }/**
net: Add __napi_synchronize() to sync with napi poll
The EMAC driver which needs to handle multiple devices with one NAPI instance implements its own per-channel disable bit. However, when setting such a bit, it needs to synchronize with the poller (that is make sure that any pending poller instance has completed, or is started late enough to see that disable bit).
This implements a low level __napi_synchronize() function to acheive that. The underscores are to emphasis the low level aspect of it and to discourage driver writers who don't know what they are doing to use it (to please DaveM :-)
---
Switched to do a cpu_relax() spin instead and only on SMP. Not that we have an smp_mb() in there which synchronize_irq() lacks. I believe this is a bug in synchronize_irq() which I'll handle separately.
Note: unfortunately, Jeff already picked up the EMAC patch without waiting for this to be sorted out (oops...). So if you agree with this patch, it would be nice to have it go in quickly or maybe via Jeff's tree to avoid breakage ? Not terribly important tho.
include/linux/netdevice.h +17 -0
@@ -394,6 +394,23 @@ static inline void napi_disable(struct n }/** +* __napi_synchronize - synchronize with a concurrent poll +* @n: napi context +* +* Synchronizes with a concurrent poll. Not to be used in normal +* drivers, mostly useful if you end up with multiple interfaces +* on one NAPI instance. +*/ +static inline void __napi_synchronize (struct napi_struct *n) +{ +#ifdef CONFIG_SMP +smp_mb (); +while (test_bit (NAPI_STATE_SCHED , &n->state)) +cpu_relax (); +#endif /* CONFIG_SMP */ +} + +/** * napi_enable - enable NAPI scheduling * @n: napi context *
Quoted 16 lines · Benjamin Herrenschmidt
net: Add
__napi_synchronize()to sync with napi pollThe EMAC driver which needs to handle multiple devices with one NAPI instance implements its own per-channel disable bit. However, when setting such a bit, it needs to synchronize with the poller (that is make sure that any pending poller instance has completed, or is started late enough to see that disable bit).
This implements a low level
__napi_synchronize()function to acheive that. The underscores are to emphasis the low level aspect of it and to discourage driver writers who don't know what they are doing to use it (to please DaveM :-)Signed-off-by Benjamin Herrenschmidt <[email protected]>---
Quoted 8 lines
Switched to do a
cpu_relax()spin instead and only on SMP. Not that we have ansmp_mb()in there whichsynchronize_irq()lacks. I believe this is a bug insynchronize_irq()which I'll handle separately.Note: unfortunately, Jeff already picked up the EMAC patch without waiting for this to be sorted out (oops...). So if you agree with this patch, it would be nice to have it go in quickly or maybe via Jeff's tree to avoid breakage ? Not terribly important tho.
Sorry, I thought that was the way everybody was headed. With the driver broken /anyway/, I just sorta threw it into the pile of fixes.
It's upstream now, so let me know if you want to revert or move forward from here...
Jeff
\
Quoted 11 lines
Quoted 4 lines
Note: unfortunately, Jeff already picked up the EMAC patch without waiting for this to be sorted out (oops...). So if you agree with this patch, it would be nice to have it go in quickly or maybe via Jeff's tree to avoid breakage ? Not terribly important tho.
Sorry, I thought that was the way everybody was headed. With the driver broken /anyway/, I just sorta threw it into the pile of fixes.
It's upstream now, so let me know if you want to revert or move forward from here...
Let's just move forward. I can always re-fix the driver :-)
Ben.
Please don't use double underscore, for this function name. There is no reason to not make it a normal API call.
The sky2 fix I am working on will use napi_synchronize as well.
include/linux/netdevice.h +18 -0
@@ -407,6 +407,24 @@ static inline void napi_enable(struct naclear_bit (NAPI_STATE_SCHED , &n->state); } +#ifdef CONFIG_SMP +/** +* napi_synchronize - wait until NAPI is not running +* @n: napi context +* +* Wait until NAPI is done being scheduled on this context. +* Any outstanding processing completes but +* does not disable future activations. +*/ +static inline void napi_synchronize (const struct napi_struct *n) +{ +while (test_bit (NAPI_STATE_SCHED , &n->state)) +msleep (1 ); +} +#else +# define napi_synchronize (n) barrier() +#endif +/* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O
Quoted 4 lines · Stephen Hemminger
Please don't use double underscore, for this function name. There is no reason to not make it a normal API call.
The sky2 fix I am working on will use
napi_synchronizeas well.
Allright. A compiler barrier in the !SMP case makes sense, but I would still want an smp_mb() before the test_bit. I think it's a bug in synchronize_irq not to have it.
Cheers,
Ben.
Quoted 27 lines
include/linux/netdevice.h +18
-0@@ -407,6 +407,24 @@ static inline void napi_enable(struct naclear_bit (NAPI_STATE_SCHED , &n->state); } +#ifdef CONFIG_SMP +/** +* napi_synchronize - wait until NAPI is not running +* @n: napi context +* +* Wait until NAPI is done being scheduled on this context. +* Any outstanding processing completes but +* does not disable future activations. +*/ +static inline void napi_synchronize (const struct napi_struct *n) +{ +while (test_bit (NAPI_STATE_SCHED , &n->state)) +msleep (1 ); +} +#else +# define napi_synchronize (n) barrier() +#endif +/* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O
PATCH 1/1 net: Add napi_sycnhronize() to sync with napi poll
In reply to Stephen Hemmingernet: Add __napi_synchronize() to sync with napi poll
The EMAC driver which needs to handle multiple devices with one NAPI instance implements its own per-channel disable bit. However, when setting such a bit, it needs to synchronize with the poller (that is make sure that any pending poller instance has completed, or is started late enough to see that disable bit).
This implements a low level __napi_synchronize() function to acheive that. The underscores are to emphasis the low level aspect of it and to discourage driver writers who don't know what they are doing to use it (to please DaveM :-)
---
Back to msleep() since it fits my need well and that's what you used as well. Note that the smp_mb() will turn into barrier() on non-SMP.
I'll send a separate patch to fix EMAC to use the non __ version.
include/linux/netdevice.h +17 -0
@@ -394,6 +394,23 @@ static inline void napi_disable(struct n }/** +* napi_synchronize - synchronize with a concurrent poll +* @n: napi context +* +* Synchronizes with a concurrent poll. Not to be used in normal +* drivers, mostly useful if you end up with multiple interfaces +* on one NAPI instance. This must be called from task context. +*/ +static inline void napi_synchronize (struct napi_struct *n) +{ +smp_mb (); +#ifdef CONFIG_SMP +while (test_bit (NAPI_STATE_SCHED , &n->state)) +msleep (1 ); +#endif /* CONFIG_SMP */ +} + +/** * napi_enable - enable NAPI scheduling * @n: napi context *
Re: [PATCH] net: Add napi_sycnhronize() to sync with napi poll
Quoted 8 lines · Benjamin Herrenschmidt
net: Add
__napi_synchronize()to sync with napi pollThe EMAC driver which needs to handle multiple devices with one NAPI instance implements its own per-channel disable bit. However, when setting such a bit, it needs to synchronize with the poller (that is make sure that any pending poller instance has completed, or is started late enough to see that disable bit).
Quoted 4 lines
This implements a low level
__napi_synchronize()function to acheive that. The underscores are to emphasis the low level aspect of it and to discourage driver writers who don't know what they are doing to use it (to please DaveM :-)
Erm.. your commit log calls it __napi_synchronize still.
josh
Re: [PATCH] net: Add napi_sycnhronize() to sync with napi poll
Quoted 9 lines · Josh Boyer
Quoted 8 lines · Benjamin Herrenschmidt
net: Add
__napi_synchronize()to sync with napi pollThe EMAC driver which needs to handle multiple devices with one NAPI instance implements its own per-channel disable bit. However, when setting such a bit, it needs to synchronize with the poller (that is make sure that any pending poller instance has completed, or is started late enough to see that disable bit).
Quoted 6 lines
Quoted 4 lines
This implements a low level
__napi_synchronize()function to acheive that. The underscores are to emphasis the low level aspect of it and to discourage driver writers who don't know what they are doing to use it (to please DaveM :-)Erm.. your commit log calls it
__napi_synchronizestill.
The commit is a mistake, I sent a patch to rename it, or did I miss something ?
Ben.
Re: [PATCH] net: Add napi_sycnhronize() to sync with napi poll
In reply to Benjamin HerrenschmidtQuoted 8 lines · Benjamin Herrenschmidt
net: Add
__napi_synchronize()to sync with napi pollThe EMAC driver which needs to handle multiple devices with one NAPI instance implements its own per-channel disable bit. However, when setting such a bit, it needs to synchronize with the poller (that is make sure that any pending poller instance has completed, or is started late enough to see that disable bit).
Quoted 6 lines
This implements a low level
__napi_synchronize()function to acheive that. The underscores are to emphasis the low level aspect of it and to discourage driver writers who don't know what they are doing to use it (to please DaveM :-)Signed-off-by Benjamin Herrenschmidt <[email protected]>
Ok, trying again, leaving the actual patch below. In the above patch description, you still call it __napi_synchronize. In the patch below, it's napi_syncronize.
I was just trying to point out to whomever commits this patch that the actual description should probably be fixed.
Quoted 42 lines
---
Back to
msleep()since it fits my need well and that's what you used as well. Note that thesmp_mb()will turn intobarrier()on non-SMP.I'll send a separate patch to fix EMAC to use the non __ version.
Index:
linux-work/include/linux/netdevice.h
===================================================================include/linux/netdevice.h +17
-0@@ -394,6 +394,23 @@ static inline void napi_disable(struct n }/** +* napi_synchronize - synchronize with a concurrent poll +* @n: napi context +* +* Synchronizes with a concurrent poll. Not to be used in normal +* drivers, mostly useful if you end up with multiple interfaces +* on one NAPI instance. This must be called from task context. +*/ +static inline void napi_synchronize (struct napi_struct *n) +{ +smp_mb (); +#ifdef CONFIG_SMP +while (test_bit (NAPI_STATE_SCHED , &n->state)) +msleep (1 ); +#endif /* CONFIG_SMP */ +} + +/** * napi_enable - enable NAPI scheduling * @n: napi context * _______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev
Re: [PATCH] net: Add napi_sycnhronize() to sync with napi poll
Quoted 7 lines · Josh Boyer
k, trying again, leaving the actual patch below. In the above patch description, you still call it
__napi_synchronize. In the patch below,
it'snapi_syncronize.I was just trying to point out to whomever commits this patch that the actual description should probably be fixed.
Yup, I noticed finally :-) I think whoever commits can fix it up (it's likely that it's sch patch that gets commited anyway).
Ben.
Re: [PATCH] net: Add napi_sycnhronize() to sync with napi poll
In reply to Benjamin HerrenschmidtQuoted 5 lines
This implements a low level
__napi_synchronize()function to acheive that. The underscores are to emphasis the low level aspect of it and to discourage driver writers who don't know what they are doing to use it (to please DaveM :-)
And I forgot to remove that bit from the description... as pointed out by Josh. Grrr...
Ben.
PATCH 1/1 fix EMAC driver for proper napi_synchronize API
In reply to Stephen HemmingerThe EMAC driver "fix" was merged by mistake before the dust had settled on the new napi synchronize interface (and before it got merged). The final version of that function is spelled without underscores.
---
drivers/net/ibm_newemac/mal.c +1 -1
@@ -322,7 +322,7 @@ void mal_poll_disable(struct mal_instancmsleep (1 );/* Synchronize with the MAL NAPI poller */ -__napi_synchronize (&mal->napi); +napi_synchronize (&mal->napi); }void mal_poll_enable (struct mal_instance *mal,struct mal_commac *commac)
Jeff Garzik
AppliedRe: [PATCH] fix EMAC driver for proper napi_synchronize API
Quoted 5 lines · Benjamin Herrenschmidt
The EMAC driver "fix" was merged by mistake before the dust had settled on the new napi synchronize interface (and before it got merged). The final version of that function is spelled without underscores.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
applied