static int my3126_interrupt_handler(struct cphy *cphy) { u32 val; u16 val16; u16 status; u32 act_count; adapter_t *adapter; adapter = cphy->adapter; if (cphy->count == 50) { mdio_read(cphy, 0x1, 0x1, &val); val16 = (u16) val; status = cphy->bmsr ^ val16; if (status & BMSR_LSTATUS) t1_link_changed(adapter, 0); cphy->bmsr = val16; /* We have only enabled link change interrupts so it must be that */ cphy->count = 0; } t1_tpi_write(adapter, OFFSET(SUNI1x10GEXP_REG_MSTAT_CONTROL), SUNI1x10GEXP_BITMSK_MSTAT_SNAP); t1_tpi_read(adapter, OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW), &act_count); t1_tpi_read(adapter, OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW), &val); act_count += val; /* Populate elmer_gpo with the register value */ t1_tpi_read(adapter, A_ELMER0_GPO, &val); cphy->elmer_gpo = val; if ( (val & (1 << 8)) || (val & (1 << 19)) || (cphy->act_count == act_count) || cphy->act_on ) { if (is_T2(adapter)) val |= (1 << 9); else if (t1_is_T1B(adapter)) val |= (1 << 20); cphy->act_on = 0; } else { if (is_T2(adapter)) val &= ~(1 << 9); else if (t1_is_T1B(adapter)) val &= ~(1 << 20); cphy->act_on = 1; } t1_tpi_write(adapter, A_ELMER0_GPO, val); cphy->elmer_gpo = val; cphy->act_count = act_count; cphy->count++; return cphy_cause_link_change; }
int t1_espi_intr_handler(struct peespi *espi) { u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); if (status & F_DIP4ERR) espi->intr_cnt.DIP4_err++; if (status & F_RXDROP) espi->intr_cnt.rx_drops++; if (status & F_TXDROP) espi->intr_cnt.tx_drops++; if (status & F_RXOVERFLOW) espi->intr_cnt.rx_ovflw++; if (status & F_RAMPARITYERR) espi->intr_cnt.parity_err++; if (status & F_DIP2PARITYERR) { espi->intr_cnt.DIP2_parity_err++; readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); } if (status && t1_is_T1B(espi->adapter)) status = 1; writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS); return 0; }
int t1_espi_intr_handler(struct peespi *espi) { u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); if (status & F_DIP4ERR) espi->intr_cnt.DIP4_err++; if (status & F_RXDROP) espi->intr_cnt.rx_drops++; if (status & F_TXDROP) espi->intr_cnt.tx_drops++; if (status & F_RXOVERFLOW) espi->intr_cnt.rx_ovflw++; if (status & F_RAMPARITYERR) espi->intr_cnt.parity_err++; if (status & F_DIP2PARITYERR) { espi->intr_cnt.DIP2_parity_err++; /* * Must read the error count to clear the interrupt * that it causes. */ readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); } /* * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we * write the status as is. */ if (status && t1_is_T1B(espi->adapter)) status = 1; writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS); return 0; }
void t1_mc3_intr_clear(struct pemc3 *mc3) { if (t1_is_asic(mc3->adapter)) { if (t1_is_T1B(mc3->adapter)) { /* * Workaround for T1B bug: we must write to enable * register to clear interrupts. */ u32 old_en; old_en = t1_read_reg_4(mc3->adapter, A_MC3_INT_ENABLE); t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, 0xffffffff); t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, old_en); } else t1_write_reg_4(mc3->adapter, A_MC3_INT_CAUSE, 0xffffffff); t1_write_reg_4(mc3->adapter, A_PL_CAUSE, F_PL_INTR_MC3); #ifdef CONFIG_CHELSIO_T1_1G } else { t1_write_reg_4(mc3->adapter, FPGA_MC3_REG_INTRCAUSE, 0xffffffff); t1_write_reg_4(mc3->adapter, A_PL_CAUSE, FPGA_PCIX_INTERRUPT_MC3); #endif } }
void t1_espi_intr_enable(struct peespi *espi) { u32 enable, pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK; writel(enable, espi->adapter->regs + A_ESPI_INTR_ENABLE); writel(pl_intr | F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); }
/* To check the activity LED */ static int my3126_get_link_status(struct cphy *cphy, int *link_ok, int *speed, int *duplex, int *fc) { u32 val; u16 val16; adapter_t *adapter; adapter = cphy->adapter; mdio_read(cphy, 0x1, 0x1, &val); val16 = (u16) val; /* Populate elmer_gpo with the register value */ t1_tpi_read(adapter, A_ELMER0_GPO, &val); cphy->elmer_gpo = val; *link_ok = (val16 & BMSR_LSTATUS); if (*link_ok) { /* Turn on the LED. */ if (is_T2(adapter)) val &= ~(1 << 8); else if (t1_is_T1B(adapter)) val &= ~(1 << 19); } else { /* Turn off the LED. */ if (is_T2(adapter)) val |= (1 << 8); else if (t1_is_T1B(adapter)) val |= (1 << 19); } t1_tpi_write(adapter, A_ELMER0_GPO, val); cphy->elmer_gpo = val; *speed = SPEED_10000; *duplex = DUPLEX_FULL; /* need to add flow control */ if (fc) *fc = PAUSE_RX | PAUSE_TX; return 0; }
static void espi_setup_for_pm3393(adapter_t *adapter) { u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200; writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN1); writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN3); writel(0x100, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); writel(wmark, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); writel(3, adapter->regs + A_ESPI_CALENDAR_LENGTH); writel(0x08000008, adapter->regs + A_ESPI_TRAIN); writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG); }
void t1_espi_intr_enable(struct peespi *espi) { u32 enable, pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); /* * Cannot enable ESPI interrupts on T1B because HW asserts the * interrupt incorrectly, namely the driver gets ESPI interrupts * but no data is actually dropped (can verify this reading the ESPI * drop registers). Also, once the ESPI interrupt is asserted it * cannot be cleared (HW bug). */ enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK; writel(enable, espi->adapter->regs + A_ESPI_INTR_ENABLE); writel(pl_intr | F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); }
static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { struct adapter *adapter = dev->priv; int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; e->rx_max_pending = MAX_RX_BUFFERS; e->rx_mini_max_pending = 0; e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS; e->tx_max_pending = MAX_CMDQ_ENTRIES; e->rx_pending = adapter->params.sge.freelQ_size[!jumbo_fl]; e->rx_mini_pending = 0; e->rx_jumbo_pending = adapter->params.sge.freelQ_size[jumbo_fl]; e->tx_pending = adapter->params.sge.cmdQ_size[0]; }
static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { struct adapter *adapter = dev->priv; int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; if (e->rx_pending > MAX_RX_BUFFERS || e->rx_mini_pending || e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS || e->tx_pending > MAX_CMDQ_ENTRIES || e->rx_pending < MIN_FL_ENTRIES || e->rx_jumbo_pending < MIN_FL_ENTRIES || e->tx_pending < (adapter->params.nports + 1) * (MAX_SKB_FRAGS + 1)) return -EINVAL; if (adapter->flags & FULL_INIT_DONE) return -EBUSY; adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending; adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending; adapter->params.sge.cmdQ_size[0] = e->tx_pending; adapter->params.sge.cmdQ_size[1] = e->tx_pending > MAX_CMDQ1_ENTRIES ? MAX_CMDQ1_ENTRIES : e->tx_pending; return 0; }
/* 3. Init TriCN Hard Macro */ int t1_espi_init(struct peespi *espi, int mac_type, int nports) { u32 cnt; u32 status_enable_extra = 0; adapter_t *adapter = espi->adapter; u32 status, burstval = 0x800100; /* Disable ESPI training. MACs that can handle it enable it below. */ writel(0, adapter->regs + A_ESPI_TRAIN); if (is_T2(adapter)) { writel(V_OUT_OF_SYNC_COUNT(4) | V_DIP2_PARITY_ERR_THRES(3) | V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL); if (nports == 4) { /* T204: maxburst1 = 0x40, maxburst2 = 0x20 */ burstval = 0x200040; } } writel(burstval, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); switch (mac_type) { case CHBT_MAC_PM3393: espi_setup_for_pm3393(adapter); break; default: return -1; } /* * Make sure any pending interrupts from the SPI are * Cleared before enabling the interrupt. */ writel(ESPI_INTR_MASK, espi->adapter->regs + A_ESPI_INTR_ENABLE); status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); if (status & F_DIP2PARITYERR) { cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); } /* * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we * write the status as is. */ if (status && t1_is_T1B(espi->adapter)) status = 1; writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS); writel(status_enable_extra | F_RXSTATUSENABLE, adapter->regs + A_ESPI_FIFO_STATUS_ENABLE); if (is_T2(adapter)) { tricn_init(adapter); /* * Always position the control at the 1st port egress IN * (sop,eop) counter to reduce PIOs for T/N210 workaround. */ espi->misc_ctrl = (readl(adapter->regs + A_ESPI_MISC_CONTROL) & ~MON_MASK) | (F_MONITORED_DIRECTION | F_MONITORED_INTERFACE); writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); spin_lock_init(&espi->lock); } return 0; }
int t1_mc3_intr_handler(struct pemc3 *mc3) { adapter_t *adapter = mc3->adapter; int cause_reg = A_MC3_INT_CAUSE; u32 cause; #ifdef CONFIG_CHELSIO_T1_1G if (!t1_is_asic(adapter)) cause_reg = FPGA_MC3_REG_INTRCAUSE; #endif cause = t1_read_reg_4(adapter, cause_reg); if (cause & F_MC3_CORR_ERR) { mc3->intr_cnt.corr_err++; CH_WARN("%s: MC3 correctable error at addr 0x%x, " "data 0x%x 0x%x 0x%x 0x%x 0x%x\n", adapter_name(adapter), G_MC3_CE_ADDR(t1_read_reg_4(adapter, A_MC3_CE_ADDR)), t1_read_reg_4(adapter, A_MC3_CE_DATA0), t1_read_reg_4(adapter, A_MC3_CE_DATA1), t1_read_reg_4(adapter, A_MC3_CE_DATA2), t1_read_reg_4(adapter, A_MC3_CE_DATA3), t1_read_reg_4(adapter, A_MC3_CE_DATA4)); } if (cause & F_MC3_UNCORR_ERR) { mc3->intr_cnt.uncorr_err++; CH_ALERT("%s: MC3 uncorrectable error at addr 0x%x, " "data 0x%x 0x%x 0x%x 0x%x 0x%x\n", adapter_name(adapter), G_MC3_UE_ADDR(t1_read_reg_4(adapter, A_MC3_UE_ADDR)), t1_read_reg_4(adapter, A_MC3_UE_DATA0), t1_read_reg_4(adapter, A_MC3_UE_DATA1), t1_read_reg_4(adapter, A_MC3_UE_DATA2), t1_read_reg_4(adapter, A_MC3_UE_DATA3), t1_read_reg_4(adapter, A_MC3_UE_DATA4)); } if (G_MC3_PARITY_ERR(cause)) { mc3->intr_cnt.parity_err++; CH_ALERT("%s: MC3 parity error 0x%x\n", adapter_name(adapter), G_MC3_PARITY_ERR(cause)); } if (cause & F_MC3_ADDR_ERR) { mc3->intr_cnt.addr_err++; CH_ALERT("%s: MC3 address error\n", adapter_name(adapter)); } if (cause & MC3_INTR_FATAL) t1_fatal_err(adapter); if (t1_is_T1B(adapter)) { /* * Workaround for T1B bug: we must write to enable register to * clear interrupts. */ t1_write_reg_4(adapter, A_MC3_INT_ENABLE, cause); /* restore enable */ t1_write_reg_4(adapter, A_MC3_INT_ENABLE, MC3_INTR_MASK); } else t1_write_reg_4(adapter, cause_reg, cause); return 0; }