📄 ipath_iba6110.c
字号:
u32 width; switch (linkwidth & 7) { case 5: width = 4; break; case 4: width = 2; break; case 3: width = 32; break; case 1: width = 16; break; case 0: default: /* if wrong, assume 8 bit */ width = 8; break; } dd->ipath_htwidth = width; if (linkwidth != 0x11) { ipath_dev_err(dd, "Not configured for 16 bit HT " "(%x)\n", linkwidth); if (!(linkwidth & 0xf)) { ipath_dbg("Will ignore HT lane1 errors\n"); dd->ipath_flags |= IPATH_8BIT_IN_HT0; } } } /* * this is just for our link to the host, not devices connected * through tunnel. */ if (pci_read_config_byte(pdev, link_a_b_off + 0xd, &linkwidth)) ipath_dev_err(dd, "Couldn't read HT link frequency " "config register\n"); else { u32 speed; switch (linkwidth & 0xf) { case 6: speed = 1000; break; case 5: speed = 800; break; case 4: speed = 600; break; case 3: speed = 500; break; case 2: speed = 400; break; case 1: speed = 300; break; default: /* * assume reserved and vendor-specific are 200... */ case 0: speed = 200; break; } dd->ipath_htspeed = speed; }}static int ipath_ht_intconfig(struct ipath_devdata *dd){ int ret; if (dd->ipath_intconfig) { ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig, dd->ipath_intconfig); /* interrupt address */ ret = 0; } else { ipath_dev_err(dd, "No interrupts enabled, couldn't setup " "interrupt address\n"); ret = -EINVAL; } return ret;}static void ipath_ht_irq_update(struct pci_dev *dev, int irq, struct ht_irq_msg *msg){ struct ipath_devdata *dd = pci_get_drvdata(dev); u64 prev_intconfig = dd->ipath_intconfig; dd->ipath_intconfig = msg->address_lo; dd->ipath_intconfig |= ((u64) msg->address_hi) << 32; /* * If the previous value of dd->ipath_intconfig is zero, we're * getting configured for the first time, and must not program the * intconfig register here (it will be programmed later, when the * hardware is ready). Otherwise, we should. */ if (prev_intconfig) ipath_ht_intconfig(dd);}/** * ipath_setup_ht_config - setup the interruptconfig register * @dd: the infinipath device * @pdev: the PCI device * * setup the interruptconfig register from the HT config info. * Also clear CRC errors in HT linkcontrol, if necessary. * This is done only for the real hardware. It is done before * chip address space is initted, so can't touch infinipath registers */static int ipath_setup_ht_config(struct ipath_devdata *dd, struct pci_dev *pdev){ int pos, ret; ret = __ht_create_irq(pdev, 0, ipath_ht_irq_update); if (ret < 0) { ipath_dev_err(dd, "Couldn't create interrupt handler: " "err %d\n", ret); goto bail; } dd->ipath_irq = ret; ret = 0; /* * Handle clearing CRC errors in linkctrl register if necessary. We * do this early, before we ever enable errors or hardware errors, * mostly to avoid causing the chip to enter freeze mode. */ pos = pci_find_capability(pdev, PCI_CAP_ID_HT); if (!pos) { ipath_dev_err(dd, "Couldn't find HyperTransport " "capability; no interrupts\n"); ret = -ENODEV; goto bail; } do { u8 cap_type; /* the HT capability type byte is 3 bytes after the * capability byte. */ if (pci_read_config_byte(pdev, pos + 3, &cap_type)) { dev_info(&pdev->dev, "Couldn't read config " "command @ %d\n", pos); continue; } if (!(cap_type & 0xE0)) slave_or_pri_blk(dd, pdev, pos, cap_type); } while ((pos = pci_find_next_capability(pdev, pos, PCI_CAP_ID_HT)));bail: return ret;}/** * ipath_setup_ht_cleanup - clean up any per-chip chip-specific stuff * @dd: the infinipath device * * Called during driver unload. * This is currently a nop for the HT chip, not for all chips */static void ipath_setup_ht_cleanup(struct ipath_devdata *dd){}/** * ipath_setup_ht_setextled - set the state of the two external LEDs * @dd: the infinipath device * @lst: the L state * @ltst: the LT state * * Set the state of the two external LEDs, to indicate physical and * logical state of IB link. For this chip (at least with recommended * board pinouts), LED1 is Green (physical state), and LED2 is Yellow * (logical 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_ht_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); /* * start by setting both LED control bits to off, then turn * on the appropriate bit(s). */ if (dd->ipath_boardrev == 8) { /* LS/X-1 uses different pins */ /* * major difference is that INFINIPATH_EXTC_LEDGBLERR_OFF * is inverted, because it is normally used to indicate * a hardware fault at reset, if there were errors */ extctl = (dd->ipath_extctrl & ~INFINIPATH_EXTC_LEDGBLOK_ON) | INFINIPATH_EXTC_LEDGBLERR_OFF; if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP) extctl &= ~INFINIPATH_EXTC_LEDGBLERR_OFF; if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE) extctl |= INFINIPATH_EXTC_LEDGBLOK_ON; } else { extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON | INFINIPATH_EXTC_LED2PRIPORT_ON); if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP) extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON; if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE) extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON; } dd->ipath_extctrl = extctl; ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl); spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);}static void ipath_init_ht_variables(struct ipath_devdata *dd){ 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; 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_hwe_bitsextant = (INFINIPATH_HWE_HTCMEMPARITYERR_MASK << INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) | (INFINIPATH_HWE_TXEMEMPARITYERR_MASK << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) | (INFINIPATH_HWE_RXEMEMPARITYERR_MASK << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) | INFINIPATH_HWE_HTCLNKABYTE0CRCERR | INFINIPATH_HWE_HTCLNKABYTE1CRCERR | INFINIPATH_HWE_HTCLNKBBYTE0CRCERR | INFINIPATH_HWE_HTCLNKBBYTE1CRCERR | INFINIPATH_HWE_HTCMISCERR4 | INFINIPATH_HWE_HTCMISCERR5 | INFINIPATH_HWE_HTCMISCERR6 | INFINIPATH_HWE_HTCMISCERR7 | INFINIPATH_HWE_HTCBUSTREQPARITYERR | INFINIPATH_HWE_HTCBUSTRESPPARITYERR | INFINIPATH_HWE_HTCBUSIREQPARITYERR | INFINIPATH_HWE_RXDSYNCMEMPARITYERR | INFINIPATH_HWE_MEMBISTFAILED | INFINIPATH_HWE_COREPLL_FBSLIP | INFINIPATH_HWE_COREPLL_RFSLIP | INFINIPATH_HWE_HTBPLL_FBSLIP | INFINIPATH_HWE_HTBPLL_RFSLIP | INFINIPATH_HWE_HTAPLL_FBSLIP | INFINIPATH_HWE_HTAPLL_RFSLIP | INFINIPATH_HWE_SERDESPLLFAILED | INFINIPATH_HWE_IBCBUSTOSPCPARITYERR | INFINIPATH_HWE_IBCBUSFRSPCPARITYERR; 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; 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;}/** * ipath_ht_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_ht_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"); if (extsval & INFINIPATH_EXTS_MEMBIST_CORRECT) ipath_dbg("MemBIST corrected\n"); ipath_check_htlink(dd); /* barring bugs, all hwerrors become interrupts, which can */ val = -1LL; /* don't look at crc lane1 if 8 bit */ if (dd->ipath_flags & IPATH_8BIT_IN_HT0) val &= ~infinipath_hwe_htclnkabyte1crcerr; /* don't look at crc lane1 if 8 bit */ if (dd->ipath_flags & IPATH_8BIT_IN_HT1) val &= ~infinipath_hwe_htclnkbbyte1crcerr; /* * disable RXDSYNCMEMPARITY because external serdes is unused, * and therefore the logic will never be used or initialized, * and uninitialized state will normally result in this error * being asserted. Similarly for the external serdess pll * lock signal. */ val &= ~(INFINIPATH_HWE_SERDESPLLFAILED | INFINIPATH_HWE_RXDSYNCMEMPARITYERR); /* * Disable MISCERR4 because of an inversion in the HT core * logic checking for errors that cause this bit to be set. * The errata can also cause the protocol error bit to be set * in the HT config space linkerror register(s). */ val &= ~INFINIPATH_HWE_HTCMISCERR4; /* * PLL ignored because MDIO interface has a logic problem * for reads, on Comstock and Ponderosa. BRINGUP */ if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9) val &= ~INFINIPATH_HWE_SERDESPLLFAILED; dd->ipath_hwerrmask = val;}/** * ipath_ht_bringup_serdes - bring up the serdes * @dd: the infinipath device */static int ipath_ht_bringup_serdes(struct ipath_devdata *dd){ u64 val, 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -