Re: [RFC][PATCH] apparent big-endian bugs in dwc-xlgmac

2017-12-10 Thread Jie Deng
On 2017/12/11 13:38, Al Viro wrote:

> On Mon, Dec 11, 2017 at 05:05:20AM +, Al Viro wrote:
>
>> What for?  Sure, this variant will work, but why bother with
>>  a = le32_to_cpu(b);
>>  (cpu_to_le32(a) & ) | 
>> and how is that better than
>>  (b & ...) | ...
>>
>> IDGI...  Mind you, I'm not sure if there is any point keeping _var in that 
>> thing,
>> seeing that we use var only once - might be better off with
>>  ((var) & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) |\
>>  cpu_to_le32(_val);  \
> FWIW, seeing how many drivers end up open-coding that, I'm rather tempted to
> add to linux/bitops.h or linux/byteorder/generic.h the following:
>
> static inline __le16 le16_replace_bits(__le16 old, u16 v, int bit, int size)
> {
>   __le16 mask = cpu_to_le16(GENMASK(bit + size - 1, bit));
>   return (old & ~mask) | (cpu_to_le16(v << bit) & mask);
> }
>
> static inline __le32 le32_replace_bits(__le32 old, u32 v, int bit, int size)
> {
>   __le32 mask = cpu_to_le32(GENMASK(bit + size - 1, bit));
>   return (old & ~mask) | (cpu_to_le32(v << bit) & mask);
> }
>
> static inline __le64 le64_replace_bits(__le64 old, u64 v, int bit, int size)
> {
>   __le64 mask = cpu_to_le64(GENMASK_ULL(bit + size - 1, bit));
>   return (old & ~mask) | (cpu_to_le64(v << bit) & mask);
> }
>
> static inline __be16 be16_replace_bits(__be16 old, u16 v, int bit, int size)
> {
>   __be16 mask = cpu_to_be16(GENMASK(bit + size - 1, bit));
>   return (old & ~mask) | (cpu_to_be16(v << bit) & mask);
> }
>
> static inline __be32 be32_replace_bits(__be32 old, u32 v, int bit, int size)
> {
>   __be32 mask = cpu_to_be32(GENMASK(bit + size - 1, bit));
>   return (old & ~mask) | (cpu_to_be32(v << bit) & mask);
> }
>
> static inline __be64 be64_replace_bits(__be64 old, u64 v, int bit, int size)
> {
>   __be64 mask = cpu_to_be64(GENMASK_ULL(bit + size - 1, bit));
>   return (old & ~mask) | (cpu_to_be64(v << bit) & mask);
> }
>
> static inline u16 le16_get_bits(__le16 v, int bit, int size)
> {
>   return (le16_to_cpu(v) >> bit) & (BIT(size) - 1);
> }
>
> static inline u32 le32_get_bits(__le32 v, int bit, int size)
> {
>   return (le32_to_cpu(v) >> bit) & (BIT(size) - 1);
> }
>
> static inline u64 le64_get_bits(__le64 v, int bit, int size)
> {
>   return (le64_to_cpu(v) >> bit) & (BIT_ULL(size) - 1);
> }
>
> static inline u16 be16_get_bits(__be16 v, int bit, int size)
> {
>   return (be16_to_cpu(v) >> bit) & (BIT(size) - 1);
> }
>
> static inline u32 be32_get_bits(__be32 v, int bit, int size)
> {
>   return (be32_to_cpu(v) >> bit) & (BIT(size) - 1);
> }
>
> static inline u64 be64_get_bits(__be64 v, int bit, int size)
> {
>   return (be64_to_cpu(v) >> bit) & (BIT_ULL(size) - 1);
> }
>
> and let drivers use those...
Sounds good. As a driver developer, I'm happy to see this.


Re: [RFC][PATCH] apparent big-endian bugs in dwc-xlgmac

2017-12-10 Thread Jie Deng
On 2017/12/11 13:05, Al Viro wrote:

