ipath_ht400.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,604 行 · 第 1/4 页
C
1,604 行
dev_info(&pdev->dev, "Couldn't read linkerror%d " "of HT slave/primary block\n", i); else if (linkerr & 0xf0) { ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, " "clearing\n", linkerr >> 4, i); /* * writing the linkerr bits that are set will clear * them */ if (pci_write_config_byte (pdev, link_off, linkerr)) ipath_dbg("Failed write to clear HT " "linkerror%d\n", i); if (pci_read_config_byte(pdev, link_off, &linkerr)) dev_info(&pdev->dev, "Couldn't reread " "linkerror%d of HT slave/primary " "block\n", i); else if (linkerr & 0xf0) dev_info(&pdev->dev, "HT linkerror%d bits " "0x%x couldn't be cleared\n", i, linkerr >> 4); } } /* * this is just for our link to the host, not devices connected * through tunnel. */ if (pci_read_config_byte(pdev, link_a_b_off + 7, &linkwidth)) ipath_dev_err(dd, "Couldn't read HT link width " "config register\n"); else { 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 set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev, int pos){ u32 int_handler_addr_lower; u32 int_handler_addr_upper; u64 ihandler; u32 intvec; /* use indirection register to get the intr handler */ pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x10); pci_read_config_dword(pdev, pos + 4, &int_handler_addr_lower); pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x11); pci_read_config_dword(pdev, pos + 4, &int_handler_addr_upper); ihandler = (u64) int_handler_addr_lower | ((u64) int_handler_addr_upper << 32); /* * kernels with CONFIG_PCI_MSI set the vector in the irq field of * struct pci_device, so we use that to program the HT-400 internal * interrupt register (not config space) with that value. The BIOS * must still have done the basic MSI setup. */ intvec = pdev->irq; /* * clear any vector bits there; normally not set but we'll overload * this for some debug purposes (setting the HTC debug register * value from software, rather than GPIOs), so it might be set on a * driver reload. */ ihandler &= ~0xff0000; /* x86 vector goes in intrinfo[23:16] */ ihandler |= intvec << 16; ipath_cdbg(VERBOSE, "ihandler lower %x, upper %x, intvec %x, " "interruptconfig %llx\n", int_handler_addr_lower, int_handler_addr_upper, intvec, (unsigned long long) ihandler); /* can't program yet, so save for interrupt setup */ dd->ipath_intconfig = ihandler; /* keep going, so we find link control stuff also */ return ihandler != 0;}/** * 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 = 0; int ihandler = 0; /* * Read the capability info to find the interrupt info, and also * 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, HT_CAPABILITY_ID); 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); else if (cap_type == HT_INTR_DISC_CONFIG) ihandler = set_int_handler(dd, pdev, pos); } while ((pos = pci_find_next_capability(pdev, pos, HT_CAPABILITY_ID))); if (!ihandler) { ipath_dev_err(dd, "Couldn't find interrupt handler in " "config space\n"); ret = -ENODEV; }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-400, 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; /* 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; /* * 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);}static void ipath_init_ht_variables(void){ ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM; ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM; ipath_gpio_sda = IPATH_GPIO_SDA; ipath_gpio_scl = IPATH_GPIO_SCL; infinipath_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; infinipath_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; infinipath_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; infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK; infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;}/** * 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"); 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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?