dsa: mv88e6xxx: Optimise atu_get
authorAndrew Lunn <andrew@lunn.ch>
Wed, 4 Jan 2017 18:56:24 +0000 (19:56 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 4 Jan 2017 21:34:34 +0000 (16:34 -0500)
Lookup in the ATU can be performed starting from a given MAC
address. This is faster than starting with the first possible MAC
address and iterating all entries.

Entries are returned in numeric order. So if the MAC address returned
is bigger than what we are searching for, we know it is not in the
ATU.

Using the benchmark provided by Volodymyr Bendiuga
<volodymyr.bendiuga@gmail.com>,

https://www.spinics.net/lists/netdev/msg411550.html

on an Marvell Armada 370 RD, the test to add a number of static fdb
entries went from 1.616531 seconds to 0.312052 seconds.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/mv88e6xxx/chip.c
include/linux/etherdevice.h

index b5f0e1ec864d838f7c5dacb0d08e82861927efb5..676b0e2ad221faeab93ee5f49d6d7f137287aee8 100644 (file)
@@ -2023,7 +2023,8 @@ static int mv88e6xxx_atu_get(struct mv88e6xxx_chip *chip, int fid,
        struct mv88e6xxx_atu_entry next;
        int err;
 
-       eth_broadcast_addr(next.mac);
+       memcpy(next.mac, addr, ETH_ALEN);
+       eth_addr_dec(next.mac);
 
        err = _mv88e6xxx_atu_mac_write(chip, next.mac);
        if (err)
@@ -2041,7 +2042,7 @@ static int mv88e6xxx_atu_get(struct mv88e6xxx_chip *chip, int fid,
                        *entry = next;
                        return 0;
                }
-       } while (!is_broadcast_ether_addr(next.mac));
+       } while (ether_addr_greater(addr, next.mac));
 
        memset(entry, 0, sizeof(*entry));
        entry->fid = fid;
index 6fec9e81bd70d9e0646a240e09b2395f74fd6f79..42add77ae47d7ef7f0203949f42a89338f05e97e 100644 (file)
@@ -396,6 +396,66 @@ static inline bool ether_addr_equal_masked(const u8 *addr1, const u8 *addr2,
        return true;
 }
 
+/**
+ * ether_addr_to_u64 - Convert an Ethernet address into a u64 value.
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Return a u64 value of the address
+ */
+static inline u64 ether_addr_to_u64(const u8 *addr)
+{
+       u64 u = 0;
+       int i;
+
+       for (i = 0; i < ETH_ALEN; i++)
+               u = u << 8 | addr[i];
+
+       return u;
+}
+
+/**
+ * u64_to_ether_addr - Convert a u64 to an Ethernet address.
+ * @u: u64 to convert to an Ethernet MAC address
+ * @addr: Pointer to a six-byte array to contain the Ethernet address
+ */
+static inline void u64_to_ether_addr(u64 u, u8 *addr)
+{
+       int i;
+
+       for (i = ETH_ALEN - 1; i >= 0; i--) {
+               addr[i] = u & 0xff;
+               u = u >> 8;
+       }
+}
+
+/**
+ * eth_addr_dec - Decrement the given MAC address
+ *
+ * @addr: Pointer to a six-byte array containing Ethernet address to decrement
+ */
+static inline void eth_addr_dec(u8 *addr)
+{
+       u64 u = ether_addr_to_u64(addr);
+
+       u--;
+       u64_to_ether_addr(u, addr);
+}
+
+/**
+ * ether_addr_greater - Compare two Ethernet addresses
+ * @addr1: Pointer to a six-byte array containing the Ethernet address
+ * @addr2: Pointer other six-byte array containing the Ethernet address
+ *
+ * Compare two Ethernet addresses, returns true addr1 is greater than addr2
+ */
+static inline bool ether_addr_greater(const u8 *addr1, const u8 *addr2)
+{
+       u64 u1 = ether_addr_to_u64(addr1);
+       u64 u2 = ether_addr_to_u64(addr2);
+
+       return u1 > u2;
+}
+
 /**
  * is_etherdev_addr - Tell if given Ethernet address belongs to the device.
  * @dev: Pointer to a device structure