]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/cxgb3/xgmac.c
Merge branch 'linux-2.6'
[linux-2.6-omap-h63xx.git] / drivers / net / cxgb3 / xgmac.c
index 94aaff005a355fd352123001fadacdf20f0a59c1..efcf09a709cf899c0a3fabdd63cf5daff82e5b76 100644 (file)
@@ -106,6 +106,7 @@ int t3_mac_reset(struct cmac *mac)
        t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
                         F_RXSTRFRWRD | F_DISERRFRAMES,
                         uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
+       t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);
 
        if (uses_xaui(adap)) {
                if (adap->params.rev == 0) {
@@ -124,7 +125,11 @@ int t3_mac_reset(struct cmac *mac)
                        xaui_serdes_reset(mac);
        }
 
-       val = F_MAC_RESET_;
+       t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
+                        V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
+                        V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
+       val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
+
        if (is_10G(adap))
                val |= F_PCS_RESET_;
        else if (uses_xaui(adap))
@@ -142,7 +147,7 @@ int t3_mac_reset(struct cmac *mac)
        return 0;
 }
 
-int t3b2_mac_reset(struct cmac *mac)
+static int t3b2_mac_reset(struct cmac *mac)
 {
        struct adapter *adap = mac->adapter;
        unsigned int oft = mac->offset;
@@ -231,6 +236,28 @@ int t3_mac_set_num_ucast(struct cmac *mac, int n)
        return 0;
 }
 
+static void disable_exact_filters(struct cmac *mac)
+{
+       unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
+
+       for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
+               u32 v = t3_read_reg(mac->adapter, reg);
+               t3_write_reg(mac->adapter, reg, v);
+       }
+       t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1);  /* flush */
+}
+
+static void enable_exact_filters(struct cmac *mac)
+{
+       unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
+
+       for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
+               u32 v = t3_read_reg(mac->adapter, reg);
+               t3_write_reg(mac->adapter, reg, v);
+       }
+       t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1);  /* flush */
+}
+
 /* Calculate the RX hash filter index of an Ethernet address */
 static int hash_hw_addr(const u8 * addr)
 {
@@ -281,10 +308,19 @@ int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
        return 0;
 }
 
+static int rx_fifo_hwm(int mtu)
+{
+       int hwm;
+
+       hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
+       return min(hwm, MAC_RXFIFO_SIZE - 8192);
+}
+
 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
 {
-       int hwm, lwm;
-       unsigned int thres, v;
+       int hwm, lwm, divisor;
+       int ipg;
+       unsigned int thres, v, reg;
        struct adapter *adap = mac->adapter;
 
        /*
@@ -305,12 +341,46 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
        hwm = min(hwm, MAC_RXFIFO_SIZE - 8192);
        lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);
 
+       if (adap->params.rev >= T3_REV_B2 &&
+           (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
+               disable_exact_filters(mac);
+               v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
+               t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
+                                F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
+
+               reg = adap->params.rev == T3_REV_B2 ?
+                       A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
+
+               /* drain RX FIFO */
+               if (t3_wait_op_done(adap, reg + mac->offset,
+                                   F_RXFIFO_EMPTY, 1, 20, 5)) {
+                       t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
+                       enable_exact_filters(mac);
+                       return -EIO;
+               }
+               t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
+                                V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
+                                V_RXMAXPKTSIZE(mtu));
+               t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
+               enable_exact_filters(mac);
+       } else
+               t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
+                                V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
+                                V_RXMAXPKTSIZE(mtu));
+
+       /*
+        * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
+        * HWM only if flow-control is enabled.
+        */
+       hwm = rx_fifo_hwm(mtu);
+       lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);
        v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
        v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
        v |= V_RXFIFOPAUSELWM(lwm / 8);
        if (G_RXFIFOPAUSEHWM(v))
                v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
                    V_RXFIFOPAUSEHWM(hwm / 8);
+
        t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
 
        /* Adjust the TX FIFO threshold based on the MTU */
@@ -320,16 +390,18 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
                thres /= 10;
        thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
        thres = max(thres, 8U); /* need at least 8 */
+       ipg = (adap->params.rev == T3_REV_C) ? 0 : 1;
        t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
                         V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
-                        V_TXFIFOTHRESH(thres) | V_TXIPG(1));
+                        V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
 
-       if (adap->params.rev > 0)
+       if (adap->params.rev > 0) {
+               divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;
                t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
-                            (hwm - lwm) * 4 / 8);
+                            (hwm - lwm) * 4 / divisor);
+       }
        t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
                     MAC_RXFIFO_SIZE * 4 * 8 / 512);
-
        return 0;
 }
 
@@ -357,6 +429,15 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
                                 V_PORTSPEED(M_PORTSPEED), val);
        }
 
+       val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
+       val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
+       if (fc & PAUSE_TX)
+               val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(
+                                               t3_read_reg(adap,
+                                               A_XGM_RX_MAX_PKT_SIZE
+                                               + oft)) / 8);
+       t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
+
        t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
                         (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
        return 0;
@@ -367,19 +448,29 @@ int t3_mac_enable(struct cmac *mac, int which)
        int idx = macidx(mac);
        struct adapter *adap = mac->adapter;
        unsigned int oft = mac->offset;
-
+       struct mac_stats *s = &mac->stats;
+       
        if (which & MAC_DIRECTION_TX) {
-               t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
                t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
                t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);
                t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
                t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
 
+               t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+
                t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
-               mac->tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
-                                                           A_TP_PIO_DATA)));
-               mac->xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
-                                               A_XGM_TX_SPI4_SOP_EOP_CNT)));
+               mac->tx_mcnt = s->tx_frames;
+               mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
+                                                       A_TP_PIO_DATA)));
+               mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
+                                               A_XGM_TX_SPI4_SOP_EOP_CNT +
+                                               oft)));
+               mac->rx_mcnt = s->rx_frames;
+               mac->rx_pause = s->rx_pause;
+               mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
+                                               A_XGM_RX_SPI4_SOP_EOP_CNT +
+                                               oft)));
+               mac->rx_ocnt = s->rx_fifo_ovfl;
                mac->txen = F_TXEN;
                mac->toggle_cnt = 0;
        }
@@ -390,55 +481,108 @@ int t3_mac_enable(struct cmac *mac, int which)
 
 int t3_mac_disable(struct cmac *mac, int which)
 {
-       int idx = macidx(mac);
        struct adapter *adap = mac->adapter;
 
        if (which & MAC_DIRECTION_TX) {
                t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
-               t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
-               t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
-               t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
-               t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
                mac->txen = 0;
        }
-       if (which & MAC_DIRECTION_RX)
+       if (which & MAC_DIRECTION_RX) {
+               int val = F_MAC_RESET_;
+
+               t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
+                                F_PCS_RESET_, 0);
+               msleep(100);
                t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
+               if (is_10G(adap))
+                       val |= F_PCS_RESET_;
+               else if (uses_xaui(adap))
+                       val |= F_PCS_RESET_ | F_XG2G_RESET_;
+               else
+                       val |= F_RGMII_RESET_ | F_XG2G_RESET_;
+               t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
+       }
        return 0;
 }
 
 int t3b2_mac_watchdog_task(struct cmac *mac)
 {
        struct adapter *adap = mac->adapter;
-       unsigned int tcnt, xcnt;
+       struct mac_stats *s = &mac->stats;
+       unsigned int tx_tcnt, tx_xcnt;
+       unsigned int tx_mcnt = s->tx_frames;
+       unsigned int rx_mcnt = s->rx_frames;
+       unsigned int rx_xcnt;
        int status;
 
-       t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + macidx(mac));
-       tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, A_TP_PIO_DATA)));
-       xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, 
-                                          A_XGM_TX_SPI4_SOP_EOP_CNT +
-                                          mac->offset)));
+       status = 0;
+       tx_xcnt = 1;            /* By default tx_xcnt is making progress */
+       tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt */
+       rx_xcnt = 1;            /* By default rx_xcnt is making progress */
+       if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
+               tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
+                                               A_XGM_TX_SPI4_SOP_EOP_CNT +
+                                               mac->offset)));
+               if (tx_xcnt == 0) {
+                       t3_write_reg(adap, A_TP_PIO_ADDR,
+                                    A_TP_TX_DROP_CNT_CH0 + macidx(mac));
+                       tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
+                                                     A_TP_PIO_DATA)));
+               } else {
+                       goto rxcheck;
+               }
+       } else {
+               mac->toggle_cnt = 0;
+               goto rxcheck;
+       }
 
-       if (tcnt != mac->tcnt && xcnt == 0 && mac->xcnt == 0) {
+       if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
                if (mac->toggle_cnt > 4) {
-                       t3b2_mac_reset(mac);
-                       mac->toggle_cnt = 0;
                        status = 2;
+                       goto out;
                } else {
-                       t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
-                       t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);
-                       t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset,
-                                    mac->txen);
-                       t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);
-                       mac->toggle_cnt++;
                        status = 1;
-               }       
+                       goto out;
+               }
        } else {
                mac->toggle_cnt = 0;
-               status = 0;
+               goto rxcheck;
+       }
+
+rxcheck:
+       if (rx_mcnt != mac->rx_mcnt) {
+               rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
+                                               A_XGM_RX_SPI4_SOP_EOP_CNT +
+                                               mac->offset))) +
+                                               (s->rx_fifo_ovfl -
+                                                mac->rx_ocnt);
+               mac->rx_ocnt = s->rx_fifo_ovfl;
+       } else
+               goto out;
+
+       if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 &&
+           mac->rx_xcnt == 0) {
+               status = 2;
+               goto out;
        }
-       mac->tcnt = tcnt;
-       mac->xcnt = xcnt;
 
+out:
+       mac->tx_tcnt = tx_tcnt;
+       mac->tx_xcnt = tx_xcnt;
+       mac->tx_mcnt = s->tx_frames;
+       mac->rx_xcnt = rx_xcnt;
+       mac->rx_mcnt = s->rx_frames;
+       mac->rx_pause = s->rx_pause;
+       if (status == 1) {
+               t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
+               t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
+               t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
+               t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
+               mac->toggle_cnt++;
+       } else if (status == 2) {
+               t3b2_mac_reset(mac);
+               mac->toggle_cnt = 0;
+       }
        return status;
 }