Message ID | 20190204164213.30727-2-thierry.reding@gmail.com |
---|---|
State | Changes Requested |
Delegated to: | David Miller |
Headers | show |
Series | [v2,1/2] r8169: Load MAC address from device tree if present | expand |
On Mon, Feb 04, 2019 at 05:42:13PM +0100, Thierry Reding wrote: > From: Thierry Reding <treding@nvidia.com> > > Read MAC address 32-bit at a time and manually extract the individual > bytes. This avoids pointer aliasing and gives the compiler a better > chance of optimizing the operation. > > Suggested-by: Andrew Lunn <andrew@lunn.ch> > Signed-off-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Andrew
On 04.02.2019 17:42, Thierry Reding wrote: > From: Thierry Reding <treding@nvidia.com> > > Read MAC address 32-bit at a time and manually extract the individual > bytes. This avoids pointer aliasing and gives the compiler a better > chance of optimizing the operation. > > Suggested-by: Andrew Lunn <andrew@lunn.ch> > Signed-off-by: Thierry Reding <treding@nvidia.com> > --- > Applies to net-next. > > I tested this on a Jetson TX2 with an add-in Realtek ethernet card that > has a properly programmed OTP to verify that I got the endianess right. > Seems like everything works and the device behaves the same with or > without this patch. > > drivers/net/ethernet/realtek/r8169.c | 15 ++++++++++++--- > 1 file changed, 12 insertions(+), 3 deletions(-) > > diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c > index 501891be7c56..192fbb36bc9f 100644 > --- a/drivers/net/ethernet/realtek/r8169.c > +++ b/drivers/net/ethernet/realtek/r8169.c > @@ -7113,12 +7113,21 @@ static int rtl_alloc_irq(struct rtl8169_private *tp) > static void rtl_read_mac_address(struct rtl8169_private *tp, > u8 mac_addr[ETH_ALEN]) > { > + u32 value; > + > /* Get MAC address */ > switch (tp->mac_version) { > case RTL_GIGA_MAC_VER_35 ... RTL_GIGA_MAC_VER_38: > case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: > - *(u32 *)&mac_addr[0] = rtl_eri_read(tp, 0xe0, ERIAR_EXGMAC); > - *(u16 *)&mac_addr[4] = rtl_eri_read(tp, 0xe4, ERIAR_EXGMAC); > + value = rtl_eri_read(tp, 0xe0, ERIAR_EXGMAC); > + mac_addr[0] = (value >> 0) & 0xff; > + mac_addr[1] = (value >> 8) & 0xff; > + mac_addr[2] = (value >> 16) & 0xff; > + mac_addr[3] = (value >> 24) & 0xff; > + > + value = rtl_eri_read(tp, 0xe4, ERIAR_EXGMAC); > + mac_addr[4] = (value >> 0) & 0xff; > + mac_addr[5] = (value >> 8) & 0xff; > break; > default: > break; > @@ -7316,7 +7325,7 @@ static int rtl_get_ether_clk(struct rtl8169_private *tp) > static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) > { > const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; > - u8 mac_addr[ETH_ALEN] __aligned(4) = {}; > + u8 mac_addr[ETH_ALEN] = {}; > struct rtl8169_private *tp; > struct net_device *dev; > int chipset, region, i; > I just have one concern / question: After this there's a call to is_valid_ether_addr(mac_addr) and kernel-doc of is_valid_ether_addr() states that argument must be u16-aligned. AFAIK that's not guaranteed for a byte array. Heiner
From: Thierry Reding <thierry.reding@gmail.com> Date: Mon, 4 Feb 2019 17:42:13 +0100 > @@ -7316,7 +7325,7 @@ static int rtl_get_ether_clk(struct rtl8169_private *tp) > static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) > { > const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; > - u8 mac_addr[ETH_ALEN] __aligned(4) = {}; > + u8 mac_addr[ETH_ALEN] = {}; > struct rtl8169_private *tp; I agree with Heiner, you have to provide at least 2 byte alignment for this buffer due to the reasons he stated.
On Mon, 2019-02-04 at 19:20 -0800, David Miller wrote: > From: Thierry Reding <thierry.reding@gmail.com> > Date: Mon, 4 Feb 2019 17:42:13 +0100 > > > @@ -7316,7 +7325,7 @@ static int rtl_get_ether_clk(struct rtl8169_private *tp) > > static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) > > { > > const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; > > - u8 mac_addr[ETH_ALEN] __aligned(4) = {}; > > + u8 mac_addr[ETH_ALEN] = {}; > > struct rtl8169_private *tp; > > I agree with Heiner, you have to provide at least 2 byte alignment for this > buffer due to the reasons he stated. It's declared after a pointer so it is already is 2 byte aligned. A lot of drivers wouldn't work otherwise.
From: Joe Perches <joe@perches.com> Date: Tue, 05 Feb 2019 10:42:54 -0800 > On Mon, 2019-02-04 at 19:20 -0800, David Miller wrote: >> From: Thierry Reding <thierry.reding@gmail.com> >> Date: Mon, 4 Feb 2019 17:42:13 +0100 >> >> > @@ -7316,7 +7325,7 @@ static int rtl_get_ether_clk(struct rtl8169_private *tp) >> > static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) >> > { >> > const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; >> > - u8 mac_addr[ETH_ALEN] __aligned(4) = {}; >> > + u8 mac_addr[ETH_ALEN] = {}; >> > struct rtl8169_private *tp; >> >> I agree with Heiner, you have to provide at least 2 byte alignment for this >> buffer due to the reasons he stated. > > It's declared after a pointer so it is already is 2 byte aligned. > > A lot of drivers wouldn't work otherwise. That's assuming a lot about what the compiler will do when it allocates local variables to the stack. I want it _explicit_.
On Tue, 2019-02-05 at 11:14 -0800, David Miller wrote: > From: Joe Perches <joe@perches.com> > Date: Tue, 05 Feb 2019 10:42:54 -0800 > > > On Mon, 2019-02-04 at 19:20 -0800, David Miller wrote: > >> From: Thierry Reding <thierry.reding@gmail.com> > >> Date: Mon, 4 Feb 2019 17:42:13 +0100 > >> > >> > @@ -7316,7 +7325,7 @@ static int rtl_get_ether_clk(struct rtl8169_private *tp) > >> > static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) > >> > { > >> > const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; > >> > - u8 mac_addr[ETH_ALEN] __aligned(4) = {}; > >> > + u8 mac_addr[ETH_ALEN] = {}; > >> > struct rtl8169_private *tp; > >> > >> I agree with Heiner, you have to provide at least 2 byte alignment for this > >> buffer due to the reasons he stated. > > > > It's declared after a pointer so it is already is 2 byte aligned. > > > > A lot of drivers wouldn't work otherwise. > > That's assuming a lot about what the compiler will do when nit allocates > local variables to the stack. It's also assuming what a compiler will do when it defines a struct. > I want it _explicit_. Your choice, but there are a _lot_ of existing uses and I think requiring it is as senseless as requiring void * arithmetic to be cast to char * as gcc and clang already do not add padding after a pointer.
On 02/05/2019 10:42 AM, Joe Perches wrote: > > It's declared after a pointer so it is already is 2 byte aligned. > > A lot of drivers wouldn't work otherwise. Maybe these drivers are only used on arches where this does not matter.
On Tue, 2019-02-05 at 12:04 -0800, Eric Dumazet wrote: > > On 02/05/2019 10:42 AM, Joe Perches wrote: > > It's declared after a pointer so it is already is 2 byte aligned. > > > > A lot of drivers wouldn't work otherwise. > > Maybe these drivers are only used on arches where this does not matter. Possible. I had only grepped through the sources looking for declarations using: $ git grep -B1 '\[ETH_ALEN\];' -- '*.c' | grep -A1 '\*' It's quite a few files in net/ too btw. I still think adding __align(<even#>) is unnecessary here unless it follows something like a bool or a u8.
On 02/05/2019 12:18 PM, Joe Perches wrote: > I still think adding __align(<even#>) is unnecessary here unless > it follows something like a bool or a u8. This would be some historical side effect, and we do not want to rely on that. A security feature could in fact ask a compiler to perform random shuffling of automatic variables. ( a la __randomize_layout )
On 05.02.2019 21:18, Joe Perches wrote: > On Tue, 2019-02-05 at 12:04 -0800, Eric Dumazet wrote: >> >> On 02/05/2019 10:42 AM, Joe Perches wrote: >>> It's declared after a pointer so it is already is 2 byte aligned. >>> >>> A lot of drivers wouldn't work otherwise. >> >> Maybe these drivers are only used on arches where this does not matter. > > Possible. > > I had only grepped through the sources looking for > declarations using: > > $ git grep -B1 '\[ETH_ALEN\];' -- '*.c' | grep -A1 '\*' > > It's quite a few files in net/ too btw. > > I still think adding __align(<even#>) is unnecessary here unless > it follows something like a bool or a u8. > > I there's such a controversy, then it may be better to stay with the current code, or?
On Tue, Feb 05, 2019 at 11:19:04AM -0800, Joe Perches wrote: > On Tue, 2019-02-05 at 11:14 -0800, David Miller wrote: > > From: Joe Perches <joe@perches.com> > > Date: Tue, 05 Feb 2019 10:42:54 -0800 > > > > > On Mon, 2019-02-04 at 19:20 -0800, David Miller wrote: > > >> From: Thierry Reding <thierry.reding@gmail.com> > > >> Date: Mon, 4 Feb 2019 17:42:13 +0100 > > >> > > >> > @@ -7316,7 +7325,7 @@ static int rtl_get_ether_clk(struct rtl8169_private *tp) > > >> > static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) > > >> > { > > >> > const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; > > >> > - u8 mac_addr[ETH_ALEN] __aligned(4) = {}; > > >> > + u8 mac_addr[ETH_ALEN] = {}; > > >> > struct rtl8169_private *tp; > > >> > > >> I agree with Heiner, you have to provide at least 2 byte alignment for this > > >> buffer due to the reasons he stated. > > > > > > It's declared after a pointer so it is already is 2 byte aligned. > > > > > > A lot of drivers wouldn't work otherwise. > > > > That's assuming a lot about what the compiler will do when nit allocates > > local variables to the stack. > > It's also assuming what a compiler will do when > it defines a struct. This is not a structure member, it's a local variable. I'm not aware of any C norm requirement for ordering of local variables on the stack. After all, some of them might not be on the stack at all and use only registers or be optimized out completely. Michal Kubecek
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 501891be7c56..192fbb36bc9f 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -7113,12 +7113,21 @@ static int rtl_alloc_irq(struct rtl8169_private *tp) static void rtl_read_mac_address(struct rtl8169_private *tp, u8 mac_addr[ETH_ALEN]) { + u32 value; + /* Get MAC address */ switch (tp->mac_version) { case RTL_GIGA_MAC_VER_35 ... RTL_GIGA_MAC_VER_38: case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: - *(u32 *)&mac_addr[0] = rtl_eri_read(tp, 0xe0, ERIAR_EXGMAC); - *(u16 *)&mac_addr[4] = rtl_eri_read(tp, 0xe4, ERIAR_EXGMAC); + value = rtl_eri_read(tp, 0xe0, ERIAR_EXGMAC); + mac_addr[0] = (value >> 0) & 0xff; + mac_addr[1] = (value >> 8) & 0xff; + mac_addr[2] = (value >> 16) & 0xff; + mac_addr[3] = (value >> 24) & 0xff; + + value = rtl_eri_read(tp, 0xe4, ERIAR_EXGMAC); + mac_addr[4] = (value >> 0) & 0xff; + mac_addr[5] = (value >> 8) & 0xff; break; default: break; @@ -7316,7 +7325,7 @@ static int rtl_get_ether_clk(struct rtl8169_private *tp) static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; - u8 mac_addr[ETH_ALEN] __aligned(4) = {}; + u8 mac_addr[ETH_ALEN] = {}; struct rtl8169_private *tp; struct net_device *dev; int chipset, region, i;