📄 ipath_iba6110.c
字号:
config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1); ipath_cdbg(VERBOSE, "Initial serdes status is 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)); /* force reset on */ val |= INFINIPATH_SERDC0_RESET_PLL /* | INFINIPATH_SERDC0_RESET_MASK */ ; ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); udelay(15); /* need pll reset set at least for a bit */ if (val & INFINIPATH_SERDC0_RESET_PLL) { u64 val2 = val &= ~INFINIPATH_SERDC0_RESET_PLL; /* set lane resets, and tx idle, during pll reset */ val2 |= INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE; ipath_cdbg(VERBOSE, "Clearing serdes PLL reset (writing " "%llx)\n", (unsigned long long) val2); ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val2); /* * be sure chip saw it */ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); /* * need pll reset clear at least 11 usec before lane * resets cleared; give it a few more */ udelay(15); val = val2; /* for check below */ } if (val & (INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE)) { val &= ~(INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE); /* clear them */ ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); } 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); /* * we use address 3 */ val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; change = 1; } if (val & INFINIPATH_XGXS_RESET) { /* normally true after boot */ val &= ~INFINIPATH_XGXS_RESET; change = 1; } if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) & INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) { /* need to compensate for Tx inversion in partner */ val &= ~(INFINIPATH_XGXS_RX_POL_MASK << INFINIPATH_XGXS_RX_POL_SHIFT); val |= dd->ipath_rx_pol_inv << INFINIPATH_XGXS_RX_POL_SHIFT; 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, "After setup: serdes status is 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; /* for now, say we always succeeded */}/** * ipath_ht_quiet_serdes - set serdes to txidle * @dd: the infinipath device * driver is being unloaded */static void ipath_ht_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);}/** * ipath_pe_put_tid - write a TID in chip * @dd: the infinipath device * @tidptr: pointer to the expected TID (in chip) to udpate * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0) for expected * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing * * This exists as a separate routine to allow for special locking etc. * It's used for both the full cleanup on exit, as well as the normal * setup and teardown. */static void ipath_ht_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr, u32 type, unsigned long pa){ if (!dd->ipath_kregbase) return; if (pa != dd->ipath_tidinvalid) { if (unlikely((pa & ~INFINIPATH_RT_ADDR_MASK))) { dev_info(&dd->pcidev->dev, "physaddr %lx has more than " "40 bits, using only 40!!!\n", pa); pa &= INFINIPATH_RT_ADDR_MASK; } if (type == RCVHQ_RCV_TYPE_EAGER) pa |= dd->ipath_tidtemplate; else { /* in words (fixed, full page). */ u64 lenvalid = PAGE_SIZE >> 2; lenvalid <<= INFINIPATH_RT_BUFSIZE_SHIFT; pa |= lenvalid | INFINIPATH_RT_VALID; } } writeq(pa, tidptr);}/** * ipath_ht_clear_tid - clear all TID entries for a port, expected and eager * @dd: the infinipath device * @port: the port * * Used from ipath_close(), and at chip initialization. */static void ipath_ht_clear_tids(struct ipath_devdata *dd, unsigned port){ u64 __iomem *tidbase; int i; if (!dd->ipath_kregbase) return; ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port); /* * need to invalidate all of the expected TID entries for this * port, so we don't have valid entries that might somehow get * used (early in next use of this port, or through some bug) */ tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) + dd->ipath_rcvtidbase + port * dd->ipath_rcvtidcnt * sizeof(*tidbase)); for (i = 0; i < dd->ipath_rcvtidcnt; i++) ipath_ht_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED, dd->ipath_tidinvalid); tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) + dd->ipath_rcvegrbase + port * dd->ipath_rcvegrcnt * sizeof(*tidbase)); for (i = 0; i < dd->ipath_rcvegrcnt; i++) ipath_ht_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER, dd->ipath_tidinvalid);}/** * ipath_ht_tidtemplate - setup constants for TID updates * @dd: the infinipath device * * We setup stuff that we use a lot, to avoid calculating each time */static void ipath_ht_tidtemplate(struct ipath_devdata *dd){ dd->ipath_tidtemplate = dd->ipath_ibmaxlen >> 2; dd->ipath_tidtemplate <<= INFINIPATH_RT_BUFSIZE_SHIFT; dd->ipath_tidtemplate |= INFINIPATH_RT_VALID; /* * work around chip errata bug 7358, by marking invalid tids * as having max length */ dd->ipath_tidinvalid = (-1LL & INFINIPATH_RT_BUFSIZE_MASK) << INFINIPATH_RT_BUFSIZE_SHIFT;}static int ipath_ht_early_init(struct ipath_devdata *dd){ u32 __iomem *piobuf; u32 pioincr, val32; int i; /* * one cache line; long IB headers will spill over into received * buffer */ dd->ipath_rcvhdrentsize = 16; dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; /* * For HT, we allocate a somewhat overly large eager buffer, * such that we can guarantee that we can receive the largest * packet that we can send out. To truly support a 4KB MTU, * we need to bump this to a large value. To date, other than * testing, we have never encountered an HCA that can really * send 4KB MTU packets, so we do not handle that (we'll get * errors interrupts if we ever see one). */ dd->ipath_rcvegrbufsize = dd->ipath_piosize2k; /* * the min() check here is currently a nop, but it may not * always be, depending on just how we do ipath_rcvegrbufsize */ dd->ipath_ibmaxlen = min(dd->ipath_piosize2k, dd->ipath_rcvegrbufsize); dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen; ipath_ht_tidtemplate(dd); /* * zero all the TID entries at startup. We do this for sanity, * in case of a previous driver crash of some kind, and also * because the chip powers up with these memories in an unknown * state. Use portcnt, not cfgports, since this is for the * full chip, not for current (possibly different) configuration * value. * Chip Errata bug 6447 */ for (val32 = 0; val32 < dd->ipath_portcnt; val32++) ipath_ht_clear_tids(dd, val32); /* * write the pbc of each buffer, to be sure it's initialized, then * cancel all the buffers, and also abort any packets that might * have been in flight for some reason (the latter is for driver * unload/reload, but isn't a bad idea at first init). PIO send * isn't enabled at this point, so there is no danger of sending * these out on the wire. * Chip Errata bug 6610 */ piobuf = (u32 __iomem *) (((char __iomem *)(dd->ipath_kregbase)) + dd->ipath_piobufbase); pioincr = dd->ipath_palign / sizeof(*piobuf); for (i = 0; i < dd->ipath_piobcnt2k; i++) { /* * reasonable word count, just to init pbc */ writel(16, piobuf); piobuf += pioincr; } ipath_get_eeprom_info(dd); if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' && dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') { /* * Later production QHT7040 has same changes as QHT7140, so * can use GPIO interrupts. They have serial #'s starting * with 128, rather than 112. */ if (dd->ipath_serial[0] == '1' && dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') dd->ipath_flags |= IPATH_GPIO_INTR; else { ipath_dev_err(dd, "Unsupported InfiniPath board " "(serial number %.16s)!\n", dd->ipath_serial); return 1; } } if (dd->ipath_minrev >= 4) { /* Rev4+ 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;}static int ipath_ht_txe_recover(struct ipath_devdata *dd){ int cnt = ++ipath_stats.sps_txeparity; if (cnt >= IPATH_MAX_PARITY_ATTEMPTS) { if (cnt == IPATH_MAX_PARITY_ATTEMPTS) ipath_dev_err(dd, "Too many attempts to recover from " "TXE parity, giving up\n"); return 0; } dev_info(&dd->pcidev->dev, "Recovering from TXE PIO parity error\n"); return 1;}/** * ipath_init_ht_get_base_info - set chip-specific flags for user code * @dd: the infinipath device * @kbase: ipath_base_info pointer * * We set the PCIE flag because the lower bandwidth on PCIe vs * HyperTransport can affect some user packet algorithms. */static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase){ struct ipath_base_info *kinfo = kbase; kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT | IPATH_RUNTIME_PIO_REGSWAPPED; if (pd->port_dd->ipath_minrev < 4) kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY; return 0;}static void ipath_ht_free_irq(struct ipath_devdata *dd){ free_irq(dd->ipath_irq, dd); ht_destroy_irq(dd->ipath_irq); dd->ipath_irq = 0; dd->ipath_intconfig = 0;}/** * ipath_init_iba6110_funcs - set up the chip-specific function pointers * @dd: the infinipath device * * This is global, and is called directly at init to set up the * chip-specific function pointers for later use. */void ipath_init_iba6110_funcs(struct ipath_devdata *dd){ dd->ipath_f_intrsetup = ipath_ht_intconfig; dd->ipath_f_bus = ipath_setup_ht_config; dd->ipath_f_reset = ipath_setup_ht_reset; dd->ipath_f_get_boardname = ipath_ht_boardname; dd->ipath_f_init_hwerrors = ipath_ht_init_hwerrors; dd->ipath_f_early_init = ipath_ht_early_init; dd->ipath_f_handle_hwerrors = ipath_ht_handle_hwerrors; dd->ipath_f_quiet_serdes = ipath_ht_quiet_serdes; dd->ipath_f_bringup_serdes = ipath_ht_bringup_serdes; dd->ipath_f_clear_tids = ipath_ht_clear_tids; dd->ipath_f_put_tid = ipath_ht_put_tid; dd->ipath_f_cleanup = ipath_setup_ht_cleanup; dd->ipath_f_setextled = ipath_setup_ht_setextled; dd->ipath_f_get_base_info = ipath_ht_get_base_info; dd->ipath_f_free_irq = ipath_ht_free_irq; /* * initialize chip-specific variables */ dd->ipath_f_tidtemplate = ipath_ht_tidtemplate; /* * setup the register offsets, since they are different for each * chip */ dd->ipath_kregs = &ipath_ht_kregs; dd->ipath_cregs = &ipath_ht_cregs; /* * do very early init that is needed before ipath_f_bus is * called */ ipath_init_ht_variables(dd);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -