net/macb: fix ISR clear-on-write behavior only for some SoC
authorNicolas Ferre <nicolas.ferre@atmel.com>
Tue, 14 May 2013 03:00:16 +0000 (03:00 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 14 May 2013 20:04:02 +0000 (13:04 -0700)
Commit 749a2b6 (net/macb: clear tx/rx completion flags in ISR)
introduces clear-on-write on ISR register. This behavior is not always
implemented when using Cadence MACB/GEM and is breaking other platforms.
We are using the Design Configuration Register 1 information and a capability
property to actually activate this clear-on-write behavior on ISR.

Reported-by: Hein Tibosch <hein_tibosch@yahoo.es>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Tested-by: Hein Tibosch <hein_tibosch@yahoo.es>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h

index 6be513deb17f69b73be4b321821e99d3ec7a17cd..c89aa41dd44873f02fbea97c6af3f3cd6132dcbd 100644 (file)
@@ -485,7 +485,8 @@ static void macb_tx_interrupt(struct macb *bp)
        status = macb_readl(bp, TSR);
        macb_writel(bp, TSR, status);
 
-       macb_writel(bp, ISR, MACB_BIT(TCOMP));
+       if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+               macb_writel(bp, ISR, MACB_BIT(TCOMP));
 
        netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n",
                (unsigned long)status);
@@ -738,7 +739,8 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
                         * now.
                         */
                        macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
-                       macb_writel(bp, ISR, MACB_BIT(RCOMP));
+                       if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+                               macb_writel(bp, ISR, MACB_BIT(RCOMP));
 
                        if (napi_schedule_prep(&bp->napi)) {
                                netdev_vdbg(bp->dev, "scheduling RX softirq\n");
@@ -1062,6 +1064,17 @@ static void macb_configure_dma(struct macb *bp)
        }
 }
 
+/*
+ * Configure peripheral capacities according to integration options used
+ */
+static void macb_configure_caps(struct macb *bp)
+{
+       if (macb_is_gem(bp)) {
+               if (GEM_BF(IRQCOR, gem_readl(bp, DCFG1)) == 0)
+                       bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
+       }
+}
+
 static void macb_init_hw(struct macb *bp)
 {
        u32 config;
@@ -1084,6 +1097,7 @@ static void macb_init_hw(struct macb *bp)
        bp->duplex = DUPLEX_HALF;
 
        macb_configure_dma(bp);
+       macb_configure_caps(bp);
 
        /* Initialize TX and RX buffers */
        macb_writel(bp, RBQP, bp->rx_ring_dma);
index 993d703806885d9f3ebedd4f5c035bfdd03306d8..548c0ecae8697e5ffb0006819f7670b9fba813f8 100644 (file)
 #define MACB_REV_SIZE                          16
 
 /* Bitfields in DCFG1. */
+#define GEM_IRQCOR_OFFSET                      23
+#define GEM_IRQCOR_SIZE                                1
 #define GEM_DBWDEF_OFFSET                      25
 #define GEM_DBWDEF_SIZE                                3
 
 #define MACB_MAN_READ                          2
 #define MACB_MAN_CODE                          2
 
+/* Capability mask bits */
+#define MACB_CAPS_ISR_CLEAR_ON_WRITE           0x1
+
 /* Bit manipulation macros */
 #define MACB_BIT(name)                                 \
        (1 << MACB_##name##_OFFSET)
@@ -574,6 +579,8 @@ struct macb {
        unsigned int            speed;
        unsigned int            duplex;
 
+       u32                     caps;
+
        phy_interface_t         phy_interface;
 
        /* AT91RM9200 transmit */