summaryrefslogtreecommitdiffstats
path: root/sys/dev/cxgb/common/cxgb_xgmac.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/cxgb/common/cxgb_xgmac.c')
-rw-r--r--sys/dev/cxgb/common/cxgb_xgmac.c117
1 files changed, 101 insertions, 16 deletions
diff --git a/sys/dev/cxgb/common/cxgb_xgmac.c b/sys/dev/cxgb/common/cxgb_xgmac.c
index 22cd22e..34b05cd 100644
--- a/sys/dev/cxgb/common/cxgb_xgmac.c
+++ b/sys/dev/cxgb/common/cxgb_xgmac.c
@@ -1,3 +1,4 @@
+
/**************************************************************************
Copyright (c) 2007, Chelsio Inc.
@@ -128,8 +129,23 @@ int t3_mac_reset(struct cmac *mac)
xaui_serdes_reset(mac);
}
+
+ if (mac->multiport) {
+ t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
+ MAX_FRAME_SIZE - 4);
+ t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
+ F_DISPREAMBLE);
+ t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
+ F_ENNON802_3PREAMBLE);
+ t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
+ V_TXFIFOTHRESH(M_TXFIFOTHRESH),
+ V_TXFIFOTHRESH(64));
+ t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+ t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
+ }
+
val = F_MAC_RESET_;
- if (is_10G(adap))
+ if (is_10G(adap) || mac->multiport)
val |= F_PCS_RESET_;
else if (uses_xaui(adap))
val |= F_PCS_RESET_ | F_XG2G_RESET_;
@@ -220,9 +236,14 @@ static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
/* Set one of the station's unicast MAC addresses. */
int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
{
+ if (mac->multiport)
+ idx = mac->ext_port + idx * mac->adapter->params.nports;
if (idx >= mac->nucast)
return -EINVAL;
set_addr_filter(mac, idx, addr);
+ if (mac->multiport && idx < mac->adapter->params.nports)
+ t3_vsc7323_set_addr(mac->adapter, addr, idx);
+
return 0;
}
@@ -231,7 +252,7 @@ int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
* unicast addresses. Caller should reload the unicast and multicast addresses
* after calling this.
*/
-int t3_mac_set_num_ucast(struct cmac *mac, int n)
+int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
{
if (n > EXACT_ADDR_FILTERS)
return -EINVAL;
@@ -239,6 +260,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)
{
@@ -255,16 +298,18 @@ static int hash_hw_addr(const u8 *addr)
int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
{
- u32 val, hash_lo, hash_hi;
+ u32 hash_lo, hash_hi;
adapter_t *adap = mac->adapter;
unsigned int oft = mac->offset;
- val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES;
if (promisc_rx_mode(rm))
- val |= F_COPYALLFRAMES;
- t3_write_reg(adap, A_XGM_RX_CFG + oft, val);
+ mac->promisc_map |= 1 << mac->ext_port;
+ else
+ mac->promisc_map &= ~(1 << mac->ext_port);
+ t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
+ mac->promisc_map ? F_COPYALLFRAMES : 0);
- if (allmulti_rx_mode(rm))
+ if (allmulti_rx_mode(rm) || mac->multiport)
hash_lo = hash_hi = 0xffffffff;
else {
u8 *addr;
@@ -289,7 +334,15 @@ int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
return 0;
}
-int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
+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;
@@ -300,17 +353,39 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
* packet size register includes header, but not FCS.
*/
mtu += 14;
+ if (mac->multiport)
+ mtu += 8; /* for preamble */
if (mtu > MAX_FRAME_SIZE - 4)
return -EINVAL;
- t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
+ if (mac->multiport)
+ return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
+
+ 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);
+
+ /* drain rx FIFO */
+ if (t3_wait_op_done(adap,
+ A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + mac->offset,
+ 1 << 31, 1, 20, 5)) {
+ t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
+ enable_exact_filters(mac);
+ return -EIO;
+ }
+ t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
+ t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
+ enable_exact_filters(mac);
+ } else
+ t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
/*
* Adjust the PAUSE frame watermarks. We always set the LWM, and the
* HWM only if flow-control is enabled.
*/
- hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu,
- MAC_RXFIFO_SIZE * 38 / 100);
- hwm = min(hwm, MAC_RXFIFO_SIZE - 8192);
+ 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);
@@ -318,6 +393,7 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
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 */
@@ -335,7 +411,7 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
*/
if (adap->params.rev > 0)
t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
- (hwm-lwm) * 4 / 8);
+ (hwm - lwm) * 4 / 8);
t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
MAC_RXFIFO_SIZE * 4 * 8 / 512);
return 0;
@@ -349,6 +425,8 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
if (duplex >= 0 && duplex != DUPLEX_FULL)
return -EINVAL;
+ if (mac->multiport)
+ return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
if (speed >= 0) {
if (speed == SPEED_10)
val = V_PORTSPEED(0);
@@ -364,13 +442,14 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
V_PORTSPEED(M_PORTSPEED), val);
}
-#if 0
+
val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
if (fc & PAUSE_TX)
- val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128); /* +1KB */
+ 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);
-#endif
+
t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
(fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
return 0;
@@ -383,6 +462,9 @@ int t3_mac_enable(struct cmac *mac, int which)
unsigned int oft = mac->offset;
struct mac_stats *s = &mac->stats;
+ if (mac->multiport)
+ return t3_vsc7323_enable(adap, mac->ext_port, which);
+
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);
@@ -415,6 +497,9 @@ int t3_mac_disable(struct cmac *mac, int which)
adapter_t *adap = mac->adapter;
int val;
+ if (mac->multiport)
+ return t3_vsc7323_disable(adap, mac->ext_port, which);
+
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);
OpenPOWER on IntegriCloud