diff mbox

[net-next,2/5] sh_eth: WARN on access to a register not implemented in a particular chip

Message ID 1424982854.4444.73.camel@xylophone.i.decadent.org.uk
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Ben Hutchings Feb. 26, 2015, 8:34 p.m. UTC
Currently we may silently read/write a register at offset 0.  Change
this to WARN and then ignore the write or read-back all-ones.

Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
---
 drivers/net/ethernet/renesas/sh_eth.c |   16 +++++++++++++++-
 drivers/net/ethernet/renesas/sh_eth.h |   14 ++++++++++++--
 2 files changed, 27 insertions(+), 3 deletions(-)

Comments

Sergei Shtylyov Feb. 27, 2015, 3:21 p.m. UTC | #1
Hello.

On 2/26/2015 11:34 PM, Ben Hutchings wrote:

> Currently we may silently read/write a register at offset 0.  Change
> this to WARN and then ignore the write or read-back all-ones.

    I think reading non-existing registers would yield all 0s, not all 1s.
That's not x86. :-)

> Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>

    Other than that, seems a great idea.

Acked-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>

WBR, Sergei

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Geert Uytterhoeven March 5, 2015, 9:02 a.m. UTC | #2
Replying to a patchwork mbox, as I noticed this is in net-next.

On Thu, 26 Feb 2015, Ben Hutchings wrote:
> Currently we may silently read/write a register at offset 0.  Change
> this to WARN and then ignore the write or read-back all-ones.
> 
> Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
> Acked-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>

While this may be a good idea for debugging...

> --- a/drivers/net/ethernet/renesas/sh_eth.h
> +++ b/drivers/net/ethernet/renesas/sh_eth.h
> @@ -543,19 +543,29 @@ static inline void sh_eth_soft_swap(char *src, int len)
>  #endif
>  }
>  
> +#define SH_ETH_OFFSET_INVALID	((u16) ~0)
> +
>  static inline void sh_eth_write(struct net_device *ndev, u32 data,
>  				int enum_index)
>  {
>  	struct sh_eth_private *mdp = netdev_priv(ndev);
> +	u16 offset = mdp->reg_offset[enum_index];
> +
> +	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
> +		return;

... adding WARN_ON() to static inline functions increases code size a lot:

$ size drivers/net/ethernet/renesas/sh_eth.o{.orig,}
   text	   data	    bss	    dec	    hex	filename
  23352	   1136	      0	  24488	   5fa8	drivers/net/ethernet/renesas/sh_eth.o.orig
  27225	   1136	      0	  28361	   6ec9	drivers/net/ethernet/renesas/sh_eth.o
$

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ben Hutchings March 5, 2015, 1:18 p.m. UTC | #3
On Thu, 2015-03-05 at 10:02 +0100, Geert Uytterhoeven wrote:
> Replying to a patchwork mbox, as I noticed this is in net-next.
> 
> On Thu, 26 Feb 2015, Ben Hutchings wrote:
> > Currently we may silently read/write a register at offset 0.  Change
> > this to WARN and then ignore the write or read-back all-ones.
> > 
> > Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
> > Acked-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
> 
> While this may be a good idea for debugging...
> 
> > --- a/drivers/net/ethernet/renesas/sh_eth.h
> > +++ b/drivers/net/ethernet/renesas/sh_eth.h
> > @@ -543,19 +543,29 @@ static inline void sh_eth_soft_swap(char *src, int len)
> >  #endif
> >  }
> >  
> > +#define SH_ETH_OFFSET_INVALID	((u16) ~0)
> > +
> >  static inline void sh_eth_write(struct net_device *ndev, u32 data,
> >  				int enum_index)
> >  {
> >  	struct sh_eth_private *mdp = netdev_priv(ndev);
> > +	u16 offset = mdp->reg_offset[enum_index];
> > +
> > +	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
> > +		return;
> 
> ... adding WARN_ON() to static inline functions increases code size a lot:
> 
> $ size drivers/net/ethernet/renesas/sh_eth.o{.orig,}
>    text	   data	    bss	    dec	    hex	filename
>   23352	   1136	      0	  24488	   5fa8	drivers/net/ethernet/renesas/sh_eth.o.orig
>   27225	   1136	      0	  28361	   6ec9	drivers/net/ethernet/renesas/sh_eth.o
> $

Time to un-inline it, maybe?

Ben.


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ben Dooks March 9, 2015, 8:50 a.m. UTC | #4
On 05/03/15 13:18, Ben Hutchings wrote:
> On Thu, 2015-03-05 at 10:02 +0100, Geert Uytterhoeven wrote:
>> Replying to a patchwork mbox, as I noticed this is in net-next.
>>
>> On Thu, 26 Feb 2015, Ben Hutchings wrote:
>>> Currently we may silently read/write a register at offset 0.  Change
>>> this to WARN and then ignore the write or read-back all-ones.
>>>
>>> Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
>>> Acked-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>>
>> While this may be a good idea for debugging...
>>
>>> --- a/drivers/net/ethernet/renesas/sh_eth.h
>>> +++ b/drivers/net/ethernet/renesas/sh_eth.h
>>> @@ -543,19 +543,29 @@ static inline void sh_eth_soft_swap(char *src, int len)
>>>  #endif
>>>  }
>>>  
>>> +#define SH_ETH_OFFSET_INVALID	((u16) ~0)
>>> +
>>>  static inline void sh_eth_write(struct net_device *ndev, u32 data,
>>>  				int enum_index)
>>>  {
>>>  	struct sh_eth_private *mdp = netdev_priv(ndev);

does de-referencing this each time make a difference? Looks like
it would have been easier to pass an "struct sh_eth_private" instead
of the "struct net_device *ndev"

>>> +	u16 offset = mdp->reg_offset[enum_index];
>>> +
>>> +	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
>>> +		return;

You could cange the mdp->reg_offset to an mdp->reg_pointer and make
any invalid registers a NULL. This would at-least make it fail on an
invalid access.

>> ... adding WARN_ON() to static inline functions increases code size a lot:
>>
>> $ size drivers/net/ethernet/renesas/sh_eth.o{.orig,}
>>    text	   data	    bss	    dec	    hex	filename
>>   23352	   1136	      0	  24488	   5fa8	drivers/net/ethernet/renesas/sh_eth.o.orig
>>   27225	   1136	      0	  28361	   6ec9	drivers/net/ethernet/renesas/sh_eth.o
>> $
> 
> Time to un-inline it, maybe?
> 
> Ben.
> 
> 
> _______________________________________________
> linux-kernel mailing list
> linux-kernel@lists.codethink.co.uk
> https://ducie-dc1.codethink.co.uk/cgi-bin/mailman/listinfo/linux-kernel
>
Sergei Shtylyov March 10, 2015, 8:03 p.m. UTC | #5
Hello.

On 03/09/2015 11:50 AM, Ben Dooks wrote:

>>>> Currently we may silently read/write a register at offset 0.  Change
>>>> this to WARN and then ignore the write or read-back all-ones.

>>>> Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
>>>> Acked-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>

>>> While this may be a good idea for debugging...

>>>> --- a/drivers/net/ethernet/renesas/sh_eth.h
>>>> +++ b/drivers/net/ethernet/renesas/sh_eth.h
>>>> @@ -543,19 +543,29 @@ static inline void sh_eth_soft_swap(char *src, int len)
>>>>   #endif
>>>>   }
>>>>
>>>> +#define SH_ETH_OFFSET_INVALID	((u16) ~0)
>>>> +
>>>>   static inline void sh_eth_write(struct net_device *ndev, u32 data,
>>>>   				int enum_index)
>>>>   {
>>>>   	struct sh_eth_private *mdp = netdev_priv(ndev);

> does de-referencing this each time make a difference? Looks like

   It's not a dereference, it's just a pointer addition.

> it would have been easier to pass an "struct sh_eth_private" instead
> of the "struct net_device *ndev"

    Hm, maybe...

>>>> +	u16 offset = mdp->reg_offset[enum_index];
>>>> +
>>>> +	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
>>>> +		return;

> You could cange the mdp->reg_offset to an mdp->reg_pointer and make
> any invalid registers a NULL. This would at-least make it fail on an
> invalid access.

    Interesting idea...

WBR, Sergei

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 4169f93b5c3c..e21f8ce609cd 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -52,7 +52,12 @@ 
 		NETIF_MSG_RX_ERR| \
 		NETIF_MSG_TX_ERR)
 
