📄 ipath_iba6120.c
字号:
if ((r = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0, dd->ipath_pcibar0))) ipath_dev_err(dd, "rewrite of BAR0 failed: %d\n", r); if ((r = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1, dd->ipath_pcibar1))) ipath_dev_err(dd, "rewrite of BAR1 failed: %d\n", r); /* now re-enable memory access */ if ((r = pci_enable_device(dd->pcidev))) ipath_dev_err(dd, "pci_enable_device failed after " "reset: %d\n", r); /* whether it worked or not, mark as present, again */ dd->ipath_flags |= IPATH_PRESENT; val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision); if (val == dd->ipath_revision) { ipath_cdbg(VERBOSE, "Got matching revision " "register %llx on try %d\n", (unsigned long long) val, i); ret = ipath_reinit_msi(dd); goto bail; } /* Probably getting -1 back */ ipath_dbg("Didn't get expected revision register, " "got %llx, try %d\n", (unsigned long long) val, i + 1); } ret = 0; /* failed */bail: return ret;}/** * 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_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr, u32 type, unsigned long pa){ u32 __iomem *tidp32 = (u32 __iomem *)tidptr; unsigned long flags = 0; /* keep gcc quiet */ if (pa != dd->ipath_tidinvalid) { if (pa & ((1U << 11) - 1)) { dev_info(&dd->pcidev->dev, "BUG: physaddr %lx " "not 4KB aligned!\n", pa); return; } pa >>= 11; /* paranoia check */ if (pa & (7<<29)) ipath_dev_err(dd, "BUG: Physical page address 0x%lx " "has bits set in 31-29\n", pa); if (type == RCVHQ_RCV_TYPE_EAGER) pa |= dd->ipath_tidtemplate; else /* for now, always full 4KB page */ pa |= 2 << 29; } /* * Workaround chip bug 9437 by writing the scratch register * before and after the TID, and with an io write barrier. * We use a spinlock around the writes, so they can't intermix * with other TID (eager or expected) writes (the chip bug * is triggered by back to back TID writes). Unfortunately, this * call can be done from interrupt level for the port 0 eager TIDs, * so we have to use irqsave locks. */ spin_lock_irqsave(&dd->ipath_tid_lock, flags); ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf); if (dd->ipath_kregbase) writel(pa, tidp32); ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xdeadbeef); mmiowb(); spin_unlock_irqrestore(&dd->ipath_tid_lock, flags);}/** * ipath_pe_put_tid_2 - write a TID in chip, Revision 2 or higher * @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 selection of the * appropriate "flavor". The static calls in cleanup just use the * revision-agnostic form, as they are not performance critical. */static void ipath_pe_put_tid_2(struct ipath_devdata *dd, u64 __iomem *tidptr, u32 type, unsigned long pa){ u32 __iomem *tidp32 = (u32 __iomem *)tidptr; if (pa != dd->ipath_tidinvalid) { if (pa & ((1U << 11) - 1)) { dev_info(&dd->pcidev->dev, "BUG: physaddr %lx " "not 2KB aligned!\n", pa); return; } pa >>= 11; /* paranoia check */ if (pa & (7<<29)) ipath_dev_err(dd, "BUG: Physical page address 0x%lx " "has bits set in 31-29\n", pa); if (type == RCVHQ_RCV_TYPE_EAGER) pa |= dd->ipath_tidtemplate; else /* for now, always full 4KB page */ pa |= 2 << 29; } if (dd->ipath_kregbase) writel(pa, tidp32); mmiowb();}/** * ipath_pe_clear_tid - clear all TID entries for a port, expected and eager * @dd: the infinipath device * @port: the port * * clear all TID entries for a port, expected and eager. * Used from ipath_close(). On this chip, TIDs are only 32 bits, * not 64, but they are still on 64 bit boundaries, so tidbase * is declared as u64 * for the pointer math, even though we write 32 bits */static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port){ u64 __iomem *tidbase; unsigned long tidinv; int i; if (!dd->ipath_kregbase) return; ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port); tidinv = dd->ipath_tidinvalid; 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++) dd->ipath_f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED, tidinv); 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++) dd->ipath_f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER, tidinv);}/** * ipath_pe_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_pe_tidtemplate(struct ipath_devdata *dd){ u32 egrsize = dd->ipath_rcvegrbufsize; /* For now, we always allocate 4KB buffers (at init) so we can * receive max size packets. We may want a module parameter to * specify 2KB or 4KB and/or make be per port instead of per device * for those who want to reduce memory footprint. Note that the * ipath_rcvhdrentsize size must be large enough to hold the largest * IB header (currently 96 bytes) that we expect to handle (plus of * course the 2 dwords of RHF). */ if (egrsize == 2048) dd->ipath_tidtemplate = 1U << 29; else if (egrsize == 4096) dd->ipath_tidtemplate = 2U << 29; else { egrsize = 4096; dev_info(&dd->pcidev->dev, "BUG: unsupported egrbufsize " "%u, using %u\n", dd->ipath_rcvegrbufsize, egrsize); dd->ipath_tidtemplate = 2U << 29; } dd->ipath_tidinvalid = 0;}static int ipath_pe_early_init(struct ipath_devdata *dd){ dd->ipath_flags |= IPATH_4BYTE_TID; if (ipath_unordered_wc()) dd->ipath_flags |= IPATH_PIO_FLUSH_WC; /* * For openfabrics, we need to be able to handle an IB header of * 24 dwords. HT chip has arbitrary sized receive buffers, so we * made them the same size as the PIO buffers. This chip does not * handle arbitrary size buffers, so we need the header large enough * to handle largest IB header, but still have room for a 2KB MTU * standard IB packet. */ dd->ipath_rcvhdrentsize = 24; dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; /* * To truly support a 4KB MTU (for usermode), we need to * bump this to a larger value. For now, we use them for * the kernel only. */ dd->ipath_rcvegrbufsize = 2048; /* * 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_rcvhdrentsize << 2)); dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen; /* * We can request a receive interrupt for 1 or * more packets from current offset. For now, we set this * up for a single packet. */ dd->ipath_rhdrhead_intr_off = 1ULL<<32; ipath_get_eeprom_info(dd); return 0;}int __attribute__((weak)) ipath_unordered_wc(void){ return 0;}/** * ipath_init_pe_get_base_info - set chip-specific flags for user code * @pd: the infinipath port * @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_pe_get_base_info(struct ipath_portdata *pd, void *kbase){ struct ipath_base_info *kinfo = kbase; struct ipath_devdata *dd; if (ipath_unordered_wc()) { kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER; ipath_cdbg(PROC, "Intel processor, forcing WC order\n"); } else ipath_cdbg(PROC, "Not Intel processor, WC ordered\n"); if (pd == NULL) goto done; dd = pd->port_dd;done: kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE | IPATH_RUNTIME_FORCE_PIOAVAIL | IPATH_RUNTIME_PIO_REGSWAPPED; return 0;}static void ipath_pe_free_irq(struct ipath_devdata *dd){ free_irq(dd->ipath_irq, dd); dd->ipath_irq = 0;}/* * On platforms using this chip, and not having ordered WC stores, we * can get TXE parity errors due to speculative reads to the PIO buffers, * and this, due to a chip bug can result in (many) false parity error * reports. So it's a debug print on those, and an info print on systems * where the speculative reads don't occur. * Because we can get lots of false errors, we have no upper limit * on recovery attempts on those platforms. */static int ipath_pe_txe_recover(struct ipath_devdata *dd){ if (ipath_unordered_wc()) ipath_dbg("Recovering from TXE PIO parity error\n"); else { 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_iba6120_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_iba6120_funcs(struct ipath_devdata *dd){ dd->ipath_f_intrsetup = ipath_pe_intconfig; dd->ipath_f_bus = ipath_setup_pe_config; dd->ipath_f_reset = ipath_setup_pe_reset; dd->ipath_f_get_boardname = ipath_pe_boardname; dd->ipath_f_init_hwerrors = ipath_pe_init_hwerrors; dd->ipath_f_early_init = ipath_pe_early_init; dd->ipath_f_handle_hwerrors = ipath_pe_handle_hwerrors; dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes; dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes; dd->ipath_f_clear_tids = ipath_pe_clear_tids; /* * this may get changed after we read the chip revision, * but we start with the safe version for all revs */ dd->ipath_f_put_tid = ipath_pe_put_tid; dd->ipath_f_cleanup = ipath_setup_pe_cleanup; dd->ipath_f_setextled = ipath_setup_pe_setextled; dd->ipath_f_get_base_info = ipath_pe_get_base_info; dd->ipath_f_free_irq = ipath_pe_free_irq; /* initialize chip-specific variables */ dd->ipath_f_tidtemplate = ipath_pe_tidtemplate; /* * setup the register offsets, since they are different for each * chip */ dd->ipath_kregs = &ipath_pe_kregs; dd->ipath_cregs = &ipath_pe_cregs; ipath_init_pe_variables(dd);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -