Re: [PATCH] ibmveth: Fix more little endian issues
On Tue, 2013-12-24 at 12:55 +1100, Anton Blanchard wrote: The hypervisor expects MAC addresses passed in registers to be big endian u64. Create a helper function called ibmveth_encode_mac_addr which does the right thing in both big and little endian. We were storing the MAC address in a long in struct ibmveth_adapter. It's never used so remove it - we don't need another place in the driver where we create endian issues with MAC addresses. [...] @@ -523,10 +523,20 @@ retry: return rc; } +/* The hypervisor expects MAC addresses passed in registers to be + * big endian u64. + */ +static __be64 ibmveth_encode_mac_addr(char *mac) +{ + unsigned long encoded = 0; u64 + memcpy(((char *)encoded) + 2, mac, ETH_ALEN); + return cpu_to_be64(encoded); +} [...] So on big-endian systems the byte order of the result will be: 0 0 mac0 mac1 mac2 mac3 mac4 mac5 and on little-endian systems it's: mac5 mac4 mac3 mac2 mac1 mac0 0 0 It seems to me that 'encoded' is actually in big-endian order and this function returns the address in CPU order. So are you sure your explanation isn't backwards, because it looks to me like the driver was already holding the MAC address in big-endian order and perhaps the hypercall mechanism does a byte-swap when the guest is little-endian. Ben. -- Ben Hutchings, Staff Engineer, Solarflare Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked. ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH] ibmveth: Fix more little endian issues
On 23.12.2013, at 07:38, Anton Blanchard an...@samba.org wrote: Hi Alex, The ibmveth driver is memcpy()'ing the mac address between a variable (register) and memory. This assumes a certain endianness of the system, so let's make that implicit assumption work again. Nice catch! I don't like how the driver has two different methods for creating these MAC addresses, both without comments. How does this look? Heh - I didn't even realize those two places were doing the same thing. Obviously your patch is by far nicer. Reviewed-by: Alexander Graf ag...@suse.de Alex Anton -- The hypervisor expects MAC addresses passed in registers to be big endian u64. Create a helper function called ibmveth_encode_mac_addr which does the right thing in both big and little endian. We were storing the MAC address in a long in struct ibmveth_adapter. It's never used so remove it - we don't need another place in the driver where we create endian issues with MAC addresses. Reported-by: Alexander Graf ag...@suse.de Signed-off-by: Anton Blanchard an...@samba.org --- diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 952d795..044178b 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -523,6 +523,17 @@ retry: return rc; } +/* + * The hypervisor expects MAC addresses passed in registers to be + * big endian u64. + */ +static unsigned long ibmveth_encode_mac_addr(char *mac) +{ + unsigned long encoded = 0; + memcpy(((char *)encoded) + 2, mac, ETH_ALEN); + return cpu_to_be64(encoded); +} + static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev_priv(netdev); @@ -580,8 +591,7 @@ static int ibmveth_open(struct net_device *netdev) adapter-rx_queue.num_slots = rxq_entries; adapter-rx_queue.toggle = 1; - memcpy(mac_address, netdev-dev_addr, netdev-addr_len); - mac_address = mac_address 16; + mac_address = ibmveth_encode_mac_addr(netdev-dev_addr); rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter-rx_queue.queue_len; @@ -1184,8 +1194,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) /* add the addresses to the filter table */ netdev_for_each_mc_addr(ha, netdev) { /* add the multicast address to the filter table */ - unsigned long mcast_addr = 0; - memcpy(((char *)mcast_addr)+2, ha-addr, ETH_ALEN); + unsigned long mcast_addr; + mcast_addr = ibmveth_encode_mac_addr(ha-addr); lpar_rc = h_multicast_ctrl(adapter-vdev-unit_address, IbmVethMcastAddFilter, mcast_addr); @@ -1369,9 +1379,6 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) netif_napi_add(netdev, adapter-napi, ibmveth_poll, 16); - adapter-mac_addr = 0; - memcpy(adapter-mac_addr, mac_addr_p, ETH_ALEN); - netdev-irq = dev-irq; netdev-netdev_ops = ibmveth_netdev_ops; netdev-ethtool_ops = netdev_ethtool_ops; @@ -1380,7 +1387,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; netdev-features |= netdev-hw_features; - memcpy(netdev-dev_addr, adapter-mac_addr, netdev-addr_len); + memcpy(netdev-dev_addr, mac_addr_p, ETH_ALEN); for (i = 0; i IBMVETH_NUM_BUFF_POOLS; i++) { struct kobject *kobj = adapter-rx_buff_pool[i].kobj; diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index 84066ba..2c636cb 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -139,7 +139,6 @@ struct ibmveth_adapter { struct napi_struct napi; struct net_device_stats stats; unsigned int mcastFilterSize; -unsigned long mac_addr; void * buffer_list_addr; void * filter_list_addr; dma_addr_t buffer_list_dma; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH] ibmveth: Fix more little endian issues
On Mon, 2013-12-23 at 17:38 +1100, Anton Blanchard wrote: The hypervisor expects MAC addresses passed in registers to be big endian u64. So maybe use __be64 declarations? +static unsigned long ibmveth_encode_mac_addr(char *mac) static __be64 ibmveth_encode_mac_addr(const char *mac) ? etc... ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH] ibmveth: Fix more little endian issues
The hypervisor expects MAC addresses passed in registers to be big endian u64. Create a helper function called ibmveth_encode_mac_addr which does the right thing in both big and little endian. We were storing the MAC address in a long in struct ibmveth_adapter. It's never used so remove it - we don't need another place in the driver where we create endian issues with MAC addresses. Signed-off-by: Anton Blanchard an...@samba.org Reviewed-by: Alexander Graf ag...@suse.de --- v2: annotate with __be64 as suggested by Joe diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 952d795..bb9a631 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -497,7 +497,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) } static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter, -union ibmveth_buf_desc rxq_desc, u64 mac_address) + union ibmveth_buf_desc rxq_desc, __be64 mac_address) { int rc, try_again = 1; @@ -523,10 +523,20 @@ retry: return rc; } +/* The hypervisor expects MAC addresses passed in registers to be + * big endian u64. + */ +static __be64 ibmveth_encode_mac_addr(char *mac) +{ + unsigned long encoded = 0; + memcpy(((char *)encoded) + 2, mac, ETH_ALEN); + return cpu_to_be64(encoded); +} + static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev_priv(netdev); - u64 mac_address = 0; + __be64 mac_address = 0; int rxq_entries = 1; unsigned long lpar_rc; int rc; @@ -580,8 +590,7 @@ static int ibmveth_open(struct net_device *netdev) adapter-rx_queue.num_slots = rxq_entries; adapter-rx_queue.toggle = 1; - memcpy(mac_address, netdev-dev_addr, netdev-addr_len); - mac_address = mac_address 16; + mac_address = ibmveth_encode_mac_addr(netdev-dev_addr); rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter-rx_queue.queue_len; @@ -1184,8 +1193,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) /* add the addresses to the filter table */ netdev_for_each_mc_addr(ha, netdev) { /* add the multicast address to the filter table */ - unsigned long mcast_addr = 0; - memcpy(((char *)mcast_addr)+2, ha-addr, ETH_ALEN); + __be64 mcast_addr; + mcast_addr = ibmveth_encode_mac_addr(ha-addr); lpar_rc = h_multicast_ctrl(adapter-vdev-unit_address, IbmVethMcastAddFilter, mcast_addr); @@ -1369,9 +1378,6 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) netif_napi_add(netdev, adapter-napi, ibmveth_poll, 16); - adapter-mac_addr = 0; - memcpy(adapter-mac_addr, mac_addr_p, ETH_ALEN); - netdev-irq = dev-irq; netdev-netdev_ops = ibmveth_netdev_ops; netdev-ethtool_ops = netdev_ethtool_ops; @@ -1380,7 +1386,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; netdev-features |= netdev-hw_features; - memcpy(netdev-dev_addr, adapter-mac_addr, netdev-addr_len); + memcpy(netdev-dev_addr, mac_addr_p, ETH_ALEN); for (i = 0; i IBMVETH_NUM_BUFF_POOLS; i++) { struct kobject *kobj = adapter-rx_buff_pool[i].kobj; diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index 84066ba..2c636cb 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -139,7 +139,6 @@ struct ibmveth_adapter { struct napi_struct napi; struct net_device_stats stats; unsigned int mcastFilterSize; -unsigned long mac_addr; void * buffer_list_addr; void * filter_list_addr; dma_addr_t buffer_list_dma; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH] ibmveth: Fix more little endian issues
On Mon, 2013-12-23 at 06:52 -0800, Joe Perches wrote: On Mon, 2013-12-23 at 17:38 +1100, Anton Blanchard wrote: The hypervisor expects MAC addresses passed in registers to be big endian u64. So maybe use __be64 declarations? +static unsigned long ibmveth_encode_mac_addr(char *mac) static __be64 ibmveth_encode_mac_addr(const char *mac) A register value has no endianness. Only memory content does. Especially talking of a MAC address which is really a byte stream (Yes, our __beXX types used without a * are borderline, but we've got used to it). In fact I find the use of memcpy(((char *)encoded) + 2, mac, ETH_ALEN); Really gross :-) Yes it works with the added cpu_to_be64() but in that specific case, I think it would be nicer to simply load shift into position the 6 bytes and avoid the endianness issue completely. Cheers, Ben. ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH] ibmveth: Fix more little endian issues
The ibmveth driver is memcpy()'ing the mac address between a variable (register) and memory. This assumes a certain endianness of the system, so let's make that implicit assumption work again. This patch adds be64_to_cpu() calls to all places where the mac address gets memcpy()'ed into a local variable. Signed-off-by: Alexander Graf ag...@suse.de --- drivers/net/ethernet/ibm/ibmveth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 952d795..97f4ee96 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -581,7 +581,7 @@ static int ibmveth_open(struct net_device *netdev) adapter-rx_queue.toggle = 1; memcpy(mac_address, netdev-dev_addr, netdev-addr_len); - mac_address = mac_address 16; + mac_address = be64_to_cpu(mac_address) 16; rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter-rx_queue.queue_len; @@ -1186,6 +1186,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) /* add the multicast address to the filter table */ unsigned long mcast_addr = 0; memcpy(((char *)mcast_addr)+2, ha-addr, ETH_ALEN); + mcast_addr = cpu_to_be64(mcast_addr); lpar_rc = h_multicast_ctrl(adapter-vdev-unit_address, IbmVethMcastAddFilter, mcast_addr); -- 1.8.1.4 ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH] ibmveth: Fix more little endian issues
Hi Alex, The ibmveth driver is memcpy()'ing the mac address between a variable (register) and memory. This assumes a certain endianness of the system, so let's make that implicit assumption work again. Nice catch! I don't like how the driver has two different methods for creating these MAC addresses, both without comments. How does this look? Anton -- The hypervisor expects MAC addresses passed in registers to be big endian u64. Create a helper function called ibmveth_encode_mac_addr which does the right thing in both big and little endian. We were storing the MAC address in a long in struct ibmveth_adapter. It's never used so remove it - we don't need another place in the driver where we create endian issues with MAC addresses. Reported-by: Alexander Graf ag...@suse.de Signed-off-by: Anton Blanchard an...@samba.org --- diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 952d795..044178b 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -523,6 +523,17 @@ retry: return rc; } +/* + * The hypervisor expects MAC addresses passed in registers to be + * big endian u64. + */ +static unsigned long ibmveth_encode_mac_addr(char *mac) +{ + unsigned long encoded = 0; + memcpy(((char *)encoded) + 2, mac, ETH_ALEN); + return cpu_to_be64(encoded); +} + static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev_priv(netdev); @@ -580,8 +591,7 @@ static int ibmveth_open(struct net_device *netdev) adapter-rx_queue.num_slots = rxq_entries; adapter-rx_queue.toggle = 1; - memcpy(mac_address, netdev-dev_addr, netdev-addr_len); - mac_address = mac_address 16; + mac_address = ibmveth_encode_mac_addr(netdev-dev_addr); rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter-rx_queue.queue_len; @@ -1184,8 +1194,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) /* add the addresses to the filter table */ netdev_for_each_mc_addr(ha, netdev) { /* add the multicast address to the filter table */ - unsigned long mcast_addr = 0; - memcpy(((char *)mcast_addr)+2, ha-addr, ETH_ALEN); + unsigned long mcast_addr; + mcast_addr = ibmveth_encode_mac_addr(ha-addr); lpar_rc = h_multicast_ctrl(adapter-vdev-unit_address, IbmVethMcastAddFilter, mcast_addr); @@ -1369,9 +1379,6 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) netif_napi_add(netdev, adapter-napi, ibmveth_poll, 16); - adapter-mac_addr = 0; - memcpy(adapter-mac_addr, mac_addr_p, ETH_ALEN); - netdev-irq = dev-irq; netdev-netdev_ops = ibmveth_netdev_ops; netdev-ethtool_ops = netdev_ethtool_ops; @@ -1380,7 +1387,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; netdev-features |= netdev-hw_features; - memcpy(netdev-dev_addr, adapter-mac_addr, netdev-addr_len); + memcpy(netdev-dev_addr, mac_addr_p, ETH_ALEN); for (i = 0; i IBMVETH_NUM_BUFF_POOLS; i++) { struct kobject *kobj = adapter-rx_buff_pool[i].kobj; diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index 84066ba..2c636cb 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -139,7 +139,6 @@ struct ibmveth_adapter { struct napi_struct napi; struct net_device_stats stats; unsigned int mcastFilterSize; -unsigned long mac_addr; void * buffer_list_addr; void * filter_list_addr; dma_addr_t buffer_list_dma; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev