ipath_pe800.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,254 行 · 第 1/3 页
C
1,254 行
INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) & INFINIPATH_HWE_PCIEMEMPARITYERR_MASK); snprintf(bitsmsg, sizeof bitsmsg, "[PCIe Mem Parity Errs %x] ", bits); strlcat(msg, bitsmsg, msgl); } if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR) strlcat(msg, "[IB2IPATH Parity]", msgl); if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR) strlcat(msg, "[IPATH2IB Parity]", msgl);#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \ INFINIPATH_HWE_COREPLL_RFSLIP ) if (hwerrs & _IPATH_PLL_FAIL) { snprintf(bitsmsg, sizeof bitsmsg, "[PLL failed (%llx), PE-800 unusable]", (unsigned long long) hwerrs & _IPATH_PLL_FAIL); strlcat(msg, bitsmsg, msgl); /* ignore from now on, so disable until driver reloaded */ dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL); ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, dd->ipath_hwerrmask); } if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) { /* * If it occurs, it is left masked since the eternal * interface is unused */ dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED; ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, dd->ipath_hwerrmask); } if (hwerrs & INFINIPATH_HWE_PCIEPOISONEDTLP) strlcat(msg, "[PCIe Poisoned TLP]", msgl); if (hwerrs & INFINIPATH_HWE_PCIECPLTIMEOUT) strlcat(msg, "[PCIe completion timeout]", msgl); /* * In practice, it's unlikely wthat we'll see PCIe PLL, or bus * parity or memory parity error failures, because most likely we * won't be able to talk to the core of the chip. Nonetheless, we * might see them, if they are in parts of the PCIe core that aren't * essential. */ if (hwerrs & INFINIPATH_HWE_PCIE1PLLFAILED) strlcat(msg, "[PCIePLL1]", msgl); if (hwerrs & INFINIPATH_HWE_PCIE0PLLFAILED) strlcat(msg, "[PCIePLL0]", msgl); if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXTLH) strlcat(msg, "[PCIe XTLH core parity]", msgl); if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXADM) strlcat(msg, "[PCIe ADM TX core parity]", msgl); if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYRADM) strlcat(msg, "[PCIe ADM RX core parity]", msgl); if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR) strlcat(msg, "[Rx Dsync]", msgl); if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) strlcat(msg, "[SerDes PLL]", msgl); ipath_dev_err(dd, "%s hardware error\n", msg); if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) { /* * for /sys status file ; if no trailing } is copied, we'll * know it was truncated. */ snprintf(dd->ipath_freezemsg, dd->ipath_freezelen, "{%s}", msg); }}/** * ipath_pe_boardname - fill in the board name * @dd: the infinipath device * @name: the output buffer * @namelen: the size of the output buffer * * info is based on the board revision register */static int ipath_pe_boardname(struct ipath_devdata *dd, char *name, size_t namelen){ char *n = NULL; u8 boardrev = dd->ipath_boardrev; int ret; switch (boardrev) { case 0: n = "InfiniPath_Emulation"; break; case 1: n = "InfiniPath_PE-800-Bringup"; break; case 2: n = "InfiniPath_PE-880"; break; case 3: n = "InfiniPath_PE-850"; break; case 4: n = "InfiniPath_PE-860"; break; default: ipath_dev_err(dd, "Don't yet know about board with ID %u\n", boardrev); snprintf(name, namelen, "Unknown_InfiniPath_PE-8xx_%u", boardrev); break; } if (n) snprintf(name, namelen, "%s", n); if (dd->ipath_majrev != 4 || dd->ipath_minrev != 1) { ipath_dev_err(dd, "Unsupported PE-800 revision %u.%u!\n", dd->ipath_majrev, dd->ipath_minrev); ret = 1; } else ret = 0; return ret;}/** * ipath_pe_init_hwerrors - enable hardware errors * @dd: the infinipath device * * now that we have finished initializing everything that might reasonably * cause a hardware error, and cleared those errors bits as they occur, * we can enable hardware errors in the mask (potentially enabling * freeze mode), and enable hardware errors as errors (along with * everything else) in errormask */static void ipath_pe_init_hwerrors(struct ipath_devdata *dd){ ipath_err_t val; u64 extsval; extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus); if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST)) ipath_dev_err(dd, "MemBIST did not complete!\n"); val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */ if (!dd->ipath_boardrev) // no PLL for Emulator val &= ~INFINIPATH_HWE_SERDESPLLFAILED; /* workaround bug 9460 in internal interface bus parity checking */ val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM; dd->ipath_hwerrmask = val;}/** * ipath_pe_bringup_serdes - bring up the serdes * @dd: the infinipath device */static int ipath_pe_bringup_serdes(struct ipath_devdata *dd){ u64 val, tmp, config1; int ret = 0, change = 0; ipath_dbg("Trying to bringup serdes\n"); if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) & INFINIPATH_HWE_SERDESPLLFAILED) { ipath_dbg("At start, serdes PLL failed bit set " "in hwerrstatus, clearing and continuing\n"); ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, INFINIPATH_HWE_SERDESPLLFAILED); } val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1); ipath_cdbg(VERBOSE, "SerDes status config0=%llx config1=%llx, " "xgxsconfig %llx\n", (unsigned long long) val, (unsigned long long) config1, (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); /* * Force reset on, also set rxdetect enable. Must do before reading * serdesstatus at least for simulation, or some of the bits in * serdes status will come back as undefined and cause simulation * failures */ val |= INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RXDETECT_EN | INFINIPATH_SERDC0_L1PWR_DN; ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); /* be sure chip saw it */ tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); udelay(5); /* need pll reset set at least for a bit */ /* * after PLL is reset, set the per-lane Resets and TxIdle and * clear the PLL reset and rxdetect (to get falling edge). * Leave L1PWR bits set (permanently) */ val &= ~(INFINIPATH_SERDC0_RXDETECT_EN | INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_L1PWR_DN); val |= INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE; ipath_cdbg(VERBOSE, "Clearing pll reset and setting lane resets " "and txidle (%llx)\n", (unsigned long long) val); ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); /* be sure chip saw it */ tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); /* need PLL reset clear for at least 11 usec before lane * resets cleared; give it a few more to be sure */ udelay(15); val &= ~(INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE); ipath_cdbg(VERBOSE, "Clearing lane resets and txidle " "(writing %llx)\n", (unsigned long long) val); ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); /* be sure chip saw it */ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK << INFINIPATH_XGXS_MDIOADDR_SHIFT); /* MDIO address 3 */ val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; change = 1; } if (val & INFINIPATH_XGXS_RESET) { val &= ~INFINIPATH_XGXS_RESET; change = 1; } if (change) ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); /* clear current and de-emphasis bits */ config1 &= ~0x0ffffffff00ULL; /* set current to 20ma */ config1 |= 0x00000000000ULL; /* set de-emphasis to -5.68dB */ config1 |= 0x0cccc000000ULL; ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1); ipath_cdbg(VERBOSE, "done: SerDes status config0=%llx " "config1=%llx, sstatus=%llx xgxs=%llx\n", (unsigned long long) val, (unsigned long long) config1, (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus), (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); if (!ipath_waitfor_mdio_cmdready(dd)) { ipath_write_kreg( dd, dd->ipath_kregs->kr_mdio, ipath_mdio_req(IPATH_MDIO_CMD_READ, 31, IPATH_MDIO_CTRL_XGXS_REG_8, 0)); if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio, IPATH_MDIO_DATAVALID, &val)) ipath_dbg("Never got MDIO data for XGXS " "status read\n"); else ipath_cdbg(VERBOSE, "MDIO Read reg8, " "'bank' 31 %x\n", (u32) val); } else ipath_dbg("Never got MDIO cmdready for XGXS status read\n"); return ret;}/** * ipath_pe_quiet_serdes - set serdes to txidle * @dd: the infinipath device * Called when driver is being unloaded */static void ipath_pe_quiet_serdes(struct ipath_devdata *dd){ u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); val |= INFINIPATH_SERDC0_TXIDLE; ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n", (unsigned long long) val); ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);}/* this is not yet needed on the PE800, so just return 0. */static int ipath_pe_intconfig(struct ipath_devdata *dd){ return 0;}/** * ipath_setup_pe_setextled - set the state of the two external LEDs * @dd: the infinipath device * @lst: the L state * @ltst: the LT state * These LEDs indicate the physical and logical state of IB link. * For this chip (at least with recommended board pinouts), LED1 * is Yellow (logical state) and LED2 is Green (physical state), * * Note: We try to match the Mellanox HCA LED behavior as best * we can. Green indicates physical link state is OK (something is * plugged in, and we can train). * Amber indicates the link is logically up (ACTIVE). * Mellanox further blinks the amber LED to indicate data packet * activity, but we have no hardware support for that, so it would * require waking up every 10-20 msecs and checking the counters * on the chip, and then turning the LED off if appropriate. That's * visible overhead, so not something we will do. * */static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst, u64 ltst){ u64 extctl; /* the diags use the LED to indicate diag info, so we leave * the external LED alone when the diags are running */ if (ipath_diag_inuse) return; extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON | INFINIPATH_EXTC_LED2PRIPORT_ON); if (ltst & INFINIPATH_IBCS_LT_STATE_LINKUP) extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON; if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE) extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON; dd->ipath_extctrl = extctl; ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);}/** * ipath_setup_pe_cleanup - clean up any per-chip chip-specific stuff * @dd: the infinipath device * * This is called during driver unload. * We do the pci_disable_msi here, not in generic code, because it * isn't used for the HT-400. If we do end up needing pci_enable_msi * at some point in the future for HT-400, we'll move the call back * into the main init_one code. */static void ipath_setup_pe_cleanup(struct ipath_devdata *dd){ dd->ipath_msi_lo = 0; /* just in case unload fails */ pci_disable_msi(dd->pcidev);}/** * ipath_setup_pe_config - setup PCIe config related stuff * @dd: the infinipath device * @pdev: the PCI device * * The pci_enable_msi() call will fail on systems with MSI quirks * such as those with AMD8131, even if the device of interest is not * attached to that device, (in the 2.6.13 - 2.6.15 kernels, at least, fixed * late in 2.6.16). * All that can be done is to edit the kernel source to remove the quirk * check until that is fixed. * We do not need to call enable_msi() for our HyperTransport chip (HT-400), * even those it uses MSI, and we want to avoid the quirk warning, so * So we call enable_msi only for the PE-800. If we do end up needing * pci_enable_msi at some point in the future for HT-400, we'll move the * call back into the main init_one code. * We save the msi lo and hi values, so we can restore them after * chip reset (the kernel PCI infrastructure doesn't yet handle that * correctly). */static int ipath_setup_pe_config(struct ipath_devdata *dd, struct pci_dev *pdev){ int pos, ret; dd->ipath_msi_lo = 0; /* used as a flag during reset processing */ ret = pci_enable_msi(dd->pcidev); if (ret) ipath_dev_err(dd, "pci_enable_msi failed: %d, " "interrupts may not work\n", ret); /* continue even if it fails, we may still be OK... */ if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) { u16 control; pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO, &dd->ipath_msi_lo); pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI, &dd->ipath_msi_hi); pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control); /* now save the data (vector) info */ pci_read_config_word(dd->pcidev, pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8), &dd->ipath_msi_data); ipath_cdbg(VERBOSE, "Read msi data 0x%x from config offset " "0x%x, control=0x%x\n", dd->ipath_msi_data, pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8), control); /* we save the cachelinesize also, although it doesn't * really matter */ pci_read_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE, &dd->ipath_pci_cacheline); } else ipath_dev_err(dd, "Can't find MSI capability, " "can't save MSI settings for reset\n"); if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_EXP))) { u16 linkstat; pci_read_config_word(dd->pcidev, pos + PCI_EXP_LNKSTA, &linkstat); linkstat >>= 4; linkstat &= 0x1f; if (linkstat != 8) ipath_dev_err(dd, "PCIe width %u, " "performance reduced\n", linkstat); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?