static ssize_t tool_link_event_write(struct file *filep, const char __user *ubuf, size_t size, loff_t *offp) { struct tool_ctx *tc = filep->private_data; char buf[32]; size_t buf_size; bool val; int rc; buf_size = min(size, (sizeof(buf) - 1)); if (copy_from_user(buf, ubuf, buf_size)) return -EFAULT; buf[buf_size] = '\0'; rc = strtobool(buf, &val); if (rc) return rc; if (wait_event_interruptible(tc->link_wq, ntb_link_is_up(tc->ntb, NULL, NULL) == val)) return -ERESTART; return size; }
static void perf_link_event(void *ctx) { struct perf_ctx *perf = ctx; if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1) schedule_delayed_work(&perf->link_work, 2*HZ); else schedule_work(&perf->link_cleanup); }
static void perf_link_work(struct work_struct *work) { struct perf_ctx *perf = container_of(work, struct perf_ctx, link_work.work); struct ntb_dev *ndev = perf->ntb; struct pci_dev *pdev = ndev->pdev; u32 val; u64 size; int rc; dev_dbg(&perf->ntb->pdev->dev, "%s called\n", __func__); size = perf->mw.phys_size; if (max_mw_size && size > max_mw_size) size = max_mw_size; ntb_peer_spad_write(ndev, MW_SZ_HIGH, upper_32_bits(size)); ntb_peer_spad_write(ndev, MW_SZ_LOW, lower_32_bits(size)); ntb_peer_spad_write(ndev, VERSION, PERF_VERSION); /* now read what peer wrote */ val = ntb_spad_read(ndev, VERSION); if (val != PERF_VERSION) { dev_dbg(&pdev->dev, "Remote version = %#x\n", val); goto out; } val = ntb_spad_read(ndev, MW_SZ_HIGH); size = (u64)val << 32; val = ntb_spad_read(ndev, MW_SZ_LOW); size |= val; dev_dbg(&pdev->dev, "Remote MW size = %#llx\n", size); rc = perf_set_mw(perf, size); if (rc) goto out1; perf->link_is_up = true; wake_up(&perf->link_wq); return; out1: perf_free_mw(perf); out: if (ntb_link_is_up(ndev, NULL, NULL) == 1) schedule_delayed_work(&perf->link_work, msecs_to_jiffies(PERF_LINK_DOWN_TIMEOUT)); }
static ssize_t tool_link_read(struct file *filep, char __user *ubuf, size_t size, loff_t *offp) { struct tool_ctx *tc = filep->private_data; char buf[3]; buf[0] = ntb_link_is_up(tc->ntb, NULL, NULL) ? 'Y' : 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(ubuf, size, offp, buf, 2); }
/* Link Event handler */ static void ntb_transport_event_callback(void *data) { struct ntb_transport_ctx *nt = data; if (ntb_link_is_up(nt->ntb, NULL, NULL)) { ntb_printf(1, "HW link up\n"); callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt); } else { ntb_printf(1, "HW link down\n"); taskqueue_enqueue(taskqueue_swi, &nt->link_cleanup); } }
static void tool_link_event(void *ctx) { struct tool_ctx *tc = ctx; enum ntb_speed speed; enum ntb_width width; int up; up = ntb_link_is_up(tc->ntb, &speed, &width); dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n", up ? "up" : "down", speed, width); wake_up(&tc->link_wq); }
static void perf_link_event(void *ctx) { struct perf_ctx *perf = ctx; if (ntb_link_is_up(perf->ntb, NULL, NULL) == 1) { schedule_delayed_work(&perf->link_work, 2*HZ); } else { dev_dbg(&perf->ntb->pdev->dev, "link down\n"); if (!perf->link_is_up) cancel_delayed_work_sync(&perf->link_work); perf->link_is_up = false; } }
static int pp_find_next_peer(struct pp_ctx *pp) { u64 link, out_db; int pidx; link = ntb_link_is_up(pp->ntb, NULL, NULL); /* Find next available peer */ if (link & pp->nmask) pidx = __ffs64(link & pp->nmask); else if (link & pp->pmask) pidx = __ffs64(link & pp->pmask); else return -ENODEV; out_db = BIT_ULL(ntb_peer_port_number(pp->ntb, pidx)); spin_lock(&pp->lock); pp->out_pidx = pidx; pp->out_db = out_db; spin_unlock(&pp->lock); return 0; }
/* Link bring up */ static void ntb_transport_link_work(void *arg) { struct ntb_transport_ctx *nt = arg; struct ntb_softc *ntb = nt->ntb; struct ntb_transport_qp *qp; uint64_t val64, size; uint32_t val; unsigned i; int rc; /* send the local info, in the opposite order of the way we read it */ for (i = 0; i < nt->mw_count; i++) { size = nt->mw_vec[i].phys_size; if (max_mw_size != 0 && size > max_mw_size) size = max_mw_size; ntb_peer_spad_write(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2), size >> 32); ntb_peer_spad_write(ntb, IF_NTB_MW0_SZ_LOW + (i * 2), size); } ntb_peer_spad_write(ntb, IF_NTB_NUM_MWS, nt->mw_count); ntb_peer_spad_write(ntb, IF_NTB_NUM_QPS, nt->qp_count); ntb_peer_spad_write(ntb, IF_NTB_VERSION, NTB_TRANSPORT_VERSION); /* Query the remote side for its info */ val = 0; ntb_spad_read(ntb, IF_NTB_VERSION, &val); if (val != NTB_TRANSPORT_VERSION) goto out; ntb_spad_read(ntb, IF_NTB_NUM_QPS, &val); if (val != nt->qp_count) goto out; ntb_spad_read(ntb, IF_NTB_NUM_MWS, &val); if (val != nt->mw_count) goto out; for (i = 0; i < nt->mw_count; i++) { ntb_spad_read(ntb, IF_NTB_MW0_SZ_HIGH + (i * 2), &val); val64 = (uint64_t)val << 32; ntb_spad_read(ntb, IF_NTB_MW0_SZ_LOW + (i * 2), &val); val64 |= val; rc = ntb_set_mw(nt, i, val64); if (rc != 0) goto free_mws; } nt->link_is_up = true; ntb_printf(1, "transport link up\n"); for (i = 0; i < nt->qp_count; i++) { qp = &nt->qp_vec[i]; ntb_transport_setup_qp_mw(nt, i); if (qp->client_ready) callout_reset(&qp->link_work, 0, ntb_qp_link_work, qp); } return; free_mws: for (i = 0; i < nt->mw_count; i++) ntb_free_mw(nt, i); out: if (ntb_link_is_up(ntb, NULL, NULL)) callout_reset(&nt->link_work, NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_transport_link_work, nt); }