enc28j60: reduce the number of spi transfers in enc28j60_set_bank()
authorBaruch Siach <baruch@tkos.co.il>
Fri, 19 Dec 2008 03:39:14 +0000 (19:39 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 19 Dec 2008 06:27:39 +0000 (22:27 -0800)
A major source of overhead in the enc28j60 driver is the SPI transfers. Each
SPI transfer entails two kernel thread context switches. One major source of
SPI transfers is the enc28j60_set_bank() functions which runs before every
register access. This patch reduces the number of SPI transfers that
enc28j60_set_bank() performs in two ways:

  1. removes unnecessary bank switch for the registers that are present in all
 banks

  2. when switching from banks 0 or 3 to banks 1 or 2 (i.e. only one bit
 changes) enc28j60_set_bank() does only one SPI transfer instead of two

According to my tests these changes reduce the number of SPI transfers in
about 25%.

Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/enc28j60.c

index 535e14094971b6e0cba6411d9edc906020cec938..b0ef46c51a9d556069c38ed97d0cdf3086555d6f 100644 (file)
@@ -196,16 +196,32 @@ static void enc28j60_soft_reset(struct enc28j60_net *priv)
  */
 static void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr)
 {
-       if ((addr & BANK_MASK) != priv->bank) {
-               u8 b = (addr & BANK_MASK) >> 5;
+       u8 b = (addr & BANK_MASK) >> 5;
 
-               if (b != (ECON1_BSEL1 | ECON1_BSEL0))
+       /* These registers (EIE, EIR, ESTAT, ECON2, ECON1)
+        * are present in all banks, no need to switch bank
+        */
+       if (addr >= EIE && addr <= ECON1)
+               return;
+
+       /* Clear or set each bank selection bit as needed */
+       if ((b & ECON1_BSEL0) != (priv->bank & ECON1_BSEL0)) {
+               if (b & ECON1_BSEL0)
+                       spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1,
+                                       ECON1_BSEL0);
+               else
+                       spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,
+                                       ECON1_BSEL0);
+       }
+       if ((b & ECON1_BSEL1) != (priv->bank & ECON1_BSEL1)) {
+               if (b & ECON1_BSEL1)
+                       spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1,
+                                       ECON1_BSEL1);
+               else
                        spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,
-                                    ECON1_BSEL1 | ECON1_BSEL0);
-               if (b != 0)
-                       spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, b);
-               priv->bank = (addr & BANK_MASK);
+                                       ECON1_BSEL1);
        }
+       priv->bank = b;
 }
 
 /*