📄 ipath_iba6120.c
字号:
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);}static int ipath_pe_intconfig(struct ipath_devdata *dd){ u32 chiprev; /* * If the chip supports added error indication via GPIO pins, * enable interrupts on those bits so the interrupt routine * can count the events. Also set flag so interrupt routine * can know they are expected. */ chiprev = dd->ipath_revision >> INFINIPATH_R_CHIPREVMINOR_SHIFT; if ((chiprev & INFINIPATH_R_CHIPREVMINOR_MASK) > 1) { /* Rev2+ reports extra errors via internal GPIO pins */ dd->ipath_flags |= IPATH_GPIO_ERRINTRS; dd->ipath_gpio_mask |= IPATH_GPIO_ERRINTR_MASK; ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, dd->ipath_gpio_mask); } 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; unsigned long flags = 0; /* 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; /* Allow override of LED display for, e.g. Locating system in rack */ if (dd->ipath_led_override) { ltst = (dd->ipath_led_override & IPATH_LED_PHYS) ? INFINIPATH_IBCS_LT_STATE_LINKUP : INFINIPATH_IBCS_LT_STATE_DISABLED; lst = (dd->ipath_led_override & IPATH_LED_LOG) ? INFINIPATH_IBCS_L_STATE_ACTIVE : INFINIPATH_IBCS_L_STATE_DOWN; } spin_lock_irqsave(&dd->ipath_gpio_lock, flags); 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); spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);}/** * 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 chips. If we do end up needing pci_enable_msi * at some point in the future for HT, 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, * even though it uses MSI, and we want to avoid the quirk warning, so * So we call enable_msi only for PCIe. If we do end up needing * pci_enable_msi at some point in the future for HT, 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... */ dd->ipath_irq = pdev->irq; 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); } else ipath_dev_err(dd, "Can't find PCI Express " "capability!\n"); return 0;}static void ipath_init_pe_variables(struct ipath_devdata *dd){ /* * bits for selecting i2c direction and values, * used for I2C serial flash */ dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM; dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM; dd->ipath_gpio_sda = IPATH_GPIO_SDA; dd->ipath_gpio_scl = IPATH_GPIO_SCL; /* variables for sanity checking interrupt and errors */ dd->ipath_hwe_bitsextant = (INFINIPATH_HWE_RXEMEMPARITYERR_MASK << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) | (INFINIPATH_HWE_TXEMEMPARITYERR_MASK << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) | (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK << INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) | INFINIPATH_HWE_PCIE1PLLFAILED | INFINIPATH_HWE_PCIE0PLLFAILED | INFINIPATH_HWE_PCIEPOISONEDTLP | INFINIPATH_HWE_PCIECPLTIMEOUT | INFINIPATH_HWE_PCIEBUSPARITYXTLH | INFINIPATH_HWE_PCIEBUSPARITYXADM | INFINIPATH_HWE_PCIEBUSPARITYRADM | INFINIPATH_HWE_MEMBISTFAILED | INFINIPATH_HWE_COREPLL_FBSLIP | INFINIPATH_HWE_COREPLL_RFSLIP | INFINIPATH_HWE_SERDESPLLFAILED | INFINIPATH_HWE_IBCBUSTOSPCPARITYERR | INFINIPATH_HWE_IBCBUSFRSPCPARITYERR; dd->ipath_i_bitsextant = (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) | (INFINIPATH_I_RCVAVAIL_MASK << INFINIPATH_I_RCVAVAIL_SHIFT) | INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT | INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO; dd->ipath_e_bitsextant = INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC | INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN | INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN | INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR | INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP | INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION | INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN | INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK | INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN | INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED | INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET | INFINIPATH_E_HARDWARE; dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK; dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK; /* * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity. * 2 is Some Misc, 3 is reserved for future. */ dd->ipath_eep_st_masks[0].hwerrs_to_log = INFINIPATH_HWE_TXEMEMPARITYERR_MASK << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT; /* Ignore errors in PIO/PBC on systems with unordered write-combining */ if (ipath_unordered_wc()) dd->ipath_eep_st_masks[0].hwerrs_to_log &= ~TXE_PIO_PARITY; dd->ipath_eep_st_masks[1].hwerrs_to_log = INFINIPATH_HWE_RXEMEMPARITYERR_MASK << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT; dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;}/* setup the MSI stuff again after a reset. I'd like to just call * pci_enable_msi() and request_irq() again, but when I do that, * the MSI enable bit doesn't get set in the command word, and * we switch to to a different interrupt vector, which is confusing, * so I instead just do it all inline. Perhaps somehow can tie this * into the PCIe hotplug support at some point * Note, because I'm doing it all here, I don't call pci_disable_msi() * or free_irq() at the start of ipath_setup_pe_reset(). */static int ipath_reinit_msi(struct ipath_devdata *dd){ int pos; u16 control; int ret; if (!dd->ipath_msi_lo) { dev_info(&dd->pcidev->dev, "Can't restore MSI config, " "initial setup failed?\n"); ret = 0; goto bail; } if (!(pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) { ipath_dev_err(dd, "Can't find MSI capability, " "can't restore MSI settings\n"); ret = 0; goto bail; } ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n", dd->ipath_msi_lo, pos + PCI_MSI_ADDRESS_LO); pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO, dd->ipath_msi_lo); ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n", dd->ipath_msi_hi, pos + PCI_MSI_ADDRESS_HI); pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI, dd->ipath_msi_hi); pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control); if (!(control & PCI_MSI_FLAGS_ENABLE)) { ipath_cdbg(VERBOSE, "MSI control at off %x was %x, " "setting MSI enable (%x)\n", pos + PCI_MSI_FLAGS, control, control | PCI_MSI_FLAGS_ENABLE); control |= PCI_MSI_FLAGS_ENABLE; pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, control); } /* now rewrite the data (vector) info */ pci_write_config_word(dd->pcidev, pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8), dd->ipath_msi_data); /* we restore the cachelinesize also, although it doesn't really * matter */ pci_write_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE, dd->ipath_pci_cacheline); /* and now set the pci master bit again */ pci_set_master(dd->pcidev); ret = 1;bail: return ret;}/* This routine sleeps, so it can only be called from user context, not * from interrupt context. If we need interrupt context, we can split * it into two routines.*/static int ipath_setup_pe_reset(struct ipath_devdata *dd){ u64 val; int i; int ret; /* Use ERROR so it shows up in logs, etc. */ ipath_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->ipath_unit); /* keep chip from being accessed in a few places */ dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT); val = dd->ipath_control | INFINIPATH_C_RESET; ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val); mb(); for (i = 1; i <= 5; i++) { int r; /* allow MBIST, etc. to complete; longer on each retry. * We sometimes get machine checks from bus timeout if no * response, so for now, make it *really* long. */ msleep(1000 + (1 + i) * 2000);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -