ipath_driver.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,993 行 · 第 1/4 页
C
1,993 行
int ret = __ipath_verbs_rcv(dd, rc + 1, ebuf, tlen); if (ret == -ENODEV) ipath_cdbg(VERBOSE, "received IB packet, " "not SMA (QP=%x)\n", qp); } else if (etype == RCVHQ_RCV_TYPE_EAGER) { if (qp == IPATH_KD_QP && bthbytes[0] == ipath_layer_rcv_opcode && ebuf) ipath_rcv_layer(dd, etail, tlen, (struct ether_header *)hdr); else ipath_cdbg(PKT, "typ %x, opcode %x (eager, " "qp=%x), len %x; ignored\n", etype, bthbytes[0], qp, tlen); } else if (etype == RCVHQ_RCV_TYPE_EXPECTED) ipath_dbg("Bug: Expected TID, opcode %x; ignored\n", be32_to_cpu(hdr->bth[0]) & 0xff); else if (eflags & (INFINIPATH_RHF_H_TIDERR | INFINIPATH_RHF_H_IHDRERR)) { /* * This is a type 3 packet, only the LRH is in the * rcvhdrq, the rest of the header is in the eager * buffer. */ u8 opcode; if (ebuf) { bthbytes = (u8 *) ebuf; opcode = *bthbytes; } else opcode = 0; get_rhf_errstring(eflags, emsg, sizeof emsg); ipath_dbg("Err %x (%s), opcode %x, egrbuf %x, " "len %x\n", eflags, emsg, opcode, etail, tlen); } else { /* * error packet, type of error unknown. * Probably type 3, but we don't know, so don't * even try to print the opcode, etc. */ ipath_dbg("Error Pkt, but no eflags! egrbuf %x, " "len %x\nhdrq@%lx;hdrq+%x rhf: %llx; " "hdr %llx %llx %llx %llx %llx\n", etail, tlen, (unsigned long) rc, l, (unsigned long long) rc[0], (unsigned long long) rc[1], (unsigned long long) rc[2], (unsigned long long) rc[3], (unsigned long long) rc[4], (unsigned long long) rc[5]); } l += rsize; if (l >= maxcnt) l = 0; /* * update for each packet, to help prevent overflows if we * have lots of packets. */ (void)ipath_write_ureg(dd, ur_rcvhdrhead, dd->ipath_rhdrhead_intr_off | l, 0); if (etype != RCVHQ_RCV_TYPE_EXPECTED) (void)ipath_write_ureg(dd, ur_rcvegrindexhead, etail, 0); } pkttot += i; dd->ipath_port0head = l; if (hdrqtail != (u32)le64_to_cpu(*dd->ipath_hdrqtailptr)) /* more arrived while we handled first batch */ goto gotmore; if (pkttot > ipath_stats.sps_maxpkts_call) ipath_stats.sps_maxpkts_call = pkttot; ipath_stats.sps_port0pkts += pkttot; ipath_stats.sps_avgpkts_call = ipath_stats.sps_port0pkts / ++totcalls;done: clear_bit(0, &dd->ipath_rcv_pending); smp_mb__after_clear_bit();bail:;}/** * ipath_update_pio_bufs - update shadow copy of the PIO availability map * @dd: the infinipath device * * called whenever our local copy indicates we have run out of send buffers * NOTE: This can be called from interrupt context by some code * and from non-interrupt context by ipath_getpiobuf(). */static void ipath_update_pio_bufs(struct ipath_devdata *dd){ unsigned long flags; int i; const unsigned piobregs = (unsigned)dd->ipath_pioavregs; /* If the generation (check) bits have changed, then we update the * busy bit for the corresponding PIO buffer. This algorithm will * modify positions to the value they already have in some cases * (i.e., no change), but it's faster than changing only the bits * that have changed. * * We would like to do this atomicly, to avoid spinlocks in the * critical send path, but that's not really possible, given the * type of changes, and that this routine could be called on * multiple cpu's simultaneously, so we lock in this routine only, * to avoid conflicting updates; all we change is the shadow, and * it's a single 64 bit memory location, so by definition the update * is atomic in terms of what other cpu's can see in testing the * bits. The spin_lock overhead isn't too bad, since it only * happens when all buffers are in use, so only cpu overhead, not * latency or bandwidth is affected. */#define _IPATH_ALL_CHECKBITS 0x5555555555555555ULL if (!dd->ipath_pioavailregs_dma) { ipath_dbg("Update shadow pioavail, but regs_dma NULL!\n"); return; } if (ipath_debug & __IPATH_VERBDBG) { /* only if packet debug and verbose */ volatile __le64 *dma = dd->ipath_pioavailregs_dma; unsigned long *shadow = dd->ipath_pioavailshadow; ipath_cdbg(PKT, "Refill avail, dma0=%llx shad0=%lx, " "d1=%llx s1=%lx, d2=%llx s2=%lx, d3=%llx " "s3=%lx\n", (unsigned long long) le64_to_cpu(dma[0]), shadow[0], (unsigned long long) le64_to_cpu(dma[1]), shadow[1], (unsigned long long) le64_to_cpu(dma[2]), shadow[2], (unsigned long long) le64_to_cpu(dma[3]), shadow[3]); if (piobregs > 4) ipath_cdbg( PKT, "2nd group, dma4=%llx shad4=%lx, " "d5=%llx s5=%lx, d6=%llx s6=%lx, " "d7=%llx s7=%lx\n", (unsigned long long) le64_to_cpu(dma[4]), shadow[4], (unsigned long long) le64_to_cpu(dma[5]), shadow[5], (unsigned long long) le64_to_cpu(dma[6]), shadow[6], (unsigned long long) le64_to_cpu(dma[7]), shadow[7]); } spin_lock_irqsave(&ipath_pioavail_lock, flags); for (i = 0; i < piobregs; i++) { u64 pchbusy, pchg, piov, pnew; /* * Chip Errata: bug 6641; even and odd qwords>3 are swapped */ if (i > 3) { if (i & 1) piov = le64_to_cpu( dd->ipath_pioavailregs_dma[i - 1]); else piov = le64_to_cpu( dd->ipath_pioavailregs_dma[i + 1]); } else piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]); pchg = _IPATH_ALL_CHECKBITS & ~(dd->ipath_pioavailshadow[i] ^ piov); pchbusy = pchg << INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT; if (pchg && (pchbusy & dd->ipath_pioavailshadow[i])) { pnew = dd->ipath_pioavailshadow[i] & ~pchbusy; pnew |= piov & pchbusy; dd->ipath_pioavailshadow[i] = pnew; } } spin_unlock_irqrestore(&ipath_pioavail_lock, flags);}/** * ipath_setrcvhdrsize - set the receive header size * @dd: the infinipath device * @rhdrsize: the receive header size * * called from user init code, and also layered driver init */int ipath_setrcvhdrsize(struct ipath_devdata *dd, unsigned rhdrsize){ int ret = 0; if (dd->ipath_flags & IPATH_RCVHDRSZ_SET) { if (dd->ipath_rcvhdrsize != rhdrsize) { dev_info(&dd->pcidev->dev, "Error: can't set protocol header " "size %u, already %u\n", rhdrsize, dd->ipath_rcvhdrsize); ret = -EAGAIN; } else ipath_cdbg(VERBOSE, "Reuse same protocol header " "size %u\n", dd->ipath_rcvhdrsize); } else if (rhdrsize > (dd->ipath_rcvhdrentsize - (sizeof(u64) / sizeof(u32)))) { ipath_dbg("Error: can't set protocol header size %u " "(> max %u)\n", rhdrsize, dd->ipath_rcvhdrentsize - (u32) (sizeof(u64) / sizeof(u32))); ret = -EOVERFLOW; } else { dd->ipath_flags |= IPATH_RCVHDRSZ_SET; dd->ipath_rcvhdrsize = rhdrsize; ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvhdrsize, dd->ipath_rcvhdrsize); ipath_cdbg(VERBOSE, "Set protocol header size to %u\n", dd->ipath_rcvhdrsize); } return ret;}/** * ipath_getpiobuf - find an available pio buffer * @dd: the infinipath device * @pbufnum: the buffer number is placed here * * do appropriate marking as busy, etc. * returns buffer number if one found (>=0), negative number is error. * Used by ipath_sma_send_pkt and ipath_layer_send */u32 __iomem *ipath_getpiobuf(struct ipath_devdata *dd, u32 * pbufnum){ int i, j, starti, updated = 0; unsigned piobcnt, iter; unsigned long flags; unsigned long *shadow = dd->ipath_pioavailshadow; u32 __iomem *buf; piobcnt = (unsigned)(dd->ipath_piobcnt2k + dd->ipath_piobcnt4k); starti = dd->ipath_lastport_piobuf; iter = piobcnt - starti; if (dd->ipath_upd_pio_shadow) { /* * Minor optimization. If we had no buffers on last call, * start out by doing the update; continue and do scan even * if no buffers were updated, to be paranoid */ ipath_update_pio_bufs(dd); /* we scanned here, don't do it at end of scan */ updated = 1; i = starti; } else i = dd->ipath_lastpioindex;rescan: /* * while test_and_set_bit() is atomic, we do that and then the * change_bit(), and the pair is not. See if this is the cause * of the remaining armlaunch errors. */ spin_lock_irqsave(&ipath_pioavail_lock, flags); for (j = 0; j < iter; j++, i++) { if (i >= piobcnt) i = starti; /* * To avoid bus lock overhead, we first find a candidate * buffer, then do the test and set, and continue if that * fails. */ if (test_bit((2 * i) + 1, shadow) || test_and_set_bit((2 * i) + 1, shadow)) continue; /* flip generation bit */ change_bit(2 * i, shadow); break; } spin_unlock_irqrestore(&ipath_pioavail_lock, flags); if (j == iter) { volatile __le64 *dma = dd->ipath_pioavailregs_dma; /* * first time through; shadow exhausted, but may be real * buffers available, so go see; if any updated, rescan * (once) */ if (!updated) { ipath_update_pio_bufs(dd); updated = 1; i = starti; goto rescan; } dd->ipath_upd_pio_shadow = 1; /* * not atomic, but if we lose one once in a while, that's OK */ ipath_stats.sps_nopiobufs++; if (!(++dd->ipath_consec_nopiobuf % 100000)) { ipath_dbg( "%u pio sends with no bufavail; dmacopy: " "%llx %llx %llx %llx; shadow: " "%lx %lx %lx %lx\n", dd->ipath_consec_nopiobuf, (unsigned long long) le64_to_cpu(dma[0]), (unsigned long long) le64_to_cpu(dma[1]), (unsigned long long) le64_to_cpu(dma[2]), (unsigned long long) le64_to_cpu(dma[3]), shadow[0], shadow[1], shadow[2], shadow[3]); /* * 4 buffers per byte, 4 registers above, cover rest * below */ if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > (sizeof(shadow[0]) * 4 * 4)) ipath_dbg("2nd group: dmacopy: %llx %llx " "%llx %llx; shadow: %lx %lx " "%lx %lx\n", (unsigned long long) le64_to_cpu(dma[4]), (unsigned long long) le64_to_cpu(dma[5]), (unsigned long long) le64_to_cpu(dma[6]), (unsigned long long) le64_to_cpu(dma[7]), shadow[4], shadow[5], shadow[6], shadow[7]); } buf = NULL; goto bail; } if (updated) /* * ran out of bufs, now some (at least this one we just * got) are now available, so tell the layered driver. */ __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE); /* * set next starting place. Since it's just an optimization, * it doesn't matter who wins on this, so no locking */ dd->ipath_lastpioindex = i + 1; if (dd->ipath_upd_pio_shadow) dd->ipath_upd_pio_shadow = 0; if (dd->ipath_consec_nopiobuf) dd->ipath_consec_nopiobuf = 0; if (i < dd->ipath_piobcnt2k) buf = (u32 __iomem *) (dd->ipath_pio2kbase + i * dd->ipath_palign); else buf = (u32 __iomem *) (dd->ipath_pio4kbase + (i - dd->ipath_piobcnt2k) * dd->ipath_4kalign); ipath_cdbg(VERBOSE, "Return piobuf%u %uk @ %p\n", i, (i < dd->ipath_piobcnt2k) ? 2 : 4, buf); if (pbufnum) *pbufnum = i;bail: return buf;}/** * ipath_create_rcvhdrq - create a receive header queue * @dd: the infinipath device * @pd: the port data * * this *must* be physically contiguous memory, and for now, * that limits it to what kmalloc can do. */int ipath_create_rcvhdrq(struct ipath_devdata *dd, struct ipath_portdata *pd){ int ret = 0, amt; amt = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize * sizeof(u32), PAGE_SIZE); if (!pd->port_rcvhdrq) { /* * not using REPEAT isn't viable; at 128KB, we can easily * fail this. The problem with REPEAT is we can block here * "forever". There isn't an inbetween, unfortunately. We * could reduce the risk by never freeing the rcvhdrq except * at unload, but even then, the first time a port is used, * we could delay for some time... */ gfp_t gfp_flags = GFP_USER | __GFP_COMP; pd->port_rcvhdrq = dma_alloc_coherent( &dd->pcidev->dev, amt, &pd->port_rcvhdrq_phys, gfp_flags); if (!pd->port_rcvhdrq) { ipath_dev_err(dd, "attempt to allocate %d bytes " "for port %u rcvhdrq failed\n", amt, pd->port_port); ret = -ENOMEM; goto bail; } pd->port_rcvhdrq_size = amt; ipath_cdbg(VERBOSE, "%d pages at %p (phys %lx) size=%lu " "for port %u rcvhdr Q\n", amt >> PAGE_SHIFT, pd->port_rcvhdrq, (unsigned long) pd->port_rcvhdrq_phys, (unsigned long) pd->port_rcvhdrq_size, pd->port_port); } else { /* * clear for security, sanity, and/or debugging, each * time we reuse */ memset(pd->port_rcvhdrq, 0, amt); } /* * tell chip each time we init it, even if we are re-using previous * memory (we zero it at process close) */ ipath_cdbg(VERBOSE, "writing port %d rcvhdraddr as %lx\n", pd->port_port, (unsigned long) pd->port_rcvhdrq_phys); ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr, pd->port_port, pd->port_rcvhdrq_phys); ret = 0;bail: return ret;}int ipath_waitfor_complete(struct ipath_devdata *dd, ipath_kreg reg_id, u64 bits_to_wait_for, u64 * valp){ unsigned long timeout; u64 lastval, val; int ret; lastval = ipath_read_kreg64(dd, reg_id); /* wait a ridiculously long time */ timeout = jiffies + msecs_to_jiffies(5); do { val = ipath_read_kreg64(dd, reg_id); /* set so they have something, even on failures. */ *valp = val; if ((val & bits_to_wait_for) == bits_to_wait_for) { ret = 0; break; } if (val != lastval) ipath_cdbg(VERBOSE, "Changed from %llx to %llx, " "waiting for %llx bits\n", (unsigned long long) lastval, (unsigned long long) val, (unsigned long long) bits_to_wait_for); cond_resched(); if (time_after(jiffies, timeout)) { ipath_dbg("Didn't get bits %llx in register 0x%x, " "got %llx\n", (unsigned long long) bits_to_wait_for, reg_id, (unsigned long long) *valp); ret = -ENODEV; break; } } while (1); return ret;}/** * ipath_waitfor_mdio_cmdready - wait for last command to complete * @dd: the infinipath device * * Like ipath_waitfor_complete(), but we wait for the CMDVALID bit to go * away indicating the last command has completed. It doesn't return data */int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd){ unsigned long timeout; u64 val; int ret; /* wait a ridiculously long time */ timeout = jiffies + msecs_to_jiffies(5); do { val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_mdio); if (!(val & IPATH_MDIO_CMDVALID)) { ret = 0; break; } cond_resched(); if (time_after(jiffies, timeout)) { ipath_dbg("CMDVALID stuck in mdio reg? (%llx)\n", (unsigned long long) val);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?