1146 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*****************************************************************************3 * *4 * File: subr.c *5 * $Revision: 1.27 $ *6 * $Date: 2005/06/22 01:08:36 $ *7 * Description: *8 * Various subroutines (intr,pio,etc.) used by Chelsio 10G Ethernet driver. *9 * part of the Chelsio 10Gb Ethernet Driver. *10 * *11 * *12 * http://www.chelsio.com *13 * *14 * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. *15 * All rights reserved. *16 * *17 * Maintainers: maintainers@chelsio.com *18 * *19 * Authors: Dimitrios Michailidis <dm@chelsio.com> *20 * Tina Yang <tainay@chelsio.com> *21 * Felix Marti <felix@chelsio.com> *22 * Scott Bardone <sbardone@chelsio.com> *23 * Kurt Ottaway <kottaway@chelsio.com> *24 * Frank DiMambro <frank@chelsio.com> *25 * *26 * History: *27 * *28 ****************************************************************************/29 30#include "common.h"31#include "elmer0.h"32#include "regs.h"33#include "gmac.h"34#include "cphy.h"35#include "sge.h"36#include "tp.h"37#include "espi.h"38 39/**40 * t1_wait_op_done - wait until an operation is completed41 * @adapter: the adapter performing the operation42 * @reg: the register to check for completion43 * @mask: a single-bit field within @reg that indicates completion44 * @polarity: the value of the field when the operation is completed45 * @attempts: number of check iterations46 * @delay: delay in usecs between iterations47 *48 * Wait until an operation is completed by checking a bit in a register49 * up to @attempts times. Returns %0 if the operation completes and %150 * otherwise.51 */52static int t1_wait_op_done(adapter_t *adapter, int reg, u32 mask, int polarity,53 int attempts, int delay)54{55 while (1) {56 u32 val = readl(adapter->regs + reg) & mask;57 58 if (!!val == polarity)59 return 0;60 if (--attempts == 0)61 return 1;62 if (delay)63 udelay(delay);64 }65}66 67#define TPI_ATTEMPTS 5068 69/*70 * Write a register over the TPI interface (unlocked and locked versions).71 */72int __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)73{74 int tpi_busy;75 76 writel(addr, adapter->regs + A_TPI_ADDR);77 writel(value, adapter->regs + A_TPI_WR_DATA);78 writel(F_TPIWR, adapter->regs + A_TPI_CSR);79 80 tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,81 TPI_ATTEMPTS, 3);82 if (tpi_busy)83 pr_alert("%s: TPI write to 0x%x failed\n",84 adapter->name, addr);85 return tpi_busy;86}87 88int t1_tpi_write(adapter_t *adapter, u32 addr, u32 value)89{90 int ret;91 92 spin_lock(&adapter->tpi_lock);93 ret = __t1_tpi_write(adapter, addr, value);94 spin_unlock(&adapter->tpi_lock);95 return ret;96}97 98/*99 * Read a register over the TPI interface (unlocked and locked versions).100 */101int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)102{103 int tpi_busy;104 105 writel(addr, adapter->regs + A_TPI_ADDR);106 writel(0, adapter->regs + A_TPI_CSR);107 108 tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1,109 TPI_ATTEMPTS, 3);110 if (tpi_busy)111 pr_alert("%s: TPI read from 0x%x failed\n",112 adapter->name, addr);113 else114 *valp = readl(adapter->regs + A_TPI_RD_DATA);115 return tpi_busy;116}117 118int t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp)119{120 int ret;121 122 spin_lock(&adapter->tpi_lock);123 ret = __t1_tpi_read(adapter, addr, valp);124 spin_unlock(&adapter->tpi_lock);125 return ret;126}127 128/*129 * Set a TPI parameter.130 */131static void t1_tpi_par(adapter_t *adapter, u32 value)132{133 writel(V_TPIPAR(value), adapter->regs + A_TPI_PAR);134}135 136/*137 * Called when a port's link settings change to propagate the new values to the138 * associated PHY and MAC. After performing the common tasks it invokes an139 * OS-specific handler.140 */141void t1_link_changed(adapter_t *adapter, int port_id)142{143 int link_ok, speed, duplex, fc;144 struct cphy *phy = adapter->port[port_id].phy;145 struct link_config *lc = &adapter->port[port_id].link_config;146 147 phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);148 149 lc->speed = speed < 0 ? SPEED_INVALID : speed;150 lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;151 if (!(lc->requested_fc & PAUSE_AUTONEG))152 fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);153 154 if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {155 /* Set MAC speed, duplex, and flow control to match PHY. */156 struct cmac *mac = adapter->port[port_id].mac;157 158 mac->ops->set_speed_duplex_fc(mac, speed, duplex, fc);159 lc->fc = (unsigned char)fc;160 }161 t1_link_negotiated(adapter, port_id, link_ok, speed, duplex, fc);162}163 164static bool t1_pci_intr_handler(adapter_t *adapter)165{166 u32 pcix_cause;167 168 pci_read_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, &pcix_cause);169 170 if (pcix_cause) {171 pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE,172 pcix_cause);173 /* PCI errors are fatal */174 t1_interrupts_disable(adapter);175 adapter->pending_thread_intr |= F_PL_INTR_SGE_ERR;176 pr_alert("%s: PCI error encountered.\n", adapter->name);177 return true;178 }179 return false;180}181 182#ifdef CONFIG_CHELSIO_T1_1G183#include "fpga_defs.h"184 185/*186 * PHY interrupt handler for FPGA boards.187 */188static int fpga_phy_intr_handler(adapter_t *adapter)189{190 int p;191 u32 cause = readl(adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);192 193 for_each_port(adapter, p)194 if (cause & (1 << p)) {195 struct cphy *phy = adapter->port[p].phy;196 int phy_cause = phy->ops->interrupt_handler(phy);197 198 if (phy_cause & cphy_cause_link_change)199 t1_link_changed(adapter, p);200 }201 writel(cause, adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);202 return 0;203}204 205/*206 * Slow path interrupt handler for FPGAs.207 */208static irqreturn_t fpga_slow_intr(adapter_t *adapter)209{210 u32 cause = readl(adapter->regs + A_PL_CAUSE);211 irqreturn_t ret = IRQ_NONE;212 213 cause &= ~F_PL_INTR_SGE_DATA;214 if (cause & F_PL_INTR_SGE_ERR) {215 if (t1_sge_intr_error_handler(adapter->sge))216 ret = IRQ_WAKE_THREAD;217 }218 219 if (cause & FPGA_PCIX_INTERRUPT_GMAC)220 fpga_phy_intr_handler(adapter);221 222 if (cause & FPGA_PCIX_INTERRUPT_TP) {223 /*224 * FPGA doesn't support MC4 interrupts and it requires225 * this odd layer of indirection for MC5.226 */227 u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);228 229 /* Clear TP interrupt */230 writel(tp_cause, adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);231 }232 if (cause & FPGA_PCIX_INTERRUPT_PCIX) {233 if (t1_pci_intr_handler(adapter))234 ret = IRQ_WAKE_THREAD;235 }236 237 /* Clear the interrupts just processed. */238 if (cause)239 writel(cause, adapter->regs + A_PL_CAUSE);240 241 if (ret != IRQ_NONE)242 return ret;243 244 return cause == 0 ? IRQ_NONE : IRQ_HANDLED;245}246#endif247 248/*249 * Wait until Elmer's MI1 interface is ready for new operations.250 */251static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg)252{253 int attempts = 100, busy;254 255 do {256 u32 val;257 258 __t1_tpi_read(adapter, mi1_reg, &val);259 busy = val & F_MI1_OP_BUSY;260 if (busy)261 udelay(10);262 } while (busy && --attempts);263 if (busy)264 pr_alert("%s: MDIO operation timed out\n", adapter->name);265 return busy;266}267 268/*269 * MI1 MDIO initialization.270 */271static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi)272{273 u32 clkdiv = bi->clock_elmer0 / (2 * bi->mdio_mdc) - 1;274 u32 val = F_MI1_PREAMBLE_ENABLE | V_MI1_MDI_INVERT(bi->mdio_mdiinv) |275 V_MI1_MDI_ENABLE(bi->mdio_mdien) | V_MI1_CLK_DIV(clkdiv);276 277 if (!(bi->caps & SUPPORTED_10000baseT_Full))278 val |= V_MI1_SOF(1);279 t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val);280}281 282#if defined(CONFIG_CHELSIO_T1_1G)283/*284 * Elmer MI1 MDIO read/write operations.285 */286static int mi1_mdio_read(struct net_device *dev, int phy_addr, int mmd_addr,287 u16 reg_addr)288{289 struct adapter *adapter = dev->ml_priv;290 u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr);291 unsigned int val;292 293 spin_lock(&adapter->tpi_lock);294 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);295 __t1_tpi_write(adapter,296 A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_READ);297 mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);298 __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val);299 spin_unlock(&adapter->tpi_lock);300 return val;301}302 303static int mi1_mdio_write(struct net_device *dev, int phy_addr, int mmd_addr,304 u16 reg_addr, u16 val)305{306 struct adapter *adapter = dev->ml_priv;307 u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr);308 309 spin_lock(&adapter->tpi_lock);310 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);311 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val);312 __t1_tpi_write(adapter,313 A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_WRITE);314 mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);315 spin_unlock(&adapter->tpi_lock);316 return 0;317}318 319static const struct mdio_ops mi1_mdio_ops = {320 .init = mi1_mdio_init,321 .read = mi1_mdio_read,322 .write = mi1_mdio_write,323 .mode_support = MDIO_SUPPORTS_C22324};325 326#endif327 328static int mi1_mdio_ext_read(struct net_device *dev, int phy_addr, int mmd_addr,329 u16 reg_addr)330{331 struct adapter *adapter = dev->ml_priv;332 u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);333 unsigned int val;334 335 spin_lock(&adapter->tpi_lock);336 337 /* Write the address we want. */338 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);339 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr);340 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,341 MI1_OP_INDIRECT_ADDRESS);342 mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);343 344 /* Write the operation we want. */345 __t1_tpi_write(adapter,346 A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_READ);347 mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);348 349 /* Read the data. */350 __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val);351 spin_unlock(&adapter->tpi_lock);352 return val;353}354 355static int mi1_mdio_ext_write(struct net_device *dev, int phy_addr,356 int mmd_addr, u16 reg_addr, u16 val)357{358 struct adapter *adapter = dev->ml_priv;359 u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr);360 361 spin_lock(&adapter->tpi_lock);362 363 /* Write the address we want. */364 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr);365 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr);366 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP,367 MI1_OP_INDIRECT_ADDRESS);368 mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);369 370 /* Write the data. */371 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val);372 __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_WRITE);373 mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP);374 spin_unlock(&adapter->tpi_lock);375 return 0;376}377 378static const struct mdio_ops mi1_mdio_ext_ops = {379 .init = mi1_mdio_init,380 .read = mi1_mdio_ext_read,381 .write = mi1_mdio_ext_write,382 .mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22383};384 385enum {386 CH_BRD_T110_1CU,387 CH_BRD_N110_1F,388 CH_BRD_N210_1F,389 CH_BRD_T210_1F,390 CH_BRD_T210_1CU,391 CH_BRD_N204_4CU,392};393 394static const struct board_info t1_board[] = {395 {396 .board = CHBT_BOARD_CHT110,397 .port_number = 1,398 .caps = SUPPORTED_10000baseT_Full,399 .chip_term = CHBT_TERM_T1,400 .chip_mac = CHBT_MAC_PM3393,401 .chip_phy = CHBT_PHY_MY3126,402 .clock_core = 125000000,403 .clock_mc3 = 150000000,404 .clock_mc4 = 125000000,405 .espi_nports = 1,406 .clock_elmer0 = 44,407 .mdio_mdien = 1,408 .mdio_mdiinv = 1,409 .mdio_mdc = 1,410 .mdio_phybaseaddr = 1,411 .gmac = &t1_pm3393_ops,412 .gphy = &t1_my3126_ops,413 .mdio_ops = &mi1_mdio_ext_ops,414 .desc = "Chelsio T110 1x10GBase-CX4 TOE",415 },416 417 {418 .board = CHBT_BOARD_N110,419 .port_number = 1,420 .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,421 .chip_term = CHBT_TERM_T1,422 .chip_mac = CHBT_MAC_PM3393,423 .chip_phy = CHBT_PHY_88X2010,424 .clock_core = 125000000,425 .espi_nports = 1,426 .clock_elmer0 = 44,427 .mdio_mdien = 0,428 .mdio_mdiinv = 0,429 .mdio_mdc = 1,430 .mdio_phybaseaddr = 0,431 .gmac = &t1_pm3393_ops,432 .gphy = &t1_mv88x201x_ops,433 .mdio_ops = &mi1_mdio_ext_ops,434 .desc = "Chelsio N110 1x10GBaseX NIC",435 },436 437 {438 .board = CHBT_BOARD_N210,439 .port_number = 1,440 .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,441 .chip_term = CHBT_TERM_T2,442 .chip_mac = CHBT_MAC_PM3393,443 .chip_phy = CHBT_PHY_88X2010,444 .clock_core = 125000000,445 .espi_nports = 1,446 .clock_elmer0 = 44,447 .mdio_mdien = 0,448 .mdio_mdiinv = 0,449 .mdio_mdc = 1,450 .mdio_phybaseaddr = 0,451 .gmac = &t1_pm3393_ops,452 .gphy = &t1_mv88x201x_ops,453 .mdio_ops = &mi1_mdio_ext_ops,454 .desc = "Chelsio N210 1x10GBaseX NIC",455 },456 457 {458 .board = CHBT_BOARD_CHT210,459 .port_number = 1,460 .caps = SUPPORTED_10000baseT_Full,461 .chip_term = CHBT_TERM_T2,462 .chip_mac = CHBT_MAC_PM3393,463 .chip_phy = CHBT_PHY_88X2010,464 .clock_core = 125000000,465 .clock_mc3 = 133000000,466 .clock_mc4 = 125000000,467 .espi_nports = 1,468 .clock_elmer0 = 44,469 .mdio_mdien = 0,470 .mdio_mdiinv = 0,471 .mdio_mdc = 1,472 .mdio_phybaseaddr = 0,473 .gmac = &t1_pm3393_ops,474 .gphy = &t1_mv88x201x_ops,475 .mdio_ops = &mi1_mdio_ext_ops,476 .desc = "Chelsio T210 1x10GBaseX TOE",477 },478 479 {480 .board = CHBT_BOARD_CHT210,481 .port_number = 1,482 .caps = SUPPORTED_10000baseT_Full,483 .chip_term = CHBT_TERM_T2,484 .chip_mac = CHBT_MAC_PM3393,485 .chip_phy = CHBT_PHY_MY3126,486 .clock_core = 125000000,487 .clock_mc3 = 133000000,488 .clock_mc4 = 125000000,489 .espi_nports = 1,490 .clock_elmer0 = 44,491 .mdio_mdien = 1,492 .mdio_mdiinv = 1,493 .mdio_mdc = 1,494 .mdio_phybaseaddr = 1,495 .gmac = &t1_pm3393_ops,496 .gphy = &t1_my3126_ops,497 .mdio_ops = &mi1_mdio_ext_ops,498 .desc = "Chelsio T210 1x10GBase-CX4 TOE",499 },500 501#ifdef CONFIG_CHELSIO_T1_1G502 {503 .board = CHBT_BOARD_CHN204,504 .port_number = 4,505 .caps = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full506 | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full507 | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |508 SUPPORTED_PAUSE | SUPPORTED_TP,509 .chip_term = CHBT_TERM_T2,510 .chip_mac = CHBT_MAC_VSC7321,511 .chip_phy = CHBT_PHY_88E1111,512 .clock_core = 100000000,513 .espi_nports = 4,514 .clock_elmer0 = 44,515 .mdio_mdien = 0,516 .mdio_mdiinv = 0,517 .mdio_mdc = 0,518 .mdio_phybaseaddr = 4,519 .gmac = &t1_vsc7326_ops,520 .gphy = &t1_mv88e1xxx_ops,521 .mdio_ops = &mi1_mdio_ops,522 .desc = "Chelsio N204 4x100/1000BaseT NIC",523 },524#endif525 526};527 528const struct pci_device_id t1_pci_tbl[] = {529 CH_DEVICE(8, 0, CH_BRD_T110_1CU),530 CH_DEVICE(8, 1, CH_BRD_T110_1CU),531 CH_DEVICE(7, 0, CH_BRD_N110_1F),532 CH_DEVICE(10, 1, CH_BRD_N210_1F),533 CH_DEVICE(11, 1, CH_BRD_T210_1F),534 CH_DEVICE(14, 1, CH_BRD_T210_1CU),535 CH_DEVICE(16, 1, CH_BRD_N204_4CU),536 { 0 }537};538 539MODULE_DEVICE_TABLE(pci, t1_pci_tbl);540 541/*542 * Return the board_info structure with a given index. Out-of-range indices543 * return NULL.544 */545const struct board_info *t1_get_board_info(unsigned int board_id)546{547 return board_id < ARRAY_SIZE(t1_board) ? &t1_board[board_id] : NULL;548}549 550struct chelsio_vpd_t {551 u32 format_version;552 u8 serial_number[16];553 u8 mac_base_address[6];554 u8 pad[2]; /* make multiple-of-4 size requirement explicit */555};556 557#define EEPROMSIZE (8 * 1024)558#define EEPROM_MAX_POLL 4559 560/*561 * Read SEEPROM. A zero is written to the flag register when the address is562 * written to the Control register. The hardware device will set the flag to a563 * one when 4B have been transferred to the Data register.564 */565int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data)566{567 int i = EEPROM_MAX_POLL;568 u16 val;569 u32 v;570 571 if (addr >= EEPROMSIZE || (addr & 3))572 return -EINVAL;573 574 pci_write_config_word(adapter->pdev, A_PCICFG_VPD_ADDR, (u16)addr);575 do {576 udelay(50);577 pci_read_config_word(adapter->pdev, A_PCICFG_VPD_ADDR, &val);578 } while (!(val & F_VPD_OP_FLAG) && --i);579 580 if (!(val & F_VPD_OP_FLAG)) {581 pr_err("%s: reading EEPROM address 0x%x failed\n",582 adapter->name, addr);583 return -EIO;584 }585 pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, &v);586 *data = cpu_to_le32(v);587 return 0;588}589 590static int t1_eeprom_vpd_get(adapter_t *adapter, struct chelsio_vpd_t *vpd)591{592 int addr, ret = 0;593 594 for (addr = 0; !ret && addr < sizeof(*vpd); addr += sizeof(u32))595 ret = t1_seeprom_read(adapter, addr,596 (__le32 *)((u8 *)vpd + addr));597 598 return ret;599}600 601/*602 * Read a port's MAC address from the VPD ROM.603 */604static int vpd_macaddress_get(adapter_t *adapter, int index, u8 mac_addr[])605{606 struct chelsio_vpd_t vpd;607 608 if (t1_eeprom_vpd_get(adapter, &vpd))609 return 1;610 memcpy(mac_addr, vpd.mac_base_address, 5);611 mac_addr[5] = vpd.mac_base_address[5] + index;612 return 0;613}614 615/*616 * Set up the MAC/PHY according to the requested link settings.617 *618 * If the PHY can auto-negotiate first decide what to advertise, then619 * enable/disable auto-negotiation as desired and reset.620 *621 * If the PHY does not auto-negotiate we just reset it.622 *623 * If auto-negotiation is off set the MAC to the proper speed/duplex/FC,624 * otherwise do it later based on the outcome of auto-negotiation.625 */626int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)627{628 unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);629 630 if (lc->supported & SUPPORTED_Autoneg) {631 lc->advertising &= ~(ADVERTISED_ASYM_PAUSE | ADVERTISED_PAUSE);632 if (fc) {633 if (fc == ((PAUSE_RX | PAUSE_TX) &634 (mac->adapter->params.nports < 2)))635 lc->advertising |= ADVERTISED_PAUSE;636 else {637 lc->advertising |= ADVERTISED_ASYM_PAUSE;638 if (fc == PAUSE_RX)639 lc->advertising |= ADVERTISED_PAUSE;640 }641 }642 phy->ops->advertise(phy, lc->advertising);643 644 if (lc->autoneg == AUTONEG_DISABLE) {645 lc->speed = lc->requested_speed;646 lc->duplex = lc->requested_duplex;647 lc->fc = (unsigned char)fc;648 mac->ops->set_speed_duplex_fc(mac, lc->speed,649 lc->duplex, fc);650 /* Also disables autoneg */651 phy->state = PHY_AUTONEG_RDY;652 phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);653 phy->ops->reset(phy, 0);654 } else {655 phy->state = PHY_AUTONEG_EN;656 phy->ops->autoneg_enable(phy); /* also resets PHY */657 }658 } else {659 phy->state = PHY_AUTONEG_RDY;660 mac->ops->set_speed_duplex_fc(mac, -1, -1, fc);661 lc->fc = (unsigned char)fc;662 phy->ops->reset(phy, 0);663 }664 return 0;665}666 667/*668 * External interrupt handler for boards using elmer0.669 */670int t1_elmer0_ext_intr_handler(adapter_t *adapter)671{672 struct cphy *phy;673 int phy_cause;674 u32 cause;675 676 t1_tpi_read(adapter, A_ELMER0_INT_CAUSE, &cause);677 678 switch (board_info(adapter)->board) {679#ifdef CONFIG_CHELSIO_T1_1G680 case CHBT_BOARD_CHT204:681 case CHBT_BOARD_CHT204E:682 case CHBT_BOARD_CHN204:683 case CHBT_BOARD_CHT204V: {684 int i, port_bit;685 for_each_port(adapter, i) {686 port_bit = i + 1;687 if (!(cause & (1 << port_bit)))688 continue;689 690 phy = adapter->port[i].phy;691 phy_cause = phy->ops->interrupt_handler(phy);692 if (phy_cause & cphy_cause_link_change)693 t1_link_changed(adapter, i);694 }695 break;696 }697 case CHBT_BOARD_CHT101:698 if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */699 phy = adapter->port[0].phy;700 phy_cause = phy->ops->interrupt_handler(phy);701 if (phy_cause & cphy_cause_link_change)702 t1_link_changed(adapter, 0);703 }704 break;705 case CHBT_BOARD_7500: {706 int p;707 /*708 * Elmer0's interrupt cause isn't useful here because there is709 * only one bit that can be set for all 4 ports. This means710 * we are forced to check every PHY's interrupt status711 * register to see who initiated the interrupt.712 */713 for_each_port(adapter, p) {714 phy = adapter->port[p].phy;715 phy_cause = phy->ops->interrupt_handler(phy);716 if (phy_cause & cphy_cause_link_change)717 t1_link_changed(adapter, p);718 }719 break;720 }721#endif722 case CHBT_BOARD_CHT210:723 case CHBT_BOARD_N210:724 case CHBT_BOARD_N110:725 if (cause & ELMER0_GP_BIT6) { /* Marvell 88x2010 interrupt */726 phy = adapter->port[0].phy;727 phy_cause = phy->ops->interrupt_handler(phy);728 if (phy_cause & cphy_cause_link_change)729 t1_link_changed(adapter, 0);730 }731 break;732 case CHBT_BOARD_8000:733 case CHBT_BOARD_CHT110:734 if (netif_msg_intr(adapter))735 dev_dbg(&adapter->pdev->dev,736 "External interrupt cause 0x%x\n", cause);737 if (cause & ELMER0_GP_BIT1) { /* PMC3393 INTB */738 struct cmac *mac = adapter->port[0].mac;739 740 mac->ops->interrupt_handler(mac);741 }742 if (cause & ELMER0_GP_BIT5) { /* XPAK MOD_DETECT */743 u32 mod_detect;744 745 t1_tpi_read(adapter,746 A_ELMER0_GPI_STAT, &mod_detect);747 if (netif_msg_link(adapter))748 dev_info(&adapter->pdev->dev, "XPAK %s\n",749 mod_detect ? "removed" : "inserted");750 }751 break;752 }753 t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause);754 return 0;755}756 757/* Enables all interrupts. */758void t1_interrupts_enable(adapter_t *adapter)759{760 unsigned int i;761 762 adapter->slow_intr_mask = F_PL_INTR_SGE_ERR | F_PL_INTR_TP;763 764 t1_sge_intr_enable(adapter->sge);765 t1_tp_intr_enable(adapter->tp);766 if (adapter->espi) {767 adapter->slow_intr_mask |= F_PL_INTR_ESPI;768 t1_espi_intr_enable(adapter->espi);769 }770 771 /* Enable MAC/PHY interrupts for each port. */772 for_each_port(adapter, i) {773 adapter->port[i].mac->ops->interrupt_enable(adapter->port[i].mac);774 adapter->port[i].phy->ops->interrupt_enable(adapter->port[i].phy);775 }776 777 /* Enable PCIX & external chip interrupts on ASIC boards. */778 if (t1_is_asic(adapter)) {779 u32 pl_intr = readl(adapter->regs + A_PL_ENABLE);780 781 /* PCI-X interrupts */782 pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE,783 0xffffffff);784 785 adapter->slow_intr_mask |= F_PL_INTR_EXT | F_PL_INTR_PCIX;786 pl_intr |= F_PL_INTR_EXT | F_PL_INTR_PCIX;787 writel(pl_intr, adapter->regs + A_PL_ENABLE);788 }789}790 791/* Disables all interrupts. */792void t1_interrupts_disable(adapter_t* adapter)793{794 unsigned int i;795 796 t1_sge_intr_disable(adapter->sge);797 t1_tp_intr_disable(adapter->tp);798 if (adapter->espi)799 t1_espi_intr_disable(adapter->espi);800 801 /* Disable MAC/PHY interrupts for each port. */802 for_each_port(adapter, i) {803 adapter->port[i].mac->ops->interrupt_disable(adapter->port[i].mac);804 adapter->port[i].phy->ops->interrupt_disable(adapter->port[i].phy);805 }806 807 /* Disable PCIX & external chip interrupts. */808 if (t1_is_asic(adapter))809 writel(0, adapter->regs + A_PL_ENABLE);810 811 /* PCI-X interrupts */812 pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0);813 814 adapter->slow_intr_mask = 0;815}816 817/* Clears all interrupts */818void t1_interrupts_clear(adapter_t* adapter)819{820 unsigned int i;821 822 t1_sge_intr_clear(adapter->sge);823 t1_tp_intr_clear(adapter->tp);824 if (adapter->espi)825 t1_espi_intr_clear(adapter->espi);826 827 /* Clear MAC/PHY interrupts for each port. */828 for_each_port(adapter, i) {829 adapter->port[i].mac->ops->interrupt_clear(adapter->port[i].mac);830 adapter->port[i].phy->ops->interrupt_clear(adapter->port[i].phy);831 }832 833 /* Enable interrupts for external devices. */834 if (t1_is_asic(adapter)) {835 u32 pl_intr = readl(adapter->regs + A_PL_CAUSE);836 837 writel(pl_intr | F_PL_INTR_EXT | F_PL_INTR_PCIX,838 adapter->regs + A_PL_CAUSE);839 }840 841 /* PCI-X interrupts */842 pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, 0xffffffff);843}844 845/*846 * Slow path interrupt handler for ASICs.847 */848static irqreturn_t asic_slow_intr(adapter_t *adapter)849{850 u32 cause = readl(adapter->regs + A_PL_CAUSE);851 irqreturn_t ret = IRQ_HANDLED;852 853 cause &= adapter->slow_intr_mask;854 if (!cause)855 return IRQ_NONE;856 if (cause & F_PL_INTR_SGE_ERR) {857 if (t1_sge_intr_error_handler(adapter->sge))858 ret = IRQ_WAKE_THREAD;859 }860 if (cause & F_PL_INTR_TP)861 t1_tp_intr_handler(adapter->tp);862 if (cause & F_PL_INTR_ESPI)863 t1_espi_intr_handler(adapter->espi);864 if (cause & F_PL_INTR_PCIX) {865 if (t1_pci_intr_handler(adapter))866 ret = IRQ_WAKE_THREAD;867 }868 if (cause & F_PL_INTR_EXT) {869 /* Wake the threaded interrupt to handle external interrupts as870 * we require a process context. We disable EXT interrupts in871 * the interim and let the thread reenable them when it's done.872 */873 adapter->pending_thread_intr |= F_PL_INTR_EXT;874 adapter->slow_intr_mask &= ~F_PL_INTR_EXT;875 writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,876 adapter->regs + A_PL_ENABLE);877 ret = IRQ_WAKE_THREAD;878 }879 880 /* Clear the interrupts just processed. */881 writel(cause, adapter->regs + A_PL_CAUSE);882 readl(adapter->regs + A_PL_CAUSE); /* flush writes */883 return ret;884}885 886irqreturn_t t1_slow_intr_handler(adapter_t *adapter)887{888#ifdef CONFIG_CHELSIO_T1_1G889 if (!t1_is_asic(adapter))890 return fpga_slow_intr(adapter);891#endif892 return asic_slow_intr(adapter);893}894 895/* Power sequencing is a work-around for Intel's XPAKs. */896static void power_sequence_xpak(adapter_t* adapter)897{898 u32 mod_detect;899 u32 gpo;900 901 /* Check for XPAK */902 t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);903 if (!(ELMER0_GP_BIT5 & mod_detect)) {904 /* XPAK is present */905 t1_tpi_read(adapter, A_ELMER0_GPO, &gpo);906 gpo |= ELMER0_GP_BIT18;907 t1_tpi_write(adapter, A_ELMER0_GPO, gpo);908 }909}910 911int t1_get_board_rev(adapter_t *adapter, const struct board_info *bi,912 struct adapter_params *p)913{914 p->chip_version = bi->chip_term;915 p->is_asic = (p->chip_version != CHBT_TERM_FPGA);916 if (p->chip_version == CHBT_TERM_T1 ||917 p->chip_version == CHBT_TERM_T2 ||918 p->chip_version == CHBT_TERM_FPGA) {919 u32 val = readl(adapter->regs + A_TP_PC_CONFIG);920 921 val = G_TP_PC_REV(val);922 if (val == 2)923 p->chip_revision = TERM_T1B;924 else if (val == 3)925 p->chip_revision = TERM_T2;926 else927 return -1;928 } else929 return -1;930 return 0;931}932 933/*934 * Enable board components other than the Chelsio chip, such as external MAC935 * and PHY.936 */937static int board_init(adapter_t *adapter, const struct board_info *bi)938{939 switch (bi->board) {940 case CHBT_BOARD_8000:941 case CHBT_BOARD_N110:942 case CHBT_BOARD_N210:943 case CHBT_BOARD_CHT210:944 t1_tpi_par(adapter, 0xf);945 t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);946 break;947 case CHBT_BOARD_CHT110:948 t1_tpi_par(adapter, 0xf);949 t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);950 951 /* TBD XXX Might not need. This fixes a problem952 * described in the Intel SR XPAK errata.953 */954 power_sequence_xpak(adapter);955 break;956#ifdef CONFIG_CHELSIO_T1_1G957 case CHBT_BOARD_CHT204E:958 /* add config space write here */959 case CHBT_BOARD_CHT204:960 case CHBT_BOARD_CHT204V:961 case CHBT_BOARD_CHN204:962 t1_tpi_par(adapter, 0xf);963 t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);964 break;965 case CHBT_BOARD_CHT101:966 case CHBT_BOARD_7500:967 t1_tpi_par(adapter, 0xf);968 t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);969 break;970#endif971 }972 return 0;973}974 975/*976 * Initialize and configure the Terminator HW modules. Note that external977 * MAC and PHYs are initialized separately.978 */979int t1_init_hw_modules(adapter_t *adapter)980{981 int err = -EIO;982 const struct board_info *bi = board_info(adapter);983 984 if (!bi->clock_mc4) {985 u32 val = readl(adapter->regs + A_MC4_CFG);986 987 writel(val | F_READY | F_MC4_SLOW, adapter->regs + A_MC4_CFG);988 writel(F_M_BUS_ENABLE | F_TCAM_RESET,989 adapter->regs + A_MC5_CONFIG);990 }991 992 if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac,993 bi->espi_nports))994 goto out_err;995 996 if (t1_tp_reset(adapter->tp, &adapter->params.tp, bi->clock_core))997 goto out_err;998 999 err = t1_sge_configure(adapter->sge, &adapter->params.sge);1000 if (err)1001 goto out_err;1002 1003 err = 0;1004out_err:1005 return err;1006}1007 1008/*1009 * Determine a card's PCI mode.1010 */1011static void get_pci_mode(adapter_t *adapter, struct chelsio_pci_params *p)1012{1013 static const unsigned short speed_map[] = { 33, 66, 100, 133 };1014 u32 pci_mode;1015 1016 pci_read_config_dword(adapter->pdev, A_PCICFG_MODE, &pci_mode);1017 p->speed = speed_map[G_PCI_MODE_CLK(pci_mode)];1018 p->width = (pci_mode & F_PCI_MODE_64BIT) ? 64 : 32;1019 p->is_pcix = (pci_mode & F_PCI_MODE_PCIX) != 0;1020}1021 1022/*1023 * Release the structures holding the SW per-Terminator-HW-module state.1024 */1025void t1_free_sw_modules(adapter_t *adapter)1026{1027 unsigned int i;1028 1029 for_each_port(adapter, i) {1030 struct cmac *mac = adapter->port[i].mac;1031 struct cphy *phy = adapter->port[i].phy;1032 1033 if (mac)1034 mac->ops->destroy(mac);1035 if (phy)1036 phy->ops->destroy(phy);1037 }1038 1039 if (adapter->sge)1040 t1_sge_destroy(adapter->sge);1041 if (adapter->tp)1042 t1_tp_destroy(adapter->tp);1043 if (adapter->espi)1044 t1_espi_destroy(adapter->espi);1045}1046 1047static void init_link_config(struct link_config *lc,1048 const struct board_info *bi)1049{1050 lc->supported = bi->caps;1051 lc->requested_speed = lc->speed = SPEED_INVALID;1052 lc->requested_duplex = lc->duplex = DUPLEX_INVALID;1053 lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;1054 if (lc->supported & SUPPORTED_Autoneg) {1055 lc->advertising = lc->supported;1056 lc->autoneg = AUTONEG_ENABLE;1057 lc->requested_fc |= PAUSE_AUTONEG;1058 } else {1059 lc->advertising = 0;1060 lc->autoneg = AUTONEG_DISABLE;1061 }1062}1063 1064/*1065 * Allocate and initialize the data structures that hold the SW state of1066 * the Terminator HW modules.1067 */1068int t1_init_sw_modules(adapter_t *adapter, const struct board_info *bi)1069{1070 unsigned int i;1071 1072 adapter->params.brd_info = bi;1073 adapter->params.nports = bi->port_number;1074 adapter->params.stats_update_period = bi->gmac->stats_update_period;1075 1076 adapter->sge = t1_sge_create(adapter, &adapter->params.sge);1077 if (!adapter->sge) {1078 pr_err("%s: SGE initialization failed\n",1079 adapter->name);1080 goto error;1081 }1082 1083 if (bi->espi_nports && !(adapter->espi = t1_espi_create(adapter))) {1084 pr_err("%s: ESPI initialization failed\n",1085 adapter->name);1086 goto error;1087 }1088 1089 adapter->tp = t1_tp_create(adapter, &adapter->params.tp);1090 if (!adapter->tp) {1091 pr_err("%s: TP initialization failed\n",1092 adapter->name);1093 goto error;1094 }1095 1096 board_init(adapter, bi);1097 bi->mdio_ops->init(adapter, bi);1098 if (bi->gphy->reset)1099 bi->gphy->reset(adapter);1100 if (bi->gmac->reset)1101 bi->gmac->reset(adapter);1102 1103 for_each_port(adapter, i) {1104 u8 hw_addr[6];1105 struct cmac *mac;1106 int phy_addr = bi->mdio_phybaseaddr + i;1107 1108 adapter->port[i].phy = bi->gphy->create(adapter->port[i].dev,1109 phy_addr, bi->mdio_ops);1110 if (!adapter->port[i].phy) {1111 pr_err("%s: PHY %d initialization failed\n",1112 adapter->name, i);1113 goto error;1114 }1115 1116 adapter->port[i].mac = mac = bi->gmac->create(adapter, i);1117 if (!mac) {1118 pr_err("%s: MAC %d initialization failed\n",1119 adapter->name, i);1120 goto error;1121 }1122 1123 /*1124 * Get the port's MAC addresses either from the EEPROM if one1125 * exists or the one hardcoded in the MAC.1126 */1127 if (!t1_is_asic(adapter) || bi->chip_mac == CHBT_MAC_DUMMY)1128 mac->ops->macaddress_get(mac, hw_addr);1129 else if (vpd_macaddress_get(adapter, i, hw_addr)) {1130 pr_err("%s: could not read MAC address from VPD ROM\n",1131 adapter->port[i].dev->name);1132 goto error;1133 }1134 eth_hw_addr_set(adapter->port[i].dev, hw_addr);1135 init_link_config(&adapter->port[i].link_config, bi);1136 }1137 1138 get_pci_mode(adapter, &adapter->params.pci);1139 t1_interrupts_clear(adapter);1140 return 0;1141 1142error:1143 t1_free_sw_modules(adapter);1144 return -1;1145}1146