diff mbox series

Use a spinlock to guard `fep->ptp_clk_on`

Message ID 20220831125631.173171-1-csokas.bence@prolan.hu (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Use a spinlock to guard `fep->ptp_clk_on` | expand

Checks

Context Check Description
netdev/tree_selection success Guessed tree name to be net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix warning Target tree name not specified in the subject
netdev/cover_letter success Single patches do not need cover letters
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers fail 2 blamed authors not CCed: B38611@freescale.com heiko.thiery@gmail.com; 5 maintainers not CCed: edumazet@google.com B38611@freescale.com qiangqing.zhang@nxp.com pabeni@redhat.com heiko.thiery@gmail.com
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes fail Problems with Fixes tag: 3
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning CHECK: spinlock_t definition without comment WARNING: line length of 82 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Csókás Bence Aug. 31, 2022, 12:56 p.m. UTC
Mutexes cannot be taken in a non-preemptible context,
causing a panic in `fec_ptp_save_state()`. Replacing
`ptp_clk_mutex` by `ptp_clk_lock` fixes this.

Fixes: 91c0d987a9788dcc5fe26baafd73bf9242b68900
Fixes: 6a4d7234ae9a3bb31181f348ade9bbdb55aeb5c5
Fixes: f79959220fa5fbda939592bf91c7a9ea90419040

Reported-by: Marc Kleine-Budde <mkl@pengutronix.de>

Signed-off-by: Csókás Bence <csokas.bence@prolan.hu>
---
 drivers/net/ethernet/freescale/fec.h      |  2 +-
 drivers/net/ethernet/freescale/fec_main.c | 17 ++++++------
 drivers/net/ethernet/freescale/fec_ptp.c  | 32 +++++++++++------------
 3 files changed, 26 insertions(+), 25 deletions(-)

Comments

Richard Cochran Aug. 31, 2022, 1:54 p.m. UTC | #1
On Wed, Aug 31, 2022 at 02:56:31PM +0200, Csókás Bence wrote:

> diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
> index c74d04f4b2fd..dc8564a1f2d2 100644
> --- a/drivers/net/ethernet/freescale/fec_ptp.c
> +++ b/drivers/net/ethernet/freescale/fec_ptp.c
> @@ -365,21 +365,21 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
>   */
>  static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
>  {
> -	struct fec_enet_private *adapter =
> +	struct fec_enet_private *fep =
>  	    container_of(ptp, struct fec_enet_private, ptp_caps);
>  	u64 ns;
> -	unsigned long flags;
> +	unsigned long flags, flags2;
>  
> -	mutex_lock(&adapter->ptp_clk_mutex);
> +	spin_lock_irqsave(&fep->ptp_clk_lock, flags);
>  	/* Check the ptp clock */
> -	if (!adapter->ptp_clk_on) {
> -		mutex_unlock(&adapter->ptp_clk_mutex);
> +	if (!fep->ptp_clk_on) {

BTW This test is silly. If functionality isn't available then the code
should simply not register the clock in the first place.

> +		spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);
>  		return -EINVAL;
>  	}
> -	spin_lock_irqsave(&adapter->tmreg_lock, flags);
> -	ns = timecounter_read(&adapter->tc);
> -	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
> -	mutex_unlock(&adapter->ptp_clk_mutex);
> +	spin_lock_irqsave(&fep->tmreg_lock, flags2);
> +	ns = timecounter_read(&fep->tc);
> +	spin_unlock_irqrestore(&fep->tmreg_lock, flags2);
> +	spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);

Two spin locks?  Why not just use one?

Thanks,
Richard
Andrew Lunn Aug. 31, 2022, 2:03 p.m. UTC | #2
On Wed, Aug 31, 2022 at 02:56:31PM +0200, Csókás Bence wrote:
> Mutexes cannot be taken in a non-preemptible context,
> causing a panic in `fec_ptp_save_state()`. Replacing
> `ptp_clk_mutex` by `ptp_clk_lock` fixes this.
> 
> Fixes: 91c0d987a9788dcc5fe26baafd73bf9242b68900
> Fixes: 6a4d7234ae9a3bb31181f348ade9bbdb55aeb5c5
> Fixes: f79959220fa5fbda939592bf91c7a9ea90419040
> 
> Reported-by: Marc Kleine-Budde <mkl@pengutronix.de>
> 
> Signed-off-by: Csókás Bence <csokas.bence@prolan.hu>
> ---
>  drivers/net/ethernet/freescale/fec.h      |  2 +-
>  drivers/net/ethernet/freescale/fec_main.c | 17 ++++++------
>  drivers/net/ethernet/freescale/fec_ptp.c  | 32 +++++++++++------------
>  3 files changed, 26 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
> index 0cebe4b63adb..9aac74d14f26 100644
> --- a/drivers/net/ethernet/freescale/fec.h
> +++ b/drivers/net/ethernet/freescale/fec.h
> @@ -557,7 +557,7 @@ struct fec_enet_private {
>  	struct clk *clk_2x_txclk;
>  
>  	bool ptp_clk_on;
> -	struct mutex ptp_clk_mutex;
> +	spinlock_t ptp_clk_lock;
>  	unsigned int num_tx_queues;
>  	unsigned int num_rx_queues;
>  
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index b0d60f898249..98d8f8d6034e 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -2029,6 +2029,7 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
>  {
>  	struct fec_enet_private *fep = netdev_priv(ndev);
>  	int ret;
> +	unsigned long flags;

Please keep to reverse christmas tree
  
>  	if (enable) {
>  		ret = clk_prepare_enable(fep->clk_enet_out);
> @@ -2036,15 +2037,15 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
>  			return ret;
>  
>  		if (fep->clk_ptp) {
> -			mutex_lock(&fep->ptp_clk_mutex);
> +			spin_lock_irqsave(&fep->ptp_clk_lock, flags);

Is the ptp hardware accessed in interrupt context? If not, you can use
a plain spinlock, not _irqsave..

Looking at fec_enet_interrupt() and fec_enet_collect_events() i do not
see anything.

    Andrew
Csókás Bence Aug. 31, 2022, 2:04 p.m. UTC | #3
On 2022. 08. 31. 15:54, Richard Cochran wrote:
> On Wed, Aug 31, 2022 at 02:56:31PM +0200, Csókás Bence wrote:
> 
>> diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
>> index c74d04f4b2fd..dc8564a1f2d2 100644
>> --- a/drivers/net/ethernet/freescale/fec_ptp.c
>> +++ b/drivers/net/ethernet/freescale/fec_ptp.c
>> @@ -365,21 +365,21 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
>>    */
>>   static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
>>   {
>> -	struct fec_enet_private *adapter =
>> +	struct fec_enet_private *fep =
>>   	    container_of(ptp, struct fec_enet_private, ptp_caps);
>>   	u64 ns;
>> -	unsigned long flags;
>> +	unsigned long flags, flags2;
>>   
>> -	mutex_lock(&adapter->ptp_clk_mutex);
>> +	spin_lock_irqsave(&fep->ptp_clk_lock, flags);
>>   	/* Check the ptp clock */
>> -	if (!adapter->ptp_clk_on) {
>> -		mutex_unlock(&adapter->ptp_clk_mutex);
>> +	if (!fep->ptp_clk_on) {
> 
> BTW This test is silly. If functionality isn't available then the code
> should simply not register the clock in the first place.

As I understand, `ptp_clk_on` is a flag indicating whether `clk_ipg` is 
running or not, and not a capability thing. The driver switches it 
run-time in `fec_enet_clk_enable()`.

> 
>> +		spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);
>>   		return -EINVAL;
>>   	}
>> -	spin_lock_irqsave(&adapter->tmreg_lock, flags);
>> -	ns = timecounter_read(&adapter->tc);
>> -	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
>> -	mutex_unlock(&adapter->ptp_clk_mutex);
>> +	spin_lock_irqsave(&fep->tmreg_lock, flags2);
>> +	ns = timecounter_read(&fep->tc);
>> +	spin_unlock_irqrestore(&fep->tmreg_lock, flags2);
>> +	spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);
> 
> Two spin locks?  Why not just use one?

One guards the FEC_ATIME_* registers, the other the `ptp_clk_on` flag. 
For instance, `fec_ptp_adjfreq()` takes `tmreg_lock` but not 
`ptp_clk_lock`, and similarly `fec_enet_clk_enable()` takes 
`ptp_clk_lock` but not `tmreg_lock`.

> 
> Thanks,
> Richard
Csókás Bence Aug. 31, 2022, 2:21 p.m. UTC | #4
On 2022. 08. 31. 16:03, Andrew Lunn wrote:
>> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
>> index b0d60f898249..98d8f8d6034e 100644
>> --- a/drivers/net/ethernet/freescale/fec_main.c
>> +++ b/drivers/net/ethernet/freescale/fec_main.c
>> @@ -2029,6 +2029,7 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
>>   {
>>   	struct fec_enet_private *fep = netdev_priv(ndev);
>>   	int ret;
>> +	unsigned long flags;
> 
> Please keep to reverse christmas tree

checkpatch didn't tell me that was a requirement... Easy to fix though.

>    
>>   	if (enable) {
>>   		ret = clk_prepare_enable(fep->clk_enet_out);
>> @@ -2036,15 +2037,15 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
>>   			return ret;
>>   
>>   		if (fep->clk_ptp) {
>> -			mutex_lock(&fep->ptp_clk_mutex);
>> +			spin_lock_irqsave(&fep->ptp_clk_lock, flags);
> 
> Is the ptp hardware accessed in interrupt context? If not, you can use
> a plain spinlock, not _irqsave..

`fec_suspend()` calls `fec_enet_clk_enable()`, which may be a 
non-preemptible context, I'm not sure how the PM subsystem's internals 
work...
Besides, with the way this driver is built, function call dependencies 
all over the place, I think it's better safe than sorry. I don't think 
there is any disadvantage (besides maybe a few lost cycles) of using 
_irqsave in regular process context anyways.

Bence
Andrew Lunn Aug. 31, 2022, 4:24 p.m. UTC | #5
On Wed, Aug 31, 2022 at 04:21:47PM +0200, Csókás Bence wrote:
> 
> On 2022. 08. 31. 16:03, Andrew Lunn wrote:
> > > diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> > > index b0d60f898249..98d8f8d6034e 100644
> > > --- a/drivers/net/ethernet/freescale/fec_main.c
> > > +++ b/drivers/net/ethernet/freescale/fec_main.c
> > > @@ -2029,6 +2029,7 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
> > >   {
> > >   	struct fec_enet_private *fep = netdev_priv(ndev);
> > >   	int ret;
> > > +	unsigned long flags;
> > 
> > Please keep to reverse christmas tree
> 
> checkpatch didn't tell me that was a requirement... Easy to fix though.

checkpatch does not have the smarts to detect this. And it is a netdev
only thing.

> 
> > >   	if (enable) {
> > >   		ret = clk_prepare_enable(fep->clk_enet_out);
> > > @@ -2036,15 +2037,15 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
> > >   			return ret;
> > >   		if (fep->clk_ptp) {
> > > -			mutex_lock(&fep->ptp_clk_mutex);
> > > +			spin_lock_irqsave(&fep->ptp_clk_lock, flags);
> > 
> > Is the ptp hardware accessed in interrupt context? If not, you can use
> > a plain spinlock, not _irqsave..
> 
> `fec_suspend()` calls `fec_enet_clk_enable()`, which may be a
> non-preemptible context, I'm not sure how the PM subsystem's internals
> work...
> Besides, with the way this driver is built, function call dependencies all
> over the place, I think it's better safe than sorry. I don't think there is
> any disadvantage (besides maybe a few lost cycles) of using _irqsave in
> regular process context anyways.

Those using real time will probably disagree.

There is also a different between not being able to sleep, and not
being able to process an interrupt for some other hardware. You got a
report about taking a mutex in atomic context. That just means you
cannot sleep, probably because a spinlock is held. That is very
different to not being able to handle interrupts. You only need
spin_lock_irqsave() if the interrupt handler also needs the same spin
lock to protect it from a thread using the spin lock.

     Andrew
Francesco Dolcini Aug. 31, 2022, 5:12 p.m. UTC | #6
On Wed, Aug 31, 2022 at 02:56:31PM +0200, Csókás Bence wrote:
> Mutexes cannot be taken in a non-preemptible context,
> causing a panic in `fec_ptp_save_state()`. Replacing
> `ptp_clk_mutex` by `ptp_clk_lock` fixes this.

I would probably add the kernel BUG trace to the commit message.

> Fixes: 91c0d987a9788dcc5fe26baafd73bf9242b68900
> Fixes: 6a4d7234ae9a3bb31181f348ade9bbdb55aeb5c5
> Fixes: f79959220fa5fbda939592bf91c7a9ea90419040

Just

Fixes: f79959220fa5 ("fec: Restart PPS after link state change")

> 
> Reported-by: Marc Kleine-Budde <mkl@pengutronix.de>

Is this https://lore.kernel.org/all/20220827160922.642zlcd5foopozru@pengutronix.de/ the report?

I just stumbled on the same issue on latest torvalds 6.0-rc3.

[   22.718465] =============================
[   22.725431] [ BUG: Invalid wait context ]
[   22.732439] 6.0.0-rc3-00007-gdcf8e5633e2e #1 Tainted: G        W
[   22.742278] -----------------------------
[   22.749217] kworker/3:1/45 is trying to lock:
[   22.757157] c211b71c (&fep->ptp_clk_mutex){+.+.}-{3:3}, at: fec_ptp_gettime+0x30/0xcc
[   22.770814] other info that might help us debug this:
[   22.778718] context-{4:4}
[   22.784065] 4 locks held by kworker/3:1/45:
[   22.790949]  #0: c20072a8 ((wq_completion)events_power_efficient){+.+.}-{0:0}, at: process_one_work+0x1e4/0x730
[   22.806494]  #1: e6a15f18 ((work_completion)(&(&dev->state_queue)->work)){+.+.}-{0:0}, at: process_one_work+0x1e4/0x730
[   22.822744]  #2: c287a478 (&dev->lock){+.+.}-{3:3}, at: phy_state_machine+0x34/0x228
[   22.835884]  #3: c211b2a4 (&dev->tx_global_lock){+...}-{2:2}, at: netif_tx_lock+0x10/0x1c
[   22.849669] stack backtrace:
[   22.855340] CPU: 3 PID: 45 Comm: kworker/3:1 Tainted: G        W          6.0.0-rc3-00007-gdcf8e5633e2e #1
[   22.870713] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
[   22.880149] Workqueue: events_power_efficient phy_state_machine
[   22.888999]  unwind_backtrace from show_stack+0x10/0x14
[   22.897107]  show_stack from dump_stack_lvl+0x58/0x70
[   22.905067]  dump_stack_lvl from __lock_acquire+0x2844/0x29d4
[   22.913755]  __lock_acquire from lock_acquire+0x108/0x37c
[   22.922065]  lock_acquire from __mutex_lock+0x88/0x105c
[   22.930203]  __mutex_lock from mutex_lock_nested+0x1c/0x24
[   22.938611]  mutex_lock_nested from fec_ptp_gettime+0x30/0xcc
[   22.947278]  fec_ptp_gettime from fec_ptp_save_state+0x14/0x50
[   22.955991]  fec_ptp_save_state from fec_restart+0x48/0x8d4
[   22.964410]  fec_restart from fec_enet_adjust_link+0xa8/0x184
[   22.973004]  fec_enet_adjust_link from phy_link_change+0x28/0x54
[   22.981898]  phy_link_change from phy_check_link_status+0x94/0x108
[   22.990954]  phy_check_link_status from phy_state_machine+0x68/0x228
[   23.000153]  phy_state_machine from process_one_work+0x288/0x730
[   23.008968]  process_one_work from worker_thread+0x38/0x4d0
[   23.017289]  worker_thread from kthread+0xe4/0x104
[   23.024758]  kthread from ret_from_fork+0x14/0x28
[   23.032065] Exception stack(0xe6a15fb0 to 0xe6a15ff8)
[   23.039664] 5fa0:                                     00000000 00000000 00000000 00000000
[   23.052816] 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[   23.066101] 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000


Francesco
Jakub Kicinski Aug. 31, 2022, 9:28 p.m. UTC | #7
On Wed, 31 Aug 2022 19:12:59 +0200 Francesco Dolcini wrote:
> > Fixes: 91c0d987a9788dcc5fe26baafd73bf9242b68900
> > Fixes: 6a4d7234ae9a3bb31181f348ade9bbdb55aeb5c5
> > Fixes: f79959220fa5fbda939592bf91c7a9ea90419040  
> 
> Just
> 
> Fixes: f79959220fa5 ("fec: Restart PPS after link state change")

Yup, and please remove any empty lines between tags of all types.
Csókás Bence Sept. 1, 2022, 7:51 a.m. UTC | #8
On 2022. 08. 31. 18:24, Andrew Lunn wrote:
 >>> Please keep to reverse christmas tree
 >>
 >> checkpatch didn't tell me that was a requirement... Easy to fix though.
 >
 > checkpatch does not have the smarts to detect this. And it is a netdev
 > only thing.

I thought checkpatch also has the per-subsystem rules, too.

 > There is also a different between not being able to sleep, and not
 > being able to process an interrupt for some other hardware. You got a
 > report about taking a mutex in atomic context. That just means you
 > cannot sleep, probably because a spinlock is held. That is very
 > different to not being able to handle interrupts. You only need
 > spin_lock_irqsave() if the interrupt handler also needs the same spin
 > lock to protect it from a thread using the spin lock.

Alright, I will switch to plain `spin_lock()` then.

On 2022. 08. 31. 19:12, Francesco Dolcini wrote:
> On Wed, Aug 31, 2022 at 02:56:31PM +0200, Csókás Bence wrote:
>> Mutexes cannot be taken in a non-preemptible context,
>> causing a panic in `fec_ptp_save_state()`. Replacing
>> `ptp_clk_mutex` by `ptp_clk_lock` fixes this.
> 
> I would probably add the kernel BUG trace to the commit message.
> 
>> Fixes: 91c0d987a9788dcc5fe26baafd73bf9242b68900
>> Fixes: 6a4d7234ae9a3bb31181f348ade9bbdb55aeb5c5
>> Fixes: f79959220fa5fbda939592bf91c7a9ea90419040
> 
> Just
> 
> Fixes: f79959220fa5 ("fec: Restart PPS after link state change >
>>
>> Reported-by: Marc Kleine-Budde <mkl@pengutronix.de>
> 
> Is this https://lore.kernel.org/all/20220827160922.642zlcd5foopozru@pengutronix.de/ the report?

Yes, precisely.

> 
> I just stumbled on the same issue on latest torvalds 6.0-rc3.
> 
> [   22.718465] =============================
> [   22.725431] [ BUG: Invalid wait context ]
> [   22.732439] 6.0.0-rc3-00007-gdcf8e5633e2e #1 Tainted: G        W
> [   22.742278] -----------------------------
> [   22.749217] kworker/3:1/45 is trying to lock:
> [   22.757157] c211b71c (&fep->ptp_clk_mutex){+.+.}-{3:3}, at: fec_ptp_gettime+0x30/0xcc
> [   22.770814] other info that might help us debug this:
> [   22.778718] context-{4:4}
> [   22.784065] 4 locks held by kworker/3:1/45:
> [   22.790949]  #0: c20072a8 ((wq_completion)events_power_efficient){+.+.}-{0:0}, at: process_one_work+0x1e4/0x730
> [   22.806494]  #1: e6a15f18 ((work_completion)(&(&dev->state_queue)->work)){+.+.}-{0:0}, at: process_one_work+0x1e4/0x730
> [   22.822744]  #2: c287a478 (&dev->lock){+.+.}-{3:3}, at: phy_state_machine+0x34/0x228
> [   22.835884]  #3: c211b2a4 (&dev->tx_global_lock){+...}-{2:2}, at: netif_tx_lock+0x10/0x1c

Thank you, this lock was the source of the problem!

> 
> Francesco
> 

Bence
Csókás Bence Sept. 1, 2022, 8:06 a.m. UTC | #9
On 2022. 09. 01. 9:51, Csókás Bence wrote:
> 
> On 2022. 08. 31. 18:24, Andrew Lunn wrote:
>  >>> Please keep to reverse christmas tree
>  >>
>  >> checkpatch didn't tell me that was a requirement... Easy to fix though.
>  >
>  > checkpatch does not have the smarts to detect this. And it is a netdev
>  > only thing.
> 
> I thought checkpatch also has the per-subsystem rules, too.
> 
>  > There is also a different between not being able to sleep, and not
>  > being able to process an interrupt for some other hardware. You got a
>  > report about taking a mutex in atomic context. That just means you
>  > cannot sleep, probably because a spinlock is held. That is very
>  > different to not being able to handle interrupts. You only need
>  > spin_lock_irqsave() if the interrupt handler also needs the same spin
>  > lock to protect it from a thread using the spin lock.
> 
> Alright, I will switch to plain `spin_lock()` then.

By the way, what about `&fep->tmreg_lock`? Should that also be switched 
to `spin_lock()`? If not, how should I handle the nested locking? 
Calling `spin_lock_irqsave(&fep->tmreg_lock)` after 
`spin_lock(&&fep->ptp_clk_lock)` seems pointless. Should I lock with 
`spin_lock_irqsave(&fep->ptp_clk_lock)` there?
Andrew Lunn Sept. 1, 2022, 12:18 p.m. UTC | #10
On Thu, Sep 01, 2022 at 10:06:03AM +0200, Csókás Bence wrote:
> 
> On 2022. 09. 01. 9:51, Csókás Bence wrote:
> > 
> > On 2022. 08. 31. 18:24, Andrew Lunn wrote:
> >  >>> Please keep to reverse christmas tree
> >  >>
> >  >> checkpatch didn't tell me that was a requirement... Easy to fix though.
> >  >
> >  > checkpatch does not have the smarts to detect this. And it is a netdev
> >  > only thing.
> > 
> > I thought checkpatch also has the per-subsystem rules, too.
> > 
> >  > There is also a different between not being able to sleep, and not
> >  > being able to process an interrupt for some other hardware. You got a
> >  > report about taking a mutex in atomic context. That just means you
> >  > cannot sleep, probably because a spinlock is held. That is very
> >  > different to not being able to handle interrupts. You only need
> >  > spin_lock_irqsave() if the interrupt handler also needs the same spin
> >  > lock to protect it from a thread using the spin lock.
> > 
> > Alright, I will switch to plain `spin_lock()` then.
> 
> By the way, what about `&fep->tmreg_lock`? Should that also be switched to
> `spin_lock()`? If not, how should I handle the nested locking? Calling
> `spin_lock_irqsave(&fep->tmreg_lock)` after `spin_lock(&&fep->ptp_clk_lock)`
> seems pointless. Should I lock with `spin_lock_irqsave(&fep->ptp_clk_lock)`
> there?

Richard was making the point, do you need two locks?

What are the locks protecting? Could you use one lock for both use
cases? Should the other lock also not be an _irqsave()?

       Andrew
diff mbox series

Patch

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 0cebe4b63adb..9aac74d14f26 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -557,7 +557,7 @@  struct fec_enet_private {
 	struct clk *clk_2x_txclk;
 
 	bool ptp_clk_on;
-	struct mutex ptp_clk_mutex;
+	spinlock_t ptp_clk_lock;
 	unsigned int num_tx_queues;
 	unsigned int num_rx_queues;
 
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b0d60f898249..98d8f8d6034e 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2029,6 +2029,7 @@  static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	int ret;
+	unsigned long flags;
 
 	if (enable) {
 		ret = clk_prepare_enable(fep->clk_enet_out);
@@ -2036,15 +2037,15 @@  static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 			return ret;
 
 		if (fep->clk_ptp) {
-			mutex_lock(&fep->ptp_clk_mutex);
+			spin_lock_irqsave(&fep->ptp_clk_lock, flags);
 			ret = clk_prepare_enable(fep->clk_ptp);
 			if (ret) {
-				mutex_unlock(&fep->ptp_clk_mutex);
+				spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);
 				goto failed_clk_ptp;
 			} else {
 				fep->ptp_clk_on = true;
 			}
-			mutex_unlock(&fep->ptp_clk_mutex);
+			spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);
 		}
 
 		ret = clk_prepare_enable(fep->clk_ref);
@@ -2059,10 +2060,10 @@  static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 	} else {
 		clk_disable_unprepare(fep->clk_enet_out);
 		if (fep->clk_ptp) {
-			mutex_lock(&fep->ptp_clk_mutex);
+			spin_lock_irqsave(&fep->ptp_clk_lock, flags);
 			clk_disable_unprepare(fep->clk_ptp);
 			fep->ptp_clk_on = false;
-			mutex_unlock(&fep->ptp_clk_mutex);
+			spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);
 		}
 		clk_disable_unprepare(fep->clk_ref);
 		clk_disable_unprepare(fep->clk_2x_txclk);
@@ -2075,10 +2076,10 @@  static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 		clk_disable_unprepare(fep->clk_ref);
 failed_clk_ref:
 	if (fep->clk_ptp) {
-		mutex_lock(&fep->ptp_clk_mutex);
+		spin_lock_irqsave(&fep->ptp_clk_lock, flags);
 		clk_disable_unprepare(fep->clk_ptp);
 		fep->ptp_clk_on = false;
-		mutex_unlock(&fep->ptp_clk_mutex);
+		spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);
 	}
 failed_clk_ptp:
 	clk_disable_unprepare(fep->clk_enet_out);
@@ -3907,7 +3908,7 @@  fec_probe(struct platform_device *pdev)
 	}
 
 	fep->ptp_clk_on = false;
-	mutex_init(&fep->ptp_clk_mutex);
+	spin_lock_init(&fep->ptp_clk_lock);
 
 	/* clk_ref is optional, depends on board */
 	fep->clk_ref = devm_clk_get_optional(&pdev->dev, "enet_clk_ref");
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index c74d04f4b2fd..dc8564a1f2d2 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -365,21 +365,21 @@  static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
  */
 static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
 {
-	struct fec_enet_private *adapter =
+	struct fec_enet_private *fep =
 	    container_of(ptp, struct fec_enet_private, ptp_caps);
 	u64 ns;
-	unsigned long flags;
+	unsigned long flags, flags2;
 
-	mutex_lock(&adapter->ptp_clk_mutex);
+	spin_lock_irqsave(&fep->ptp_clk_lock, flags);
 	/* Check the ptp clock */
-	if (!adapter->ptp_clk_on) {
-		mutex_unlock(&adapter->ptp_clk_mutex);
+	if (!fep->ptp_clk_on) {
+		spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);
 		return -EINVAL;
 	}
-	spin_lock_irqsave(&adapter->tmreg_lock, flags);
-	ns = timecounter_read(&adapter->tc);
-	spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
-	mutex_unlock(&adapter->ptp_clk_mutex);
+	spin_lock_irqsave(&fep->tmreg_lock, flags2);
+	ns = timecounter_read(&fep->tc);
+	spin_unlock_irqrestore(&fep->tmreg_lock, flags2);
+	spin_unlock_irqrestore(&fep->ptp_clk_lock, flags);
 
 	*ts = ns_to_timespec64(ns);
 
@@ -401,13 +401,13 @@  static int fec_ptp_settime(struct ptp_clock_info *ptp,
 	    container_of(ptp, struct fec_enet_private, ptp_caps);
 
 	u64 ns;
-	unsigned long flags;
+	unsigned long flags, flags2;
 	u32 counter;
 
-	mutex_lock(&fep->ptp_clk_mutex);
+	spin_lock_irqsave(&fep->ptp_clk_lock, flags2);
 	/* Check the ptp clock */
 	if (!fep->ptp_clk_on) {
-		mutex_unlock(&fep->ptp_clk_mutex);
+		spin_unlock_irqrestore(&fep->ptp_clk_lock, flags2);
 		return -EINVAL;
 	}
 
@@ -421,7 +421,7 @@  static int fec_ptp_settime(struct ptp_clock_info *ptp,
 	writel(counter, fep->hwp + FEC_ATIME);
 	timecounter_init(&fep->tc, &fep->cc, ns);
 	spin_unlock_irqrestore(&fep->tmreg_lock, flags);
-	mutex_unlock(&fep->ptp_clk_mutex);
+	spin_unlock_irqrestore(&fep->ptp_clk_lock, flags2);
 	return 0;
 }
 
@@ -516,15 +516,15 @@  static void fec_time_keep(struct work_struct *work)
 {
 	struct delayed_work *dwork = to_delayed_work(work);
 	struct fec_enet_private *fep = container_of(dwork, struct fec_enet_private, time_keep);
-	unsigned long flags;
+	unsigned long flags, flags2;
 
-	mutex_lock(&fep->ptp_clk_mutex);
+	spin_lock_irqsave(&fep->ptp_clk_lock, flags2);
 	if (fep->ptp_clk_on) {
 		spin_lock_irqsave(&fep->tmreg_lock, flags);
 		timecounter_read(&fep->tc);
 		spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 	}
-	mutex_unlock(&fep->ptp_clk_mutex);
+	spin_unlock_irqrestore(&fep->ptp_clk_lock, flags2);
 
 	schedule_delayed_work(&fep->time_keep, HZ);
 }