> On Mon, Dec 11, 2017 at 12:33:42PM +0800, Jie Deng wrote:
>> Hi AI Viro,
>>> @@ -125,8 +125,8 @@
>>> typeof(len) _len = (len);   \
>>> typeof(val) _val = (val);   \
>>> _val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos); \
>>> -   _var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; \
>>> -   cpu_to_le32(_var);  \
>>> +   (_var & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) | \
>>> +   cpu_to_le32(_val);  \
>>>  })
>>>  
>>>  struct xlgmac_pdata;
>> Make sense.  But I think what you want is fix as follows. Right ?
>>
>> @@ -125,8 +125,8 @@
>>  typeof(len) _len = (len);   
>> \
>> -typeof(val) _val = (val);   
>> \
>> +   u32 _var = le32_to_cpu((var));   
>>\
>> _val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos);  
>> \
>> -_var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; 
>> \
>> -cpu_to_le32(_var);  
>> \
>> +(cpu_to_le32(_var) & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) |
>> \
>> +cpu_to_le32(_val);  
>> \
>>  })
> What for?  Sure, this variant will work, but why bother with
>   a = le32_to_cpu(b);
>   (cpu_to_le32(a) & ) | 
> and how is that better than
>   (b & ...) | ...
>
> IDGI...  Mind you, I'm not sure if there is any point keeping _var in that 
> thing,
> seeing that we use var only once - might be better off with
>   ((var) & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) |\
>   cpu_to_le32(_val);  \
I agree. Could you please send the patch with this better fix ?


Re: [RFC][PATCH] apparent big-endian bugs in dwc-xlgmac

2017-12-10 Thread Al Viro
On Mon, Dec 11, 2017 at 05:05:20AM +, Al Viro wrote:

> What for?  Sure, this variant will work, but why bother with
>   a = le32_to_cpu(b);
>   (cpu_to_le32(a) & ) | 
> and how is that better than
>   (b & ...) | ...
> 
> IDGI...  Mind you, I'm not sure if there is any point keeping _var in that 
> thing,
> seeing that we use var only once - might be better off with
>   ((var) & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) |\
>   cpu_to_le32(_val);  \

FWIW, seeing how many drivers end up open-coding that, I'm rather tempted to
add to linux/bitops.h or linux/byteorder/generic.h the following:

static inline __le16 le16_replace_bits(__le16 old, u16 v, int bit, int size)
{
__le16 mask = cpu_to_le16(GENMASK(bit + size - 1, bit));
return (old & ~mask) | (cpu_to_le16(v << bit) & mask);
}

static inline __le32 le32_replace_bits(__le32 old, u32 v, int bit, int size)
{
__le32 mask = cpu_to_le32(GENMASK(bit + size - 1, bit));
return (old & ~mask) | (cpu_to_le32(v << bit) & mask);
}

static inline __le64 le64_replace_bits(__le64 old, u64 v, int bit, int size)
{
__le64 mask = cpu_to_le64(GENMASK_ULL(bit + size - 1, bit));
return (old & ~mask) | (cpu_to_le64(v << bit) & mask);
}

static inline __be16 be16_replace_bits(__be16 old, u16 v, int bit, int size)
{
__be16 mask = cpu_to_be16(GENMASK(bit + size - 1, bit));
return (old & ~mask) | (cpu_to_be16(v << bit) & mask);
}

static inline __be32 be32_replace_bits(__be32 old, u32 v, int bit, int size)
{
__be32 mask = cpu_to_be32(GENMASK(bit + size - 1, bit));
return (old & ~mask) | (cpu_to_be32(v << bit) & mask);
}

static inline __be64 be64_replace_bits(__be64 old, u64 v, int bit, int size)
{
__be64 mask = cpu_to_be64(GENMASK_ULL(bit + size - 1, bit));
return (old & ~mask) | (cpu_to_be64(v << bit) & mask);
}

static inline u16 le16_get_bits(__le16 v, int bit, int size)
{
return (le16_to_cpu(v) >> bit) & (BIT(size) - 1);
}

static inline u32 le32_get_bits(__le32 v, int bit, int size)
{
return (le32_to_cpu(v) >> bit) & (BIT(size) - 1);
}

static inline u64 le64_get_bits(__le64 v, int bit, int size)
{
return (le64_to_cpu(v) >> bit) & (BIT_ULL(size) - 1);
}

static inline u16 be16_get_bits(__be16 v, int bit, int size)
{
return (be16_to_cpu(v) >> bit) & (BIT(size) - 1);
}

static inline u32 be32_get_bits(__be32 v, int bit, int size)
{
return (be32_to_cpu(v) >> bit) & (BIT(size) - 1);
}

static inline u64 be64_get_bits(__be64 v, int bit, int size)
{
return (be64_to_cpu(v) >> bit) & (BIT_ULL(size) - 1);
}

and let drivers use those...


Re: [RFC][PATCH] apparent big-endian bugs in dwc-xlgmac

