diff options
| author | Joe Perches <joe@perches.com> | 2013-12-05 17:54:38 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-12-06 16:37:43 -0500 |
| commit | 0d74c42f788caf3cad727c61c490d9459bc8918b (patch) | |
| tree | 6eaff61e95e9efd14e85d2c8bb159ec5ff3b2898 /include/linux | |
| parent | 5cc208becb10ca271d8a3299a09a5449490c7591 (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.h | 51 |
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 | */ | ||
| 221 | static 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 | */ |
| 237 | static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2) | 223 | static 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 | ||
| 242 | static 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) | |||
| 265 | static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], | 252 | static 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 |
