static int cxgb_ulp_iscsi_ctl(adapter_t *adapter, unsigned int req, void *data) { int ret = 0; struct ulp_iscsi_info *uiip = data; switch (req) { case ULP_ISCSI_GET_PARAMS: uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT); uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT); uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK); /* * On tx, the iscsi pdu has to be <= tx page size and has to * fit into the Tx PM FIFO. */ uiip->max_txsz = min(adapter->params.tp.tx_pg_size, t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); /* on rx, the iscsi pdu has to be < rx page size and the whole pdu + cpl headers has to fit into one sge buffer */ /* also check the max rx data length programmed in TP */ uiip->max_rxsz = min(uiip->max_rxsz, ((t3_read_reg(adapter, A_TP_PARA_REG2)) >> S_MAXRXDATA) & M_MAXRXDATA); break; case ULP_ISCSI_SET_PARAMS: t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); break; default: ret = (EOPNOTSUPP); } return ret; }
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_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->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; } if (which & MAC_DIRECTION_RX) t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); return 0; }
static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2, u32 *v3) { *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0); *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1); *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2); }
/** * t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control * @mac: the MAC to configure * @speed: the desired speed (10/100/1000/10000) * @duplex: the desired duplex * @fc: desired Tx/Rx PAUSE configuration * * Set the MAC speed, duplex (actually only full-duplex is supported), and * flow control. If a parameter value is negative the corresponding * MAC setting is left at its current value. */ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) { u32 val; adapter_t *adap = mac->adapter; unsigned int oft = mac->offset; if (duplex >= 0 && duplex != DUPLEX_FULL) return -EINVAL; if (mac->multiport) { u32 rx_max_pkt_size = G_RXMAXPKTSIZE(t3_read_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft)); val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, F_TXPAUSEEN); return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port); } if (speed >= 0) { if (speed == SPEED_10) val = V_PORTSPEED(0); else if (speed == SPEED_100) val = V_PORTSPEED(1); else if (speed == SPEED_1000) val = V_PORTSPEED(2); else if (speed == SPEED_10000) val = V_PORTSPEED(3); else return -EINVAL; if (!uses_xaui(adap)) /* T302 */ t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, V_PORTSPEED(M_PORTSPEED), val); else { u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft); if ((old & V_PORTSPEED(M_PORTSPEED)) != val) { t3_mac_reset(mac, val); mac->was_reset = 1; } } } val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); if (fc & PAUSE_TX) { u32 rx_max_pkt_size = G_RXMAXPKTSIZE(t3_read_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft)); val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 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; }
int t3b2_mac_watchdog_task(struct cmac *mac) { struct adapter *adap = mac->adapter; struct mac_stats *s = &mac->stats; unsigned int tx_tcnt, tx_xcnt; u64 tx_mcnt = s->tx_frames; int status; 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 */ 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 out; } } else { mac->toggle_cnt = 0; goto out; } if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { if (mac->toggle_cnt > 4) { status = 2; goto out; } else { status = 1; goto out; } } else { mac->toggle_cnt = 0; goto out; } out: mac->tx_tcnt = tx_tcnt; mac->tx_xcnt = tx_xcnt; mac->tx_mcnt = s->tx_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; }
void t3_mac_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 */ }
static int t3b2_mac_reset(struct cmac *mac) { struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; u32 val; if (!macidx(mac)) t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); else t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ msleep(10); /* Check for xgm Rx fifo empty */ if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, 0x80000000, 1, 5, 2)) { CH_ERR(adap, "MAC %d Rx fifo drain failed\n", macidx(mac)); return -1; } t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ val = F_MAC_RESET_; 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(adap, A_XGM_RESET_CTRL + oft, val); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { msleep(1); t3b_pcs_reset(mac); } t3_write_reg(adap, A_XGM_RX_CFG + oft, F_DISPAUSEFRAMES | F_EN1536BFRAMES | F_RMFCS | F_ENJUMBO | F_ENHASHMCAST); if (!macidx(mac)) t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE); else t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE); return 0; }
/** * t3_mc5_intr_handler - MC5 interrupt handler * @mc5: the MC5 handle * * The MC5 interrupt handler. */ void t3_mc5_intr_handler(struct mc5 *mc5) { adapter_t *adap = mc5->adapter; u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE); if ((cause & F_PARITYERR) && mc5->parity_enabled) { CH_ALERT(adap, "MC5 parity error\n"); mc5->stats.parity_err++; } if (cause & F_REQQPARERR) { CH_ALERT(adap, "MC5 request queue parity error\n"); mc5->stats.reqq_parity_err++; } if (cause & F_DISPQPARERR) { CH_ALERT(adap, "MC5 dispatch queue parity error\n"); mc5->stats.dispq_parity_err++; } if (cause & F_ACTRGNFULL) mc5->stats.active_rgn_full++; if (cause & F_NFASRCHFAIL) mc5->stats.nfa_srch_err++; if (cause & F_UNKNOWNCMD) mc5->stats.unknown_cmd++; if (cause & F_DELACTEMPTY) mc5->stats.del_act_empty++; if (cause & MC5_INT_FATAL) t3_fatal_err(adap); t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause); }
int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) { u32 val, hash_lo, hash_hi; struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; if (rm->dev->flags & IFF_PROMISC) val |= F_COPYALLFRAMES; t3_write_reg(adap, A_XGM_RX_CFG + oft, val); if (rm->dev->flags & IFF_ALLMULTI) hash_lo = hash_hi = 0xffffffff; else { u8 *addr; int exact_addr_idx = mac->nucast; hash_lo = hash_hi = 0; while ((addr = t3_get_next_mcaddr(rm))) if (exact_addr_idx < EXACT_ADDR_FILTERS) set_addr_filter(mac, exact_addr_idx++, addr); else { int hash = hash_hw_addr(addr); if (hash < 32) hash_lo |= (1 << hash); else hash_hi |= (1 << (hash - 32)); } } t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); return 0; }
/* * This function is called periodically to accumulate the current values of the * RMON counters into the port statistics. Since the packet counters are only * 32 bits they can overflow in ~286 secs at 10G, so the function should be * called more frequently than that. The byte counters are 45-bit wide, they * would overflow in ~7.8 hours. */ const struct mac_stats *t3_mac_update_stats(struct cmac *mac) { #define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset) #define RMON_UPDATE(mac, name, reg) \ (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg) #define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \ (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \ ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32) u32 v, lo; RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH); RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH); RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES); RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES); RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES); RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES); RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES); RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES); RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); if (mac->adapter->params.rev == T3_REV_B2) v &= 0x7fffffff; mac->stats.rx_too_long += v; RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES); RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES); RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES); RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES); RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH); RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH); RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST); RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST); RMON_UPDATE(mac, tx_pause, TX_PAUSE); /* This counts error frames in general (bad FCS, underrun, etc). */ RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES); RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES); RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES); RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES); RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES); RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES); RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES); RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES); /* The next stat isn't clear-on-read. */ t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50); v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA); lo = (u32) mac->stats.rx_cong_drops; mac->stats.rx_cong_drops += (u64) (v - lo); return &mac->stats; }
static inline void failover_fixup(adapter_t *adapter, int port) { if (adapter->params.rev == 0) { struct ifnet *ifp = adapter->port[port].ifp; struct cmac *mac = &adapter->port[port].mac; if (!(ifp->if_flags & IFF_UP)) { /* Failover triggered by the interface ifdown */ t3_write_reg(adapter, A_XGM_TX_CTRL + mac->offset, F_TXEN); t3_read_reg(adapter, A_XGM_TX_CTRL + mac->offset); } else { /* Failover triggered by the interface link down */ t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); t3_read_reg(adapter, A_XGM_RX_CTRL + mac->offset); t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, F_RXEN); } } }
/* * Initialization that requires the OS and protocol layers to already * be initialized goes here. */ int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, unsigned int nroutes) { u32 cfg; int err; unsigned int tcam_size = mc5->tcam_size; struct adapter *adap = mc5->adapter; if (!tcam_size) return 0; if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size) return -EINVAL; /* Reset the TCAM */ cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE; cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST; t3_write_reg(adap, A_MC5_DB_CONFIG, cfg); if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) { CH_ERR(adap, "TCAM reset timed out\n"); return -1; } t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes); t3_write_reg(adap, A_MC5_DB_FILTER_TABLE, tcam_size - nroutes - nfilters); t3_write_reg(adap, A_MC5_DB_SERVER_INDEX, tcam_size - nroutes - nfilters - nservers); mc5->parity_enabled = 1; /* All the TCAM addresses we access have only the low 32 bits non 0 */ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0); t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0); mc5_dbgi_mode_enable(mc5); switch (mc5->part_type) { case IDT75P52100: err = init_idt52100(mc5); break; case IDT75N43102: err = init_idt43102(mc5); break; default: CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type); err = -EINVAL; break; } mc5_dbgi_mode_disable(mc5); return err; }
int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) { u32 val; struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; if (duplex >= 0 && duplex != DUPLEX_FULL) return -EINVAL; if (speed >= 0) { if (speed == SPEED_10) val = V_PORTSPEED(0); else if (speed == SPEED_100) val = V_PORTSPEED(1); else if (speed == SPEED_1000) val = V_PORTSPEED(2); else if (speed == SPEED_10000) val = V_PORTSPEED(3); else return -EINVAL; t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, V_PORTSPEED(M_PORTSPEED), val); } val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); if (fc & PAUSE_TX) { u32 rx_max_pkt_size = G_RXMAXPKTSIZE(t3_read_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft)); val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 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; }
static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base, u32 data_array_base, u32 write_cmd, int addr_shift) { unsigned int i; adapter_t *adap = mc5->adapter; /* * We need the size of the TCAM data and mask arrays in terms of * 72-bit entries. */ unsigned int size72 = mc5->tcam_size; unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX); if (mc5->mode == MC5_MODE_144_BIT) { size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */ server_base *= 2; } /* Clear the data array */ dbgi_wr_data3(adap, 0, 0, 0); for (i = 0; i < size72; i++) if (mc5_write(adap, data_array_base + (i << addr_shift), write_cmd)) return -1; /* Initialize the mask array. */ for (i = 0; i < server_base; i++) { dbgi_wr_data3(adap, 0x3fffffff, 0xfff80000, 0xff); if (mc5_write(adap, mask_array_base + (i << addr_shift), write_cmd)) return -1; i++; dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); if (mc5_write(adap, mask_array_base + (i << addr_shift), write_cmd)) return -1; } dbgi_wr_data3(adap, mc5->mode == MC5_MODE_144_BIT ? 0xfffffff9 : 0xfffffffd, 0xffffffff, 0xff); for (; i < size72; i++) if (mc5_write(adap, mask_array_base + (i << addr_shift), write_cmd)) return -1; return 0; }
static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, int *speed, int *duplex, int *fc) { if (link_ok) { unsigned int status; status = t3_read_reg(phy->adapter, XGM_REG(A_XGM_SERDES_STAT0, phy->addr)); *link_ok = !(status & F_LOWSIG0); } if (speed) *speed = SPEED_10000; if (duplex) *duplex = DUPLEX_FULL; return 0; }
/* * Returns a reasonable A_XGM_RESET_CTRL value for the mac specified. */ static inline int xgm_reset_ctrl(const struct cmac *mac) { adapter_t *adap = mac->adapter; int val = F_MAC_RESET_ | F_XGMAC_STOP_EN; if (is_10G(adap)) { int cfg = t3_read_reg(adap, A_XGM_PORT_CFG + mac->offset); val |= F_PCS_RESET_; if (G_PORTSPEED(cfg) != 3) /* not running at 10G */ val |= F_XG2G_RESET_; } else if (uses_xaui(adap)) val |= F_PCS_RESET_ | F_XG2G_RESET_; else val |= F_RGMII_RESET_ | F_XG2G_RESET_; return (val); }
void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode) { #define K * 1024 static unsigned int tcam_part_size[] = { /* in K 72-bit entries */ 64 K, 128 K, 256 K, 32 K }; #undef K u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG); mc5->adapter = adapter; mc5->mode = (unsigned char)mode; mc5->part_type = (unsigned char)G_TMTYPE(cfg); if (cfg & F_TMTYPEHI) mc5->part_type |= 4; mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)]; if (mode == MC5_MODE_144_BIT) mc5->tcam_size /= 2; }
static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base, u32 data_array_base, u32 write_cmd, int addr_shift) { unsigned int i; struct adapter *adap = mc5->adapter; /* */ unsigned int size72 = mc5->tcam_size; unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX); if (mc5->mode == MC5_MODE_144_BIT) { size72 *= 2; /* */ server_base *= 2; } /* */ dbgi_wr_data3(adap, 0, 0, 0); for (i = 0; i < size72; i++) if (mc5_write(adap, data_array_base + (i << addr_shift), write_cmd)) return -1; /* */ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); for (i = 0; i < size72; i++) { if (i == server_base) /* */ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0, mc5->mode == MC5_MODE_144_BIT ? 0xfffffff9 : 0xfffffffd); if (mc5_write(adap, mask_array_base + (i << addr_shift), write_cmd)) return -1; } return 0; }
static void xaui_serdes_reset(struct cmac *mac) { static const unsigned int clear[] = { F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1, F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3 }; int i; struct adapter *adap = mac->adapter; u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset; t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] | F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 | F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 | F_RESETPLL23 | F_RESETPLL01); t3_read_reg(adap, ctrl); udelay(15); for (i = 0; i < ARRAY_SIZE(clear); i++) { t3_set_reg_field(adap, ctrl, clear[i], 0); udelay(15); } }
int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev) { u32 val, hash_lo, hash_hi; struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; if (dev->flags & IFF_PROMISC) val |= F_COPYALLFRAMES; t3_write_reg(adap, A_XGM_RX_CFG + oft, val); if (dev->flags & IFF_ALLMULTI) hash_lo = hash_hi = 0xffffffff; else { struct netdev_hw_addr *ha; int exact_addr_idx = mac->nucast; hash_lo = hash_hi = 0; netdev_for_each_mc_addr(ha, dev) if (exact_addr_idx < EXACT_ADDR_FILTERS) set_addr_filter(mac, exact_addr_idx++, ha->addr); else { int hash = hash_hw_addr(ha->addr); if (hash < 32) hash_lo |= (1 << hash); else hash_hi |= (1 << (hash - 32)); } } t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); return 0; }
int t3_mac_reset(struct cmac *mac) { static const struct addr_val_pair mac_reset_avp[] = { {A_XGM_TX_CTRL, 0}, {A_XGM_RX_CTRL, 0}, {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | F_RMFCS | F_ENJUMBO | F_ENHASHMCAST}, {A_XGM_RX_HASH_LOW, 0}, {A_XGM_RX_HASH_HIGH, 0}, {A_XGM_RX_EXACT_MATCH_LOW_1, 0}, {A_XGM_RX_EXACT_MATCH_LOW_2, 0}, {A_XGM_RX_EXACT_MATCH_LOW_3, 0}, {A_XGM_RX_EXACT_MATCH_LOW_4, 0}, {A_XGM_RX_EXACT_MATCH_LOW_5, 0}, {A_XGM_RX_EXACT_MATCH_LOW_6, 0}, {A_XGM_RX_EXACT_MATCH_LOW_7, 0}, {A_XGM_RX_EXACT_MATCH_LOW_8, 0}, {A_XGM_STAT_CTRL, F_CLRSTATS} }; u32 val; struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); 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) { t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, F_RXENABLE | F_TXENABLE); if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, F_CMULOCK, 1, 5, 2)) { CH_ERR(adap, "MAC %d XAUI SERDES CMU lock failed\n", macidx(mac)); return -1; } t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, F_SERDESRESET_); } else xaui_serdes_reset(mac); } 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)) val |= F_PCS_RESET_ | F_XG2G_RESET_; else val |= F_RGMII_RESET_ | F_XG2G_RESET_; t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { msleep(1); t3b_pcs_reset(mac); } memset(&mac->stats, 0, sizeof(mac->stats)); return 0; }
static int cxgb_rdma_ctl(adapter_t *adapter, unsigned int req, void *data) { int ret = 0; switch (req) { case RDMA_GET_PARAMS: { struct rdma_info *req = data; req->udbell_physbase = rman_get_start(adapter->udbs_res); req->udbell_len = rman_get_size(adapter->udbs_res); req->tpt_base = t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT); req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); req->pbl_base = t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT); req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); req->kdb_addr = (void *)((unsigned long)rman_get_virtual(adapter->regs_res) + A_SG_KDOORBELL); break; } case RDMA_CQ_OP: { struct rdma_cq_op *req = data; /* may be called in any context */ mtx_lock_spin(&adapter->sge.reg_lock); ret = t3_sge_cqcntxt_op(adapter, req->id, req->op, req->credits); mtx_unlock_spin(&adapter->sge.reg_lock); break; } case RDMA_GET_MEM: { struct ch_mem_range *t = data; struct mc7 *mem; if ((t->addr & 7) || (t->len & 7)) return (EINVAL); if (t->mem_id == MEM_CM) mem = &adapter->cm; else if (t->mem_id == MEM_PMRX) mem = &adapter->pmrx; else if (t->mem_id == MEM_PMTX) mem = &adapter->pmtx; else return (EINVAL); ret = t3_mc7_bd_read(mem, t->addr/8, t->len/8, (u64 *)t->buf); if (ret) return (ret); break; } case RDMA_CQ_SETUP: { struct rdma_cq_setup *req = data; mtx_lock_spin(&adapter->sge.reg_lock); ret = t3_sge_init_cqcntxt(adapter, req->id, req->base_addr, req->size, ASYNC_NOTIF_RSPQ, req->ovfl_mode, req->credits, req->credit_thres); mtx_unlock_spin(&adapter->sge.reg_lock); break; } case RDMA_CQ_DISABLE: mtx_lock_spin(&adapter->sge.reg_lock); ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data); mtx_unlock_spin(&adapter->sge.reg_lock); break; case RDMA_CTRL_QP_SETUP: { struct rdma_ctrlqp_setup *req = data; mtx_lock_spin(&adapter->sge.reg_lock); ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0, SGE_CNTXT_RDMA, ASYNC_NOTIF_RSPQ, req->base_addr, req->size, FW_RI_TID_START, 1, 0); mtx_unlock_spin(&adapter->sge.reg_lock); break; } default: ret = EOPNOTSUPP; } return (ret); }
static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) { struct adapter *adapter = tdev2adap(tdev); struct tid_range *tid; struct mtutab *mtup; struct iff_mac *iffmacp; struct ddp_params *ddpp; struct adap_ports *ports; struct ofld_page_info *rx_page_info; struct tp_params *tp = &adapter->params.tp; int port; switch (req) { case GET_MAX_OUTSTANDING_WR: *(unsigned int *)data = FW_WR_NUM; break; case GET_WR_LEN: *(unsigned int *)data = WR_FLITS; break; case GET_TX_MAX_CHUNK: *(unsigned int *)data = 1 << 20; /* 1MB */ break; case GET_TID_RANGE: tid = data; tid->num = t3_mc5_size(&adapter->mc5) - adapter->params.mc5.nroutes - adapter->params.mc5.nfilters - adapter->params.mc5.nservers; tid->base = 0; break; case GET_STID_RANGE: tid = data; tid->num = adapter->params.mc5.nservers; tid->base = t3_mc5_size(&adapter->mc5) - tid->num - adapter->params.mc5.nfilters - adapter->params.mc5.nroutes; break; case GET_L2T_CAPACITY: *(unsigned int *)data = 2048; break; case GET_MTUS: mtup = data; mtup->size = NMTUS; mtup->mtus = adapter->params.mtus; break; case GET_IFF_FROM_MAC: iffmacp = data; iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr, iffmacp->vlan_tag & EVL_VLID_MASK); break; case GET_DDP_PARAMS: ddpp = data; ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT); ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT); ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK); break; case GET_PORTS: ports = data; ports->nports = adapter->params.nports; for_each_port(adapter, port) ports->lldevs[port] = adapter->port[port].ifp; break; case FAILOVER: port = *(int *)data; t3_port_failover(adapter, port); failover_fixup(adapter, port); break; case FAILOVER_DONE: port = *(int *)data; t3_failover_done(adapter, port); break; case FAILOVER_CLEAR: t3_failover_clear(adapter); break; case GET_RX_PAGE_INFO: rx_page_info = data; rx_page_info->page_size = tp->rx_pg_size; rx_page_info->num = tp->rx_num_pgs; break; case ULP_ISCSI_GET_PARAMS: case ULP_ISCSI_SET_PARAMS: if (!offload_running(adapter)) return (EAGAIN); return cxgb_ulp_iscsi_ctl(adapter, req, data); case RDMA_GET_PARAMS: case RDMA_CQ_OP: case RDMA_CQ_SETUP: case RDMA_CQ_DISABLE: case RDMA_CTRL_QP_SETUP: case RDMA_GET_MEM: if (!offload_running(adapter)) return (EAGAIN); return cxgb_rdma_ctl(adapter, req, data); default: return (EOPNOTSUPP); } return 0; }
int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) { int hwm, lwm, divisor; int ipg; unsigned int thres, v, reg; struct adapter *adap = mac->adapter; /* * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max * packet size register includes header, but not FCS. */ mtu += 14; if (mtu > 1536) mtu += 4; if (mtu > MAX_FRAME_SIZE - 4) return -EINVAL; t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); if (adap->params.rev >= T3_REV_B2 && (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { t3_mac_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); t3_mac_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); t3_mac_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 */ thres = (adap->params.vpd.cclk * 1000) / 15625; thres = (thres * mtu) / 1000; if (is_10G(adap)) 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(ipg)); 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 / divisor); } t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, MAC_RXFIFO_SIZE * 4 * 8 / 512); return 0; }
static int t3b2_mac_reset(struct cmac *mac) { struct adapter *adap = mac->adapter; unsigned int oft = mac->offset, store; int idx = macidx(mac); u32 val; if (!macidx(mac)) t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); else t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); /* Stop NIC traffic to reduce the number of TXTOGGLES */ t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0); /* Ensure TX drains */ t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0); t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ /* Store A_TP_TX_DROP_CFG_CH0 */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx); msleep(10); /* Change DROP_CFG to 0xc0000011 */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011); /* Check for xgm Rx fifo empty */ /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, 0x80000000, 1, 1000, 2)) { CH_ERR(adap, "MAC %d Rx fifo drain failed\n", macidx(mac)); return -1; } t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ val = F_MAC_RESET_; 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(adap, A_XGM_RESET_CTRL + oft, val); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { msleep(1); t3b_pcs_reset(mac); } t3_write_reg(adap, A_XGM_RX_CFG + oft, F_DISPAUSEFRAMES | F_EN1536BFRAMES | F_RMFCS | F_ENJUMBO | F_ENHASHMCAST); /* Restore the DROP_CFG */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, store); if (!idx) t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE); else t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE); /* re-enable nic traffic */ t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); /* Set: re-enable NIC traffic */ t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); return 0; }
static int t3_mac_reset(struct cmac *mac, int portspeed) { u32 val, store_mps; adapter_t *adap = mac->adapter; unsigned int oft = mac->offset; int idx = macidx(mac); unsigned int store; /* Stop egress traffic to xgm*/ store_mps = t3_read_reg(adap, A_MPS_CFG); if (!idx) t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); else t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); /* This will reduce the number of TXTOGGLES */ /* Clear: to stop the NIC traffic */ t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0); /* Ensure TX drains */ t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0); /* PCS in reset */ t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ /* Store A_TP_TX_DROP_CFG_CH0 */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); store = t3_read_reg(adap, A_TP_PIO_DATA); msleep(10); /* Change DROP_CFG to 0xc0000011 */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011); /* Check for xgm Rx fifo empty */ /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, 0x80000000, 1, 1000, 2) && portspeed < 0) { CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx); return -1; } if (portspeed >= 0) { u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft); /* * safespeedchange: wipes out pretty much all XGMAC registers. */ t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE, portspeed | F_SAFESPEEDCHANGE); (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, F_SAFESPEEDCHANGE, 0); (void) t3_read_reg(adap, A_XGM_PORT_CFG + oft); t3_mac_init(mac); t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr); } else { t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/ (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ val = xgm_reset_ctrl(mac); t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); (void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { msleep(1); t3b_pcs_reset(mac); } t3_write_reg(adap, A_XGM_RX_CFG + oft, F_DISPAUSEFRAMES | F_EN1536BFRAMES | F_RMFCS | F_ENJUMBO | F_ENHASHMCAST ); } /* Restore the DROP_CFG */ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, store); /* Resume egress traffic to xgm */ t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, store_mps); /* Set: re-enable NIC traffic */ t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT); return 0; }
/** * t3_mac_set_mtu - set the MAC MTU * @mac: the MAC to configure * @mtu: the MTU * * Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly. */ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) { int hwm, lwm, divisor; int ipg; unsigned int thres, v, reg; adapter_t *adap = mac->adapter; unsigned port_type = adap->params.vpd.port_type[macidx(mac)]; unsigned int orig_mtu=mtu; /* * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max * 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; if (mac->multiport) return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port); /* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */ if (port_type == 2) { int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac)); if (err) return err; } if (adap->params.rev >= T3_REV_B2 && (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { t3_mac_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); t3_mac_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); t3_mac_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 */ thres = (adap->params.vpd.cclk * 1000) / 15625; thres = (thres * mtu) / 1000; if (is_10G(adap)) thres /= 10; thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; thres = max(thres, 8U); /* need at least 8 */ ipg = (port_type == 9 || adap->params.rev != T3_REV_C) ? 1 : 0; t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG), V_TXFIFOTHRESH(thres) | V_TXIPG(ipg)); /* Assuming a minimum drain rate of 2.5Gbps... */ 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 / divisor); } t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, MAC_RXFIFO_SIZE * 4 * 8 / 512); return 0; }
int t3b2_mac_watchdog_task(struct cmac *mac) { int status; unsigned int tx_tcnt, tx_xcnt; adapter_t *adap = mac->adapter; struct mac_stats *s = &mac->stats; u64 tx_mcnt = s->tx_frames; if (mac->multiport) tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW); 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*/ if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { u32 cfg, active, enforcepkt; tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, A_XGM_TX_SPI4_SOP_EOP_CNT + mac->offset))); cfg = t3_read_reg(adap, A_MPS_CFG); active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE; enforcepkt = cfg & F_ENFORCEPKT; if (active && enforcepkt && (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 out; } else { mac->toggle_cnt = 0; goto out; } if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { if (mac->toggle_cnt > 4) { status = 2; goto out; } else { status = 1; goto out; } } else { mac->toggle_cnt = 0; goto out; } out: mac->tx_tcnt = tx_tcnt; mac->tx_xcnt = tx_xcnt; mac->tx_mcnt = s->tx_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) { t3_mac_reset(mac, -1); mac->toggle_cnt = 0; } return status; }