+#define SH_ETH_OFFSET_DEFAULTS			\
+	[0 ... SH_ETH_MAX_REGISTER_OFFSET - 1] = SH_ETH_OFFSET_INVALID
+
 static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
+	SH_ETH_OFFSET_DEFAULTS,
+
 	[EDSR]		= 0x0000,
 	[EDMR]		= 0x0400,
 	[EDTRR]		= 0x0408,
@@ -151,6 +156,8 @@  static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
 };
 
 static const u16 sh_eth_offset_fast_rz[SH_ETH_MAX_REGISTER_OFFSET] = {
+	SH_ETH_OFFSET_DEFAULTS,
+
 	[EDSR]		= 0x0000,
 	[EDMR]		= 0x0400,
 	[EDTRR]		= 0x0408,
@@ -210,6 +217,8 @@  static const u16 sh_eth_offset_fast_rz[SH_ETH_MAX_REGISTER_OFFSET] = {
 };
 
 static const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = {
+	SH_ETH_OFFSET_DEFAULTS,
+
 	[ECMR]		= 0x0300,
 	[RFLR]		= 0x0308,
 	[ECSR]		= 0x0310,
@@ -256,6 +265,8 @@  static const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = {
 };
 
 static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
+	SH_ETH_OFFSET_DEFAULTS,
+
 	[ECMR]		= 0x0100,
 	[RFLR]		= 0x0108,
 	[ECSR]		= 0x0110,
@@ -308,6 +319,8 @@  static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
 };
 
 static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
+	SH_ETH_OFFSET_DEFAULTS,
+
 	[EDMR]		= 0x0000,
 	[EDTRR]		= 0x0004,
 	[EDRRR]		= 0x0008,
@@ -1541,7 +1554,8 @@  static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
 	/* If we don't need to check status, don't. -KDU */
 	if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) {
 		/* fix the values for the next receiving if RDE is set */
-		if (intr_status & EESR_RDE && mdp->reg_offset[RDFAR] != 0) {
+		if (intr_status & EESR_RDE &&
+		    mdp->reg_offset[RDFAR] != SH_ETH_OFFSET_INVALID) {
 			u32 count = (sh_eth_read(ndev, RDFAR) -
 				     sh_eth_read(ndev, RDLAR)) >> 4;
 
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 259d03f353e1..33a360c4fd10 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -543,19 +543,29 @@  static inline void sh_eth_soft_swap(char *src, int len)
 #endif
 }
 
+#define SH_ETH_OFFSET_INVALID	((u16) ~0)
+
 static inline void sh_eth_write(struct net_device *ndev, u32 data,
 				int enum_index)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
+	u16 offset = mdp->reg_offset[enum_index];
+
+	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
+		return;
 
-	iowrite32(data, mdp->addr + mdp->reg_offset[enum_index]);
+	iowrite32(data, mdp->addr + offset);
 }
 
 static inline u32 sh_eth_read(struct net_device *ndev, int enum_index)
 {
 	struct sh_eth_private *mdp = netdev_priv(ndev);
+	u16 offset = mdp->reg_offset[enum_index];
+
+	if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
+		return ~0U;
 
-	return ioread32(mdp->addr + mdp->reg_offset[enum_index]);
+	return ioread32(mdp->addr + offset);
 }
 
 static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp,