/* Link down event*/ static void ntb_transport_link_cleanup(struct ntb_netdev *nt) { int i; if (nt->transport_link == NTB_LINK_DOWN) callout_drain(&nt->link_work); else nt->transport_link = NTB_LINK_DOWN; /* Pass along the info to any clients */ for (i = 0; i < nt->max_qps; i++) if (!test_bit(i, &nt->qp_bitmap)) ntb_qp_link_down(&nt->qps[i]); /* * The scratchpad registers keep the values if the remote side * goes down, blast them now to give them a sane value the next * time they are accessed */ for (i = 0; i < IF_NTB_MAX_SPAD; i++) ntb_write_local_spad(nt->ntb, i, 0); }
static int ntb_process_rxc(struct ntb_transport_qp *qp) { struct ntb_payload_header *hdr; struct ntb_queue_entry *entry; void *offset; offset = (void *) ((char *)qp->rx_buff + qp->rx_max_frame * qp->rx_index); hdr = (void *) ((char *)offset + qp->rx_max_frame - sizeof(struct ntb_payload_header)); CTR1(KTR_NTB, "RX: process_rxc rx_index = %u", qp->rx_index); entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); if (entry == NULL) { qp->rx_err_no_buf++; CTR0(KTR_NTB, "RX: No entries in rx_pend_q"); return (ENOMEM); } callout_stop(&qp->rx_full); CTR1(KTR_NTB, "RX: rx entry %p from rx_pend_q", entry); if ((hdr->flags & IF_NTB_DESC_DONE_FLAG) == 0) { CTR1(KTR_NTB, "RX: hdr not done. Returning entry %p to rx_pend_q", entry); ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); qp->rx_ring_empty++; return (EAGAIN); } if (hdr->ver != (uint32_t) qp->rx_pkts) { CTR3(KTR_NTB,"RX: ver != rx_pkts (%x != %lx). " "Returning entry %p to rx_pend_q", hdr->ver, qp->rx_pkts, entry); ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); qp->rx_err_ver++; return (EIO); } if ((hdr->flags & IF_NTB_LINK_DOWN_FLAG) != 0) { ntb_qp_link_down(qp); CTR1(KTR_NTB, "RX: link down. adding entry %p back to rx_pend_q", entry); ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); goto out; } if (hdr->len <= entry->len) { entry->len = hdr->len; ntb_rx_copy_task(qp, entry, offset); } else { CTR1(KTR_NTB, "RX: len too long. Returning entry %p to rx_pend_q", entry); ntb_list_add(&qp->ntb_rx_pend_q_lock, entry, &qp->rx_pend_q); qp->rx_err_oflow++; } qp->rx_bytes += hdr->len; qp->rx_pkts++; CTR1(KTR_NTB, "RX: received %ld rx_pkts", qp->rx_pkts); out: /* Ensure that the data is globally visible before clearing the flag */ wmb(); hdr->flags = 0; /* TODO: replace with bus_space_write */ qp->rx_info->entry = qp->rx_index; qp->rx_index++; qp->rx_index %= qp->rx_max_entry; return (0); }
static int ntb_process_rxc(struct ntb_transport_qp *qp) { struct ntb_payload_header *hdr; struct ntb_queue_entry *entry; caddr_t offset; offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index; hdr = (void *)(offset + qp->rx_max_frame - sizeof(struct ntb_payload_header)); CTR1(KTR_NTB, "RX: process_rxc rx_index = %u", qp->rx_index); if ((hdr->flags & IF_NTB_DESC_DONE_FLAG) == 0) { CTR0(KTR_NTB, "RX: hdr not done"); qp->rx_ring_empty++; return (EAGAIN); } if ((hdr->flags & IF_NTB_LINK_DOWN_FLAG) != 0) { CTR0(KTR_NTB, "RX: link down"); ntb_qp_link_down(qp); hdr->flags = 0; return (EAGAIN); } if (hdr->ver != (uint32_t)qp->rx_pkts) { CTR2(KTR_NTB,"RX: ver != rx_pkts (%x != %lx). " "Returning entry to rx_pend_q", hdr->ver, qp->rx_pkts); qp->rx_err_ver++; return (EIO); } entry = ntb_list_mv(&qp->ntb_rx_q_lock, &qp->rx_pend_q, &qp->rx_post_q); if (entry == NULL) { qp->rx_err_no_buf++; CTR0(KTR_NTB, "RX: No entries in rx_pend_q"); return (EAGAIN); } callout_stop(&qp->rx_full); CTR1(KTR_NTB, "RX: rx entry %p from rx_pend_q", entry); entry->x_hdr = hdr; entry->index = qp->rx_index; if (hdr->len > entry->len) { CTR2(KTR_NTB, "RX: len too long. Wanted %ju got %ju", (uintmax_t)hdr->len, (uintmax_t)entry->len); qp->rx_err_oflow++; entry->len = -EIO; entry->flags |= IF_NTB_DESC_DONE_FLAG; taskqueue_enqueue(taskqueue_swi, &qp->rx_completion_task); } else { qp->rx_bytes += hdr->len; qp->rx_pkts++; CTR1(KTR_NTB, "RX: received %ld rx_pkts", qp->rx_pkts); entry->len = hdr->len; ntb_memcpy_rx(qp, entry, offset); } qp->rx_index++; qp->rx_index %= qp->rx_max_entry; return (0); }