static int hv_kvp_attach(device_t dev) { int ret = KVP_SUCCESS; #ifdef DEBUG printf("hv_kvp_attach: called\n"); #endif kvp_hv_dev = vmbus_get_devctx(dev); device_printf(dev, "Hyper-V Service attaching: %s\n", "Hyper-V KVP Service\n"); #if 0 ret = hv_vmbus_channel_open(hv_dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL, 0, hv_kvp_callback, hv_dev->channel); if (ret) printf("hv_kvp_attach: hv_vmbus_channel_open failed\n"); #endif kvp_msg_state.kvp_rcv_timer = timeout(kvp_user_rcv_timer, NULL, 10); if (kvp_msg_state.kvp_rcv_timer.callout == NULL) { printf("hv_kvp_attach: timer creation failed\n"); ret = -1; } return (ret); }
static int hv_kvp_detach(device_t dev) { struct hv_device* hv_dev; #ifdef DEBUG printf("hv_kvp_detach: called\n"); #endif hv_dev = vmbus_get_devctx(dev); if (kvp_hv_dev != hv_dev) printf("hv_kvp_detach: Closing an INVALID kvp device\n"); hv_vmbus_channel_close(hv_dev->channel); kvp_hv_dev = NULL; return (0); }
static int hv_util_detach(device_t dev) { struct hv_device* hv_dev; struct hv_vmbus_service* service; size_t receive_buffer_offset; hv_dev = vmbus_get_devctx(dev); hv_vmbus_channel_close(hv_dev->channel); service = device_get_softc(dev); receive_buffer_offset = service - &service_table[0]; if (service->work_queue != NULL) hv_work_queue_close(service->work_queue); free(receive_buffer[receive_buffer_offset], M_DEVBUF); receive_buffer[receive_buffer_offset] = NULL; return (0); }
static int hv_util_attach(device_t dev) { struct hv_device* hv_dev; struct hv_vmbus_service* service; int ret; size_t receive_buffer_offset; hv_dev = vmbus_get_devctx(dev); service = device_get_softc(dev); receive_buffer_offset = service - &service_table[0]; device_printf(dev, "Hyper-V Service attaching: %s\n", service->name); receive_buffer[receive_buffer_offset] = malloc(4 * PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO); if (service->init != NULL) { ret = service->init(service); if (ret) { ret = ENODEV; goto error0; } } ret = hv_vmbus_channel_open(hv_dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0, service->callback, hv_dev->channel); if (ret) goto error0; return (0); error0: free(receive_buffer[receive_buffer_offset], M_DEVBUF); receive_buffer[receive_buffer_offset] = NULL; return (ret); }
/* * Standard detach entry point */ static int netvsc_detach(device_t dev) { struct hv_device *hv_device = vmbus_get_devctx(dev); printf("netvsc_detach\n"); /* * XXXKYS: Need to clean up all our * driver state; this is the driver * unloading. */ /* * XXXKYS: Need to stop outgoing traffic and unregister * the netdevice. */ hv_rf_on_device_remove(hv_device, HV_RF_NV_DESTROY_CHANNEL); return (0); }
static int hn_start_locked (struct ifnet *ifp) { int ret = 0; hn_softc_t *sc = ifp->if_softc; NETVSC_DRIVER_OBJECT *net_drv_obj = &g_netvsc_drv.drv_obj; struct device_context *device_ctx = vmbus_get_devctx(sc->hn_dev); int i = 0; unsigned char *buf; NETVSC_PACKET* packet; int num_frags = 0; int retries = 0; struct mbuf *m_head, *m; int len = 0; int xlen = 0; DPRINT_ENTER(NETVSC_DRV); while (!IFQ_DRV_IS_EMPTY(&sc->hn_ifp->if_snd)) { IFQ_DRV_DEQUEUE(&sc->hn_ifp->if_snd, m_head); if (m_head == NULL) { break; } len = 0; num_frags = 0; xlen = 0; for (m = m_head; m != NULL; m = m->m_next) { if (m->m_len != 0) { num_frags++; len += m->m_len; } } DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d", len); // Add 1 for skb->data and any additional ones requested num_frags += net_drv_obj->AdditionalRequestPageBufferCount; // Allocate a netvsc packet based on # of frags. buf = malloc(16 + sizeof(NETVSC_PACKET) + (num_frags * sizeof(PAGE_BUFFER)) + net_drv_obj->RequestExtSize, M_DEVBUF, M_ZERO | M_WAITOK); if (buf == NULL) { DPRINT_ERR(NETVSC_DRV, "unable to allocate NETVSC_PACKET"); return -1; } packet = (NETVSC_PACKET *)(buf + 16); *(vm_offset_t *)buf = 0; packet->Extension = (void*)((unsigned long)packet + sizeof(NETVSC_PACKET) + (num_frags * sizeof(PAGE_BUFFER))) ; // Setup the rndis header packet->PageBufferCount = num_frags; // TODO: Flush all write buffers/ memory fence ??? //wmb(); // Initialize it from the mbuf packet->TotalDataBufferLength = len; // Start filling in the page buffers starting at // AdditionalRequestPageBufferCount offset i = net_drv_obj->AdditionalRequestPageBufferCount; for (m = m_head; m != NULL; m = m->m_next) { if (m->m_len) { vm_offset_t paddr = vtophys(mtod(m, vm_offset_t)); packet->PageBuffers[i].Pfn = paddr >> PAGE_SHIFT; packet->PageBuffers[i].Offset = paddr & (PAGE_SIZE - 1); packet->PageBuffers[i].Length = m->m_len; DPRINT_DBG(NETVSC_DRV, "vaddr: %p, pfn: %llx, Off: %x, len: %x\n", paddr, packet->PageBuffers[i].Pfn, packet->PageBuffers[i].Offset, packet->PageBuffers[i].Length); i++; } } // Set the completion routine /* * Fixme: Research the netvsc_xmit_completion() function * and figure out what to do about it. It is currently too * messed up to port easily. */ packet->Completion.Send.OnSendCompletion = netvsc_xmit_completion; packet->Completion.Send.SendCompletionContext = packet; packet->Completion.Send.SendCompletionTid = (ULONG_PTR)m_head; retry_send: critical_enter(); ret = net_drv_obj->OnSend(&device_ctx->device_obj, packet); critical_exit(); if (ret == 0) { ifp->if_opackets++; if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m_head); // if (ifp->if_timer == 0) // ifp->if_timer = 5; } else { retries++; if (retries < 4) { DPRINT_ERR(NETVSC_DRV, "unable to send...retrying %d...", retries); goto retry_send; } DPRINT_INFO(NETVSC_DRV, "net device (%p) stopping", sc); IF_PREPEND(&ifp->if_snd, m_head); ifp->if_drv_flags |= IFF_DRV_OACTIVE; ret = -1; // net_device_ctx->stats.tx_dropped++; // Null it since the caller will free it instead of // the completion routine packet->Completion.Send.SendCompletionTid = 0; // Release the resources since we will not get any // send completion netvsc_xmit_completion((void*)packet); } }
static int netvsc_attach(device_t dev) { NETVSC_DRIVER_OBJECT *net_drv_obj = &g_netvsc_drv.drv_obj; struct device_context *device_ctx = vmbus_get_devctx(dev); NETVSC_DEVICE_INFO device_info; hn_softc_t *sc; int unit = device_get_unit(dev); struct ifnet *ifp; int ret; /* Don't add new nic if NetScaler is already running */ /* Fixme: Is this correct? */ sc = device_get_softc(dev); if (sc == NULL) { DPRINT_ERR(NETVSC_DRV, "%s%d not configured", NETVSC_DEVNAME, unit); ret = ENOMEM; return ret; } if (!net_drv_obj->Base.OnDeviceAdd) { DPRINT_ERR(NETVSC_DRV, "OnDeviceAdd is not initialized"); return -1; } bzero(sc, sizeof(hn_softc_t)); sc->hn_unit = unit; sc->hn_dev = dev; SN_LOCK_INIT(sc, "NetVSCLock"); sc->hn_dev_obj = &device_ctx->device_obj; device_ctx->device_obj.Driver = &g_netvsc_drv.drv_obj.Base; ret = net_drv_obj->Base.OnDeviceAdd(&device_ctx->device_obj, (void*)&device_info); if (ret != 0) { DPRINT_ERR(NETVSC_DRV, "unable to add netvsc device (ret %d)", ret); return ret; } if (device_info.LinkState == 0) { sc->hn_carrier = 1; } #ifdef REMOVED /* * Fixme: _ac_enaddr no longer exists in 8.2 "struct arpcom" * So, we don't need to populate it. */ memcpy((void *)&sc->arpcom._ac_enaddr, (void *)&device_info.MacAddr, ETH_ALEN); DPRINT_DBG(NETVSC_DRV, "netvsc_attach: mac address: %02x %02x %02x %02x %02x %02x\n", device_info.MacAddr[0], device_info.MacAddr[1], device_info.MacAddr[2], device_info.MacAddr[3], device_info.MacAddr[4], device_info.MacAddr[5]); #endif ifp = sc->hn_ifp = sc->arpcom.ac_ifp = if_alloc(IFT_ETHER); ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_dunit = unit; ifp->if_dname = NETVSC_DEVNAME; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = hn_ioctl; ifp->if_output = ether_output; ifp->if_start = hn_start; /* Fixme: Should have this */ // ifp->if_watchdog = hn_watchdog; ifp->if_init = (void*)hn_ifinit; ifp->if_mtu = ETHERMTU; IFQ_SET_MAXLEN(&ifp->if_snd, 512); ifp->if_snd.ifq_drv_maxlen = 511; IFQ_SET_READY(&ifp->if_snd); #ifdef REMOVED /* * Fixme: _ac_enaddr no longer exists in 8.2 "struct arpcom" */ ether_ifattach(ifp, sc->arpcom._ac_enaddr); #endif // Fixme -- should we have a copy of MAC addr in softc? ether_ifattach(ifp, device_info.MacAddr); return 0; }
/* * Start a transmit of one or more packets */ static int hn_start_locked(struct ifnet *ifp) { hn_softc_t *sc = ifp->if_softc; struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev); uint8_t *buf; netvsc_packet *packet; struct mbuf *m_head, *m; struct mbuf *mc_head = NULL; int i; int num_frags; int len; int xlen; int rppi_size; int retries = 0; int ret = 0; while (!IFQ_DRV_IS_EMPTY(&sc->hn_ifp->if_snd)) { IFQ_DRV_DEQUEUE(&sc->hn_ifp->if_snd, m_head); if (m_head == NULL) { break; } len = 0; num_frags = 0; xlen = 0; /* Walk the mbuf list computing total length and num frags */ for (m = m_head; m != NULL; m = m->m_next) { if (m->m_len != 0) { num_frags++; len += m->m_len; } } /* * Reserve the number of pages requested. Currently, * one page is reserved for the message in the RNDIS * filter packet */ num_frags += HV_RF_NUM_TX_RESERVED_PAGE_BUFS; /* If exceeds # page_buffers in netvsc_packet */ if (num_frags > NETVSC_PACKET_MAXPAGE) { m_freem(m); return (EINVAL); } rppi_size = 0; if (m_head->m_flags & M_VLANTAG) { rppi_size = sizeof(rndis_per_packet_info) + sizeof(ndis_8021q_info); } /* * Allocate a buffer with space for a netvsc packet plus a * number of reserved areas. First comes a (currently 16 * bytes, currently unused) reserved data area. Second is * the netvsc_packet, which includes (currently 4) page * buffers. Third (optional) is a rndis_per_packet_info * struct, but only if a VLAN tag should be inserted into the * Ethernet frame by the Hyper-V infrastructure. Fourth is * an area reserved for an rndis_filter_packet struct. * Changed malloc to M_NOWAIT to avoid sleep under spin lock. * No longer reserving extra space for page buffers, as they * are already part of the netvsc_packet. */ buf = malloc(HV_NV_PACKET_OFFSET_IN_BUF + sizeof(netvsc_packet) + rppi_size + sizeof(rndis_filter_packet), M_DEVBUF, M_ZERO | M_NOWAIT); if (buf == NULL) { m_freem(m); return (ENOMEM); } packet = (netvsc_packet *)(buf + HV_NV_PACKET_OFFSET_IN_BUF); *(vm_offset_t *)buf = HV_NV_SC_PTR_OFFSET_IN_BUF; /* * extension points to the area reserved for the * rndis_filter_packet, which is placed just after * the netvsc_packet (and rppi struct, if present; * length is updated later). */ packet->extension = packet + 1; /* Set up the rndis header */ packet->page_buf_count = num_frags; /* Initialize it from the mbuf */ packet->tot_data_buf_len = len; /* * If the Hyper-V infrastructure needs to embed a VLAN tag, * initialize netvsc_packet and rppi struct values as needed. */ if (rppi_size) { /* Lower layers need the VLAN TCI */ packet->vlan_tci = m_head->m_pkthdr.ether_vtag; } /* * Fill the page buffers with mbuf info starting at index * HV_RF_NUM_TX_RESERVED_PAGE_BUFS. */ i = HV_RF_NUM_TX_RESERVED_PAGE_BUFS; for (m = m_head; m != NULL; m = m->m_next) { if (m->m_len) { vm_offset_t paddr = vtophys(mtod(m, vm_offset_t)); packet->page_buffers[i].pfn = paddr >> PAGE_SHIFT; packet->page_buffers[i].offset = paddr & (PAGE_SIZE - 1); packet->page_buffers[i].length = m->m_len; i++; } } /* * If bpf, copy the mbuf chain. This is less expensive than * it appears; the mbuf clusters are not copied, only their * reference counts are incremented. * Needed to avoid a race condition where the completion * callback is invoked, freeing the mbuf chain, before the * bpf_mtap code has a chance to run. */ if (ifp->if_bpf) { mc_head = m_copypacket(m_head, M_DONTWAIT); } retry_send: /* Set the completion routine */ packet->compl.send.on_send_completion = netvsc_xmit_completion; packet->compl.send.send_completion_context = packet; packet->compl.send.send_completion_tid = (uint64_t)m_head; /* Removed critical_enter(), does not appear necessary */ ret = hv_rf_on_send(device_ctx, packet); if (ret == 0) { ifp->if_opackets++; /* if bpf && mc_head, call bpf_mtap code */ if (mc_head) { ETHER_BPF_MTAP(ifp, mc_head); } } else { retries++; if (retries < 4) { goto retry_send; } IF_PREPEND(&ifp->if_snd, m_head); ifp->if_drv_flags |= IFF_DRV_OACTIVE; /* * Null the mbuf pointer so the completion function * does not free the mbuf chain. We just pushed the * mbuf chain back on the if_snd queue. */ packet->compl.send.send_completion_tid = 0; /* * Release the resources since we will not get any * send completion */ netvsc_xmit_completion(packet); } /* if bpf && mc_head, free the mbuf chain copy */ if (mc_head) { m_freem(mc_head); } }
/* * Standard attach entry point. * * Called when the driver is loaded. It allocates needed resources, * and initializes the "hardware" and software. */ static int netvsc_attach(device_t dev) { struct hv_device *device_ctx = vmbus_get_devctx(dev); netvsc_device_info device_info; hn_softc_t *sc; int unit = device_get_unit(dev); struct ifnet *ifp; int ret; netvsc_init(); sc = device_get_softc(dev); if (sc == NULL) { return (ENOMEM); } bzero(sc, sizeof(hn_softc_t)); sc->hn_unit = unit; sc->hn_dev = dev; NV_LOCK_INIT(sc, "NetVSCLock"); sc->hn_dev_obj = device_ctx; ifp = sc->hn_ifp = sc->arpcom.ac_ifp = if_alloc(IFT_ETHER); ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_dunit = unit; ifp->if_dname = NETVSC_DEVNAME; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = hn_ioctl; ifp->if_start = hn_start; ifp->if_init = hn_ifinit; /* needed by hv_rf_on_device_add() code */ ifp->if_mtu = ETHERMTU; IFQ_SET_MAXLEN(&ifp->if_snd, 512); ifp->if_snd.ifq_drv_maxlen = 511; IFQ_SET_READY(&ifp->if_snd); /* * Tell upper layers that we support full VLAN capability. */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; ret = hv_rf_on_device_add(device_ctx, &device_info); if (ret != 0) { if_free(ifp); return (ret); } if (device_info.link_state == 0) { sc->hn_carrier = 1; } ether_ifattach(ifp, device_info.mac_addr); return (0); }