2017-12-10 Thread Al Viro
On Mon, Dec 11, 2017 at 12:33:42PM +0800, Jie Deng wrote:
> Hi AI Viro,
> > @@ -125,8 +125,8 @@
> > typeof(len) _len = (len);   \
> > typeof(val) _val = (val);   \
> > _val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos); \
> > -   _var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; \
> > -   cpu_to_le32(_var);  \
> > +   (_var & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) | \
> > +   cpu_to_le32(_val);  \
> >  })
> >  
> >  struct xlgmac_pdata;
> 
> Make sense.  But I think what you want is fix as follows. Right ?
> 
> @@ -125,8 +125,8 @@
>   typeof(len) _len = (len);   
> \
> - typeof(val) _val = (val);   
> \
> +   u32 _var = le32_to_cpu((var));
>   \ 
> _val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos);   
> \
> - _var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; 
> \
> - cpu_to_le32(_var);  
> \
> + (cpu_to_le32(_var) & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) |
> \
> + cpu_to_le32(_val);  
> \
>  })

What for?  Sure, this variant will work, but why bother with
a = le32_to_cpu(b);
(cpu_to_le32(a) & ) | 
and how is that better than
(b & ...) | ...

IDGI...  Mind you, I'm not sure if there is any point keeping _var in that 
thing,
seeing that we use var only once - might be better off with
((var) & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) |\
cpu_to_le32(_val);  \


Re: [RFC][PATCH] apparent big-endian bugs in dwc-xlgmac

2017-12-10 Thread Jie Deng
Hi AI Viro,


On 2017/12/10 12:53, Al Viro wrote:
> In xlgmac_dev_xmit():
>
> /* Mark it as a CONTEXT descriptor */
> dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE(
> dma_desc->desc3,
> TX_CONTEXT_DESC3_CTXT_POS,
> TX_CONTEXT_DESC3_CTXT_LEN,
> 1);
>
>
>
> Looking at XLGMAC_SET_REG_BITS_LE() we see this:
> #define XLGMAC_SET_REG_BITS_LE(var, pos, len, val) ({   \
> typeof(var) _var = (var);   \
> typeof(pos) _pos = (pos);   \
> typeof(len) _len = (len);   \
> typeof(val) _val = (val);   \
> _val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos); \
> _var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; \
> cpu_to_le32(_var);  \
> })
>
> That thing assumes var to be host-endian and has a little-endian result.
> Unfortunately, we feed it a little-endian and store the result back into
> the same place.  That might work if the original values *was* host-endian
> and we wanted to end up with little-endian.  However, that is immediately
> followed by
> /* Indicate this descriptor contains the MSS */
> dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE(
> dma_desc->desc3,
> TX_CONTEXT_DESC3_TCMSSV_POS,
> TX_CONTEXT_DESC3_TCMSSV_LEN,
> 1);
>
> where we operate on the now definitely little-endian value.  That really
> can't be right.  I don't have the hardware in question, so I can't test
> that, but it smells like this needs something like diff below, making
> XLGMAC_SET_REG_BITS_LE take le32 and return le32.  GET side of things
> is le32 -> u32; definition looks correct, but slightly misannotated.
>
> Signed-off-by: Al Viro 
> ---
> diff --git a/drivers/net/ethernet/synopsys/dwc-xlgmac.h 
> b/drivers/net/ethernet/synopsys/dwc-xlgmac.h
> index cab3e40a86b9..e95c4c250e16 100644
> --- a/drivers/net/ethernet/synopsys/dwc-xlgmac.h
> +++ b/drivers/net/ethernet/synopsys/dwc-xlgmac.h
> @@ -106,7 +106,7 @@
>  #define XLGMAC_GET_REG_BITS_LE(var, pos, len) ({ \
>   typeof(pos) _pos = (pos);   \
>   typeof(len) _len = (len);   \
> - typeof(var) _var = le32_to_cpu((var));  \
> + u32 _var = le32_to_cpu((var));  \
>   ((_var) & GENMASK(_pos + _len - 1, _pos)) >> (_pos);\
>  })
>  
> @@ -125,8 +125,8 @@
>   typeof(len) _len = (len);   \
>   typeof(val) _val = (val);   \
>   _val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos); \
> - _var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; \
> - cpu_to_le32(_var);  \
> + (_var & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) | \
> + cpu_to_le32(_val);  \
>  })
>  
>  struct xlgmac_pdata;

Make sense.  But I think what you want is fix as follows. Right ?

@@ -125,8 +125,8 @@
typeof(len) _len = (len);   
\
-   typeof(val) _val = (val);   
\
+   u32 _var = le32_to_cpu((var));  
\   
_val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos); 
\
-   _var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; 
\
-   cpu_to_le32(_var);  
\
+   (cpu_to_le32(_var) & ~cpu_to_le32(GENMASK(_pos + _len - 1, _pos))) |
\
+   cpu_to_le32(_val);  
\
 })