aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorJoe Perches <joe@perches.com>2013-12-05 17:54:38 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-06 16:37:43 -0500
commit0d74c42f788caf3cad727c61c490d9459bc8918b (patch)
tree6eaff61e95e9efd14e85d2c8bb159ec5ff3b2898 /include/linux
parent5cc208becb10ca271d8a3299a09a5449490c7591 (diff)
ether_addr_equal: Optimize implementation, remove unused compare_ether_addr
Add a new check for CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS to reduce the number of or's used in the ether_addr_equal comparison to very slightly improve function performance. Simplify the ether_addr_equal_64bits implementation. Integrate and remove the zap_last_2bytes helper as it's now used only once. Remove the now unused compare_ether_addr function. Update the unaligned-memory-access documentation to remove the compare_ether_addr description and show how unaligned accesses could occur with ether_addr_equal. Signed-off-by: Joe Perches <joe@perches.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/etherdevice.h51
1 files changed, 18 insertions, 33 deletions
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index fc4a9aa7dd82..3526e819d7ae 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -26,6 +26,7 @@
26#include <linux/netdevice.h> 26#include <linux/netdevice.h>
27#include <linux/random.h> 27#include <linux/random.h>
28#include <asm/unaligned.h> 28#include <asm/unaligned.h>
29#include <asm/bitsperlong.h>
29 30
30#ifdef __KERNEL__ 31#ifdef __KERNEL__
31__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); 32__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
@@ -211,40 +212,26 @@ static inline void eth_hw_addr_inherit(struct net_device *dst,
211} 212}
212 213
213/** 214/**
214 * compare_ether_addr - Compare two Ethernet addresses
215 * @addr1: Pointer to a six-byte array containing the Ethernet address
216 * @addr2: Pointer other six-byte array containing the Ethernet address
217 *
218 * Compare two Ethernet addresses, returns 0 if equal, non-zero otherwise.
219 * Unlike memcmp(), it doesn't return a value suitable for sorting.
220 */
221static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2)
222{
223 const u16 *a = (const u16 *) addr1;
224 const u16 *b = (const u16 *) addr2;
225
226 BUILD_BUG_ON(ETH_ALEN != 6);
227 return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
228}
229
230/**
231 * ether_addr_equal - Compare two Ethernet addresses 215 * ether_addr_equal - Compare two Ethernet addresses
232 * @addr1: Pointer to a six-byte array containing the Ethernet address 216 * @addr1: Pointer to a six-byte array containing the Ethernet address
233 * @addr2: Pointer other six-byte array containing the Ethernet address 217 * @addr2: Pointer other six-byte array containing the Ethernet address
234 * 218 *
235 * Compare two Ethernet addresses, returns true if equal 219 * Compare two Ethernet addresses, returns true if equal
220 *
221 * Please note: addr1 & addr2 must both be aligned to u16.
236 */ 222 */
237static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2) 223static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2)
238{ 224{
239 return !compare_ether_addr(addr1, addr2); 225#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
240} 226 u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) |
227 ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4)));
241 228
242static inline unsigned long zap_last_2bytes(unsigned long value) 229 return fold == 0;
243{
244#ifdef __BIG_ENDIAN
245 return value >> 16;
246#else 230#else
247 return value << 16; 231 const u16 *a = (const u16 *)addr1;
232 const u16 *b = (const u16 *)addr2;
233
234 return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0;
248#endif 235#endif
249} 236}
250 237
@@ -265,16 +252,14 @@ static inline unsigned long zap_last_2bytes(unsigned long value)
265static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], 252static inline bool ether_addr_equal_64bits(const u8 addr1[6+2],
266 const u8 addr2[6+2]) 253 const u8 addr2[6+2])
267{ 254{
268#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 255#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
269 unsigned long fold = ((*(unsigned long *)addr1) ^ 256 u64 fold = (*(const u64 *)addr1) ^ (*(const u64 *)addr2);
270 (*(unsigned long *)addr2));
271
272 if (sizeof(fold) == 8)
273 return zap_last_2bytes(fold) == 0;
274 257
275 fold |= zap_last_2bytes((*(unsigned long *)(addr1 + 4)) ^ 258#ifdef __BIG_ENDIAN
276 (*(unsigned long *)(addr2 + 4))); 259 return (fold >> 16) == 0;
277 return fold == 0; 260#else
261 return (fold << 16) == 0;
262#endif
278#else 263#else
279 return ether_addr_equal(addr1, addr2); 264 return ether_addr_equal(addr1, addr2);
280#endif 265#endif