summaryrefslogtreecommitdiffstats
path: root/sys/dev/cxgb/common/cxgb_vsc7323.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/cxgb/common/cxgb_vsc7323.c')
-rw-r--r--sys/dev/cxgb/common/cxgb_vsc7323.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/sys/dev/cxgb/common/cxgb_vsc7323.c b/sys/dev/cxgb/common/cxgb_vsc7323.c
new file mode 100644
index 0000000..51e254e
--- /dev/null
+++ b/sys/dev/cxgb/common/cxgb_vsc7323.c
@@ -0,0 +1,340 @@
+
+/**************************************************************************
+
+Copyright (c) 2007, Chelsio Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Neither the name of the Chelsio Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef CONFIG_DEFINED
+#include <common/cxgb_common.h>
+#else
+#include <dev/cxgb/common/cxgb_common.h>
+#endif
+
+enum {
+ ELMR_ADDR = 0,
+ ELMR_STAT = 1,
+ ELMR_DATA_LO = 2,
+ ELMR_DATA_HI = 3,
+
+ ELMR_MDIO_ADDR = 10
+};
+
+#define VSC_REG(block, subblock, reg) \
+ ((reg) | ((subblock) << 8) | ((block) << 12))
+
+int t3_elmr_blk_write(adapter_t *adap, int start, const u32 *vals, int n)
+{
+ int ret;
+ const struct mdio_ops *mo = adapter_info(adap)->mdio_ops;
+
+ ELMR_LOCK(adap);
+ ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_ADDR, start);
+ for ( ; !ret && n; n--, vals++) {
+ ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_LO,
+ *vals & 0xffff);
+ if (!ret)
+ ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_HI,
+ *vals >> 16);
+ }
+ ELMR_UNLOCK(adap);
+ return ret;
+}
+
+static int elmr_write(adapter_t *adap, int addr, u32 val)
+{
+ return t3_elmr_blk_write(adap, addr, &val, 1);
+}
+
+int t3_elmr_blk_read(adapter_t *adap, int start, u32 *vals, int n)
+{
+ int ret;
+ unsigned int v;
+ const struct mdio_ops *mo = adapter_info(adap)->mdio_ops;
+
+ ELMR_LOCK(adap);
+
+ ret = mo->write(adap, ELMR_MDIO_ADDR, 0, ELMR_ADDR, start);
+ if (ret)
+ goto out;
+ ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_STAT, &v);
+ if (ret)
+ goto out;
+ if (v != 1) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ for ( ; !ret && n; n--, vals++) {
+ ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_LO, vals);
+ if (!ret) {
+ ret = mo->read(adap, ELMR_MDIO_ADDR, 0, ELMR_DATA_HI,
+ &v);
+ *vals |= v << 16;
+ }
+ }
+out: ELMR_UNLOCK(adap);
+ return ret;
+}
+
+int t3_vsc7323_init(adapter_t *adap, int nports)
+{
+ static struct addr_val_pair sys_avp[] = {
+ { VSC_REG(7, 15, 0xf), 2 },
+ { VSC_REG(7, 15, 0x19), 0xd6 },
+ { VSC_REG(7, 15, 7), 0xc },
+ { VSC_REG(7, 1, 0), 0x220 },
+ };
+ static struct addr_val_pair fifo_avp[] = {
+ { VSC_REG(2, 0, 0x2f), 0 },
+ { VSC_REG(2, 0, 0xf), 0xa0010291 },
+ { VSC_REG(2, 1, 0x2f), 1 },
+ { VSC_REG(2, 1, 0xf), 0xa0026301 }
+ };
+ static struct addr_val_pair xg_avp[] = {
+ { VSC_REG(1, 10, 0), 0x600b },
+ { VSC_REG(1, 10, 2), 0x4000 },
+ { VSC_REG(1, 10, 5), 0x65 },
+ { VSC_REG(1, 10, 7), 3 },
+ { VSC_REG(1, 10, 0x23), 0x800007bf },
+ { VSC_REG(1, 10, 0x24), 4 }
+ };
+
+ int i, ret, ing_step, egr_step, ing_bot, egr_bot;
+
+ for (i = 0; i < ARRAY_SIZE(sys_avp); i++)
+ if ((ret = t3_elmr_blk_write(adap, sys_avp[i].reg_addr,
+ &sys_avp[i].val, 1)))
+ return ret;
+
+
+ ing_step = 0xc0 / nports;
+ egr_step = 0x40 / nports;
+ ing_bot = egr_bot = 0;
+// ing_wm = ing_step * 64;
+// egr_wm = egr_step * 64;
+
+ /* {ING,EGR}_CONTROL.CLR = 1 here */
+ for (i = 0; i < nports; i++)
+ if ((ret = elmr_write(adap, VSC_REG(2, 0, 0x10 + i),
+ ((ing_bot + ing_step) << 16) | ing_bot)) ||
+ (ret = elmr_write(adap, VSC_REG(2, 0, 0x50 + i), 0)) ||
+ (ret = elmr_write(adap, VSC_REG(2, 1, 0x10 + i),
+ ((egr_bot + egr_step) << 16) | egr_bot)) ||
+ (ret = elmr_write(adap, VSC_REG(2, 1, 0x40 + i),
+ 0x2000280)) ||
+ (ret = elmr_write(adap, VSC_REG(2, 1, 0x50 + i), 0)))
+ return ret;
+
+
+ for (i = 0; i < ARRAY_SIZE(fifo_avp); i++)
+ if ((ret = t3_elmr_blk_write(adap, fifo_avp[i].reg_addr,
+ &fifo_avp[i].val, 1)))
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(xg_avp); i++)
+ if ((ret = t3_elmr_blk_write(adap, xg_avp[i].reg_addr,
+ &xg_avp[i].val, 1)))
+ return ret;
+
+ for (i = 0; i < nports; i++)
+ if ((ret = elmr_write(adap, VSC_REG(1, i, 0), 0xa59c)) ||
+ (ret = elmr_write(adap, VSC_REG(1, i, 5),
+ (i << 12) | 0x63)) ||
+ (ret = elmr_write(adap, VSC_REG(1, i, 0xb), 0x96)) ||
+ (ret = elmr_write(adap, VSC_REG(1, i, 0x15), 0x21)))
+ return ret;
+ return ret;
+}
+
+int t3_vsc7323_set_speed_fc(adapter_t *adap, int speed, int fc, int port)
+{
+ int mode, clk, r;
+
+ if (speed >= 0) {
+ if (speed == SPEED_10)
+ mode = clk = 1;
+ else if (speed == SPEED_100)
+ mode = 1, clk = 2;
+ else if (speed == SPEED_1000)
+ mode = clk = 3;
+ else
+ return -EINVAL;
+
+ if ((r = elmr_write(adap, VSC_REG(1, port, 0),
+ 0xa590 | (mode << 2))) ||
+ (r = elmr_write(adap, VSC_REG(1, port, 0xb),
+ 0x91 | (clk << 1))) ||
+ (r = elmr_write(adap, VSC_REG(1, port, 0xb),
+ 0x90 | (clk << 1))) ||
+ (r = elmr_write(adap, VSC_REG(1, port, 0),
+ 0xa593 | (mode << 2))))
+ return r;
+ }
+
+ r = (fc & PAUSE_RX) ? 0x6ffff : 0x2ffff;
+ if (fc & PAUSE_TX)
+ r |= (1 << 19);
+ return elmr_write(adap, VSC_REG(1, port, 1), r);
+}
+
+int t3_vsc7323_set_mtu(adapter_t *adap, unsigned int mtu, int port)
+{
+ return elmr_write(adap, VSC_REG(1, port, 2), mtu);
+}
+
+int t3_vsc7323_set_addr(adapter_t *adap, u8 addr[6], int port)
+{
+ int ret;
+
+ ret = elmr_write(adap, VSC_REG(1, port, 3),
+ (addr[0] << 16) | (addr[1] << 8) | addr[2]);
+ if (!ret)
+ ret = elmr_write(adap, VSC_REG(1, port, 4),
+ (addr[3] << 16) | (addr[4] << 8) | addr[5]);
+ return ret;
+}
+
+int t3_vsc7323_enable(adapter_t *adap, int port, int which)
+{
+ int ret;
+ unsigned int v, orig;
+
+ ret = t3_elmr_blk_read(adap, VSC_REG(1, port, 0), &v, 1);
+ if (!ret) {
+ orig = v;
+ if (which & MAC_DIRECTION_TX)
+ v |= 1;
+ if (which & MAC_DIRECTION_RX)
+ v |= 2;
+ if (v != orig)
+ ret = elmr_write(adap, VSC_REG(1, port, 0), v);
+ }
+ return ret;
+}
+
+int t3_vsc7323_disable(adapter_t *adap, int port, int which)
+{
+ int ret;
+ unsigned int v, orig;
+
+ ret = t3_elmr_blk_read(adap, VSC_REG(1, port, 0), &v, 1);
+ if (!ret) {
+ orig = v;
+ if (which & MAC_DIRECTION_TX)
+ v &= ~1;
+ if (which & MAC_DIRECTION_RX)
+ v &= ~2;
+ if (v != orig)
+ ret = elmr_write(adap, VSC_REG(1, port, 0), v);
+ }
+ return ret;
+}
+
+#define STATS0_START 1
+#define STATS1_START 0x24
+#define NSTATS0 (0x1d - STATS0_START + 1)
+#define NSTATS1 (0x2a - STATS1_START + 1)
+
+const struct mac_stats *t3_vsc7323_update_stats(struct cmac *mac)
+{
+ int ret;
+ u64 rx_ucast, tx_ucast;
+ u32 stats0[NSTATS0], stats1[NSTATS1];
+
+ ret = t3_elmr_blk_read(mac->adapter,
+ VSC_REG(4, mac->ext_port, STATS0_START),
+ stats0, NSTATS0);
+ if (!ret)
+ ret = t3_elmr_blk_read(mac->adapter,
+ VSC_REG(4, mac->ext_port, STATS1_START),
+ stats1, NSTATS1);
+ if (ret)
+ goto out;
+
+ /*
+ * HW counts Rx/Tx unicast frames but we want all the frames.
+ */
+ rx_ucast = mac->stats.rx_frames - mac->stats.rx_mcast_frames -
+ mac->stats.rx_bcast_frames;
+ rx_ucast += (u64)(stats0[6 - STATS0_START] - (u32)rx_ucast);
+ tx_ucast = mac->stats.tx_frames - mac->stats.tx_mcast_frames -
+ mac->stats.tx_bcast_frames;
+ tx_ucast += (u64)(stats0[27 - STATS0_START] - (u32)tx_ucast);
+
+#define RMON_UPDATE(mac, name, hw_stat) \
+ mac->stats.name += (u64)((hw_stat) - (u32)(mac->stats.name))
+
+ RMON_UPDATE(mac, rx_octets, stats0[4 - STATS0_START]);
+ RMON_UPDATE(mac, rx_frames, stats0[6 - STATS0_START]);
+ RMON_UPDATE(mac, rx_frames, stats0[7 - STATS0_START]);
+ RMON_UPDATE(mac, rx_frames, stats0[8 - STATS0_START]);
+ RMON_UPDATE(mac, rx_mcast_frames, stats0[7 - STATS0_START]);
+ RMON_UPDATE(mac, rx_bcast_frames, stats0[8 - STATS0_START]);
+ RMON_UPDATE(mac, rx_fcs_errs, stats0[9 - STATS0_START]);
+ RMON_UPDATE(mac, rx_pause, stats0[2 - STATS0_START]);
+ RMON_UPDATE(mac, rx_jabber, stats0[16 - STATS0_START]);
+ RMON_UPDATE(mac, rx_short, stats0[11 - STATS0_START]);
+ RMON_UPDATE(mac, rx_symbol_errs, stats0[1 - STATS0_START]);
+ RMON_UPDATE(mac, rx_too_long, stats0[15 - STATS0_START]);
+
+ RMON_UPDATE(mac, rx_frames_64, stats0[17 - STATS0_START]);
+ RMON_UPDATE(mac, rx_frames_65_127, stats0[18 - STATS0_START]);
+ RMON_UPDATE(mac, rx_frames_128_255, stats0[19 - STATS0_START]);
+ RMON_UPDATE(mac, rx_frames_256_511, stats0[20 - STATS0_START]);
+ RMON_UPDATE(mac, rx_frames_512_1023, stats0[21 - STATS0_START]);
+ RMON_UPDATE(mac, rx_frames_1024_1518, stats0[22 - STATS0_START]);
+ RMON_UPDATE(mac, rx_frames_1519_max, stats0[23 - STATS0_START]);
+
+ RMON_UPDATE(mac, tx_octets, stats0[26 - STATS0_START]);
+ RMON_UPDATE(mac, tx_frames, stats0[27 - STATS0_START]);
+ RMON_UPDATE(mac, tx_frames, stats0[28 - STATS0_START]);
+ RMON_UPDATE(mac, tx_frames, stats0[29 - STATS0_START]);
+ RMON_UPDATE(mac, tx_mcast_frames, stats0[28 - STATS0_START]);
+ RMON_UPDATE(mac, tx_bcast_frames, stats0[29 - STATS0_START]);
+ RMON_UPDATE(mac, tx_pause, stats0[25 - STATS0_START]);
+
+ RMON_UPDATE(mac, tx_underrun, 0);
+
+ RMON_UPDATE(mac, tx_frames_64, stats1[36 - STATS1_START]);
+ RMON_UPDATE(mac, tx_frames_65_127, stats1[37 - STATS1_START]);
+ RMON_UPDATE(mac, tx_frames_128_255, stats1[38 - STATS1_START]);
+ RMON_UPDATE(mac, tx_frames_256_511, stats1[39 - STATS1_START]);
+ RMON_UPDATE(mac, tx_frames_512_1023, stats1[40 - STATS1_START]);
+ RMON_UPDATE(mac, tx_frames_1024_1518, stats1[41 - STATS1_START]);
+ RMON_UPDATE(mac, tx_frames_1519_max, stats1[42 - STATS1_START]);
+
+#undef RMON_UPDATE
+
+ mac->stats.rx_frames = rx_ucast + mac->stats.rx_mcast_frames +
+ mac->stats.rx_bcast_frames;
+ mac->stats.tx_frames = tx_ucast + mac->stats.tx_mcast_frames +
+ mac->stats.tx_bcast_frames;
+out: return &mac->stats;
+}
OpenPOWER on IntegriCloud