/*++ Name: netvsc_drv_init() Desc: NetVsc driver initialization --*/ int netvsc_drv_init(PFN_DRIVERINITIALIZE pfn_drv_init) { int ret = 0; NETVSC_DRIVER_OBJECT *net_drv_obj=&g_netvsc_drv.drv_obj; struct driver_context *drv_ctx=&g_netvsc_drv.drv_ctx; DPRINT_ENTER(NETVSC_DRV); vmbus_get_interface(&net_drv_obj->Base.VmbusChannelInterface); net_drv_obj->RingBufferSize = netvsc_ringbuffer_size; /* Fixme: warning: assignment from incompatible pointer type */ net_drv_obj->OnReceiveCallback = netvsc_recv_callback; net_drv_obj->OnLinkStatusChanged = netvsc_linkstatus_callback; // Callback to client driver to complete the initialization pfn_drv_init(&net_drv_obj->Base); memcpy(&drv_ctx->class_id, &net_drv_obj->Base.deviceType, sizeof(GUID)); // The driver belongs to vmbus vmbus_child_driver_register(drv_ctx); DPRINT_EXIT(NETVSC_DRV); return ret; }
static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo) { struct storvsc_device_info *deviceInfo; int ret = 0; DPRINT_ENTER(BLKVSC); deviceInfo = (struct storvsc_device_info *)AdditionalInfo; ret = StorVscOnDeviceAdd(Device, AdditionalInfo); if (ret != 0) { DPRINT_EXIT(BLKVSC); return ret; } /* * We need to use the device instance guid to set the path and target * id. For IDE devices, the device instance id is formatted as * <bus id> * - <device id> - 8899 - 000000000000. */ deviceInfo->PathId = Device->deviceInstance.data[3] << 24 | Device->deviceInstance.data[2] << 16 | Device->deviceInstance.data[1] << 8 | Device->deviceInstance.data[0]; deviceInfo->TargetId = Device->deviceInstance.data[5] << 8 | Device->deviceInstance.data[4]; DPRINT_EXIT(BLKVSC); return ret; }
static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice) { struct nvsp_message *revokePacket; int ret = 0; DPRINT_ENTER(NETVSC); if (NetDevice->ReceiveSectionCount) { DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeReceiveBuffer..."); revokePacket = &NetDevice->RevokePacket; memset(revokePacket, 0, sizeof(struct nvsp_message)); revokePacket->Header.MessageType = NvspMessage1TypeRevokeReceiveBuffer; revokePacket->Messages.Version1Messages.RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket( NetDevice->Device, revokePacket, sizeof(struct nvsp_message), (unsigned long)revokePacket, VmbusPacketTypeDataInBand, 0); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to send revoke receive " "buffer to netvsp"); DPRINT_EXIT(NETVSC); return -1; } } if (NetDevice->ReceiveBufferGpadlHandle) { DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL..."); ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl( NetDevice->Device, NetDevice->ReceiveBufferGpadlHandle); if (ret != 0) { DPRINT_ERR(NETVSC, "unable to teardown receive buffer's gpadl"); DPRINT_EXIT(NETVSC); return -1; } NetDevice->ReceiveBufferGpadlHandle = 0; } if (NetDevice->ReceiveBuffer) { DPRINT_INFO(NETVSC, "Freeing up receive buffer..."); osd_PageFree(NetDevice->ReceiveBuffer, NetDevice->ReceiveBufferSize >> PAGE_SHIFT); NetDevice->ReceiveBuffer = NULL; }
static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo) { u32 *irqvector = AdditionalInfo; int ret; DPRINT_ENTER(VMBUS); gDevice = dev; memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(struct hv_guid)); /* strcpy(dev->name, "vmbus"); */ /* SynIC setup... */ on_each_cpu(HvSynicInit, (void *)irqvector, 1); /* Connect to VMBus in the root partition */ ret = VmbusConnect(); /* VmbusSendEvent(device->localPortId+1); */ DPRINT_EXIT(VMBUS); return ret; }
static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv)) { struct netvsc_driver *net_drv_obj = &g_netvsc_drv.drv_obj; struct driver_context *drv_ctx = &g_netvsc_drv.drv_ctx; int ret; DPRINT_ENTER(NETVSC_DRV); vmbus_get_interface(&net_drv_obj->Base.VmbusChannelInterface); net_drv_obj->RingBufferSize = ring_size * PAGE_SIZE; net_drv_obj->OnReceiveCallback = netvsc_recv_callback; net_drv_obj->OnLinkStatusChanged = netvsc_linkstatus_callback; /* Callback to client driver to complete the initialization */ drv_init(&net_drv_obj->Base); drv_ctx->driver.name = net_drv_obj->Base.name; memcpy(&drv_ctx->class_id, &net_drv_obj->Base.deviceType, sizeof(struct hv_guid)); drv_ctx->probe = netvsc_probe; drv_ctx->remove = netvsc_remove; /* The driver belongs to vmbus */ ret = vmbus_child_driver_register(drv_ctx); DPRINT_EXIT(NETVSC_DRV); return ret; }
static int VmbusOnISR(struct hv_driver *drv) { int ret = 0; int cpu = smp_processor_id(); void *page_addr; struct hv_message *msg; union hv_synic_event_flags *event; page_addr = gHvContext.synICMessagePage[cpu]; msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; DPRINT_ENTER(VMBUS); /* Check if there are actual msgs to be process */ if (msg->Header.MessageType != HvMessageTypeNone) { DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize); ret |= 0x1; } /* TODO: Check if there are events to be process */ page_addr = gHvContext.synICEventPage[cpu]; event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; /* Since we are a child, we only need to check bit 0 */ if (test_and_clear_bit(0, (unsigned long *) &event->Flags32[0])) { DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]); ret |= 0x2; } DPRINT_EXIT(VMBUS); return ret; }
/* * netvsc_linkstatus_callback - Link up/down notification */ static void netvsc_linkstatus_callback(struct hv_device *device_obj, unsigned int status) { struct vm_device *device_ctx = to_vm_device(device_obj); struct net_device *net = dev_get_drvdata(&device_ctx->device); struct net_device_context *ndev_ctx; DPRINT_ENTER(NETVSC_DRV); if (!net) { DPRINT_ERR(NETVSC_DRV, "got link status but net device " "not initialized yet"); return; } if (status == 1) { netif_carrier_on(net); netif_wake_queue(net); netif_notify_peers(net); ndev_ctx = netdev_priv(net); schedule_work(&ndev_ctx->work); } else { netif_carrier_off(net); netif_stop_queue(net); } DPRINT_EXIT(NETVSC_DRV); }
static int netvsc_open(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver); struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context *)driver_ctx; struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj; struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj; int ret = 0; DPRINT_ENTER(NETVSC_DRV); if (netif_carrier_ok(net)) { memset(&net_device_ctx->stats, 0, sizeof(struct net_device_stats)); /* Open up the device */ ret = net_drv_obj->OnOpen(device_obj); if (ret != 0) { DPRINT_ERR(NETVSC_DRV, "unable to open device (ret %d).", ret); return ret; } netif_start_queue(net); } else { DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down."); } DPRINT_EXIT(NETVSC_DRV); return ret; }
static int netvsc_open(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj; int ret = 0; DPRINT_ENTER(NETVSC_DRV); if (netif_carrier_ok(net)) { /* Open up the device */ ret = RndisFilterOnOpen(device_obj); if (ret != 0) { DPRINT_ERR(NETVSC_DRV, "unable to open device (ret %d).", ret); return ret; } netif_start_queue(net); } else { DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down."); } DPRINT_EXIT(NETVSC_DRV); return ret; }
static void netvsc_xmit_completion(void *context) { struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; struct sk_buff *skb = (struct sk_buff *) (unsigned long)packet->Completion.Send.SendCompletionTid; struct net_device *net; DPRINT_ENTER(NETVSC_DRV); kfree(packet); if (skb) { net = skb->dev; dev_kfree_skb_any(skb); if (netif_queue_stopped(net)) { DPRINT_INFO(NETVSC_DRV, "net device (%p) waking up...", net); netif_wake_queue(net); } } DPRINT_EXIT(NETVSC_DRV); }
int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo, struct scatterlist *sglist, u32 sgcount) { int i = 0; u32 byteAvailToWrite; u32 byteAvailToRead; u32 totalBytesToWrite = 0; struct scatterlist *sg; volatile u32 nextWriteLocation; u64 prevIndices = 0; unsigned long flags; DPRINT_ENTER(VMBUS); for_each_sg(sglist, sg, sgcount, i) { totalBytesToWrite += sg->length; } totalBytesToWrite += sizeof(u64); spin_lock_irqsave(&OutRingInfo->ring_lock, flags); GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite); DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); /* DumpRingInfo(OutRingInfo, "BEFORE "); */ /* If there is only room for the packet, assume it is full. */ /* Otherwise, the next time around, we think the ring buffer */ /* is empty since the read index == write index */ if (byteAvailToWrite <= totalBytesToWrite) { DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer " "(needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite); spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); DPRINT_EXIT(VMBUS); return -1; } /* Write to the ring buffer */ nextWriteLocation = GetNextWriteLocation(OutRingInfo); for_each_sg(sglist, sg, sgcount, i) { nextWriteLocation = CopyToRingBuffer(OutRingInfo, nextWriteLocation, sg_virt(sg), sg->length); }
static void VmbusOnCleanup(struct hv_driver *drv) { /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */ DPRINT_ENTER(VMBUS); HvCleanup(); DPRINT_EXIT(VMBUS); }
static void netvsc_init(void) { DPRINT_ENTER(NETVSC_DRV); printf("Netvsc initializing...."); netvsc_drv_init(NetVscInitialize); DPRINT_EXIT(NETVSC_DRV); }
static int VmbusOnDeviceRemove(struct hv_device *dev) { int ret = 0; DPRINT_ENTER(VMBUS); VmbusChannelReleaseUnattachedChannels(); VmbusDisconnect(); on_each_cpu(HvSynicCleanup, NULL, 1); DPRINT_EXIT(VMBUS); return ret; }
int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo, struct scatterlist *sglist, u32 sgcount) { int i=0; u32 byteAvailToWrite; u32 byteAvailToRead; u32 totalBytesToWrite=0; struct scatterlist *sg; volatile u32 nextWriteLocation; u64 prevIndices=0; unsigned long flags; DPRINT_ENTER(VMBUS); for_each_sg(sglist, sg, sgcount, i) { totalBytesToWrite += sg->length; } totalBytesToWrite += sizeof(u64); spin_lock_irqsave(&OutRingInfo->ring_lock, flags); GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite); DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); if (byteAvailToWrite <= totalBytesToWrite) { DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite); spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); DPRINT_EXIT(VMBUS); return -1; } nextWriteLocation = GetNextWriteLocation(OutRingInfo); for_each_sg(sglist, sg, sgcount, i) { nextWriteLocation = CopyToRingBuffer(OutRingInfo, nextWriteLocation, sg_virt(sg), sg->length); }
static int __init netvsc_init(void) { int ret; DPRINT_ENTER(NETVSC_DRV); DPRINT_INFO(NETVSC_DRV, "Netvsc initializing...."); ret = netvsc_drv_init(NetVscInitialize); DPRINT_EXIT(NETVSC_DRV); return ret; }
/* * Heartbeat functionality. * Every two seconds, Hyper-V send us a heartbeat request message. * we respond to this message, and Hyper-V knows we are alive. */ static void heartbeat_onchannelcallback(void *context) { struct vmbus_channel *channel = context; u8 *buf; u32 buflen, recvlen; u64 requestid; struct icmsg_hdr *icmsghdrp; struct heartbeat_msg_data *heartbeat_msg; DPRINT_ENTER(VMBUS); buflen = PAGE_SIZE; buf = kmalloc(buflen, GFP_ATOMIC); VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid); if (recvlen > 0) { DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld", recvlen, requestid); icmsghdrp = (struct icmsg_hdr *)&buf[ sizeof(struct vmbuspipe_hdr)]; icmsghdrp = (struct icmsg_hdr *)&buf[ sizeof(struct vmbuspipe_hdr)]; if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { prep_negotiate_resp(icmsghdrp, NULL, buf); } else { heartbeat_msg = (struct heartbeat_msg_data *)&buf[ sizeof(struct vmbuspipe_hdr) + sizeof(struct icmsg_hdr)]; DPRINT_DBG(VMBUS, "heartbeat seq = %lld", heartbeat_msg->seq_num); heartbeat_msg->seq_num += 1; } icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; VmbusChannelSendPacket(channel, buf, recvlen, requestid, VmbusPacketTypeDataInBand, 0); } kfree(buf); DPRINT_EXIT(VMBUS); }
static int __init netvsc_init(void) { int ret; DPRINT_ENTER(NETVSC_DRV); DPRINT_INFO(NETVSC_DRV, "Netvsc initializing...."); if (!dmi_check_system(hv_netvsc_dmi_table)) return -ENODEV; ret = netvsc_drv_init(NetVscInitialize); DPRINT_EXIT(NETVSC_DRV); return ret; }
/** * VmbusInitialize - Main entry point */ int VmbusInitialize(struct hv_driver *drv) { struct vmbus_driver *driver = (struct vmbus_driver *)drv; int ret; DPRINT_ENTER(VMBUS); DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime); DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc); DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER); DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT); DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%zd, " "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd", sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)); drv->name = gDriverName; memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid)); /* Setup dispatch table */ driver->Base.OnDeviceAdd = VmbusOnDeviceAdd; driver->Base.OnDeviceRemove = VmbusOnDeviceRemove; driver->Base.OnCleanup = VmbusOnCleanup; driver->OnIsr = VmbusOnISR; driver->OnMsgDpc = VmbusOnMsgDPC; driver->OnEventDpc = VmbusOnEventDPC; driver->GetChannelOffers = VmbusGetChannelOffers; driver->GetChannelInterface = VmbusGetChannelInterface; driver->GetChannelInfo = VmbusGetChannelInfo; /* Hypervisor initialization...setup hypercall page..etc */ ret = HvInit(); if (ret != 0) DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret); gDriver = drv; DPRINT_EXIT(VMBUS); return ret; }
static int netvsc_remove(struct device *device) { struct driver_context *driver_ctx = driver_to_driver_context(device->driver); struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context *)driver_ctx; struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj; struct vm_device *device_ctx = device_to_vm_device(device); struct net_device *net = dev_get_drvdata(&device_ctx->device); struct hv_device *device_obj = &device_ctx->device_obj; int ret; DPRINT_ENTER(NETVSC_DRV); if (net == NULL) { DPRINT_INFO(NETVSC, "no net device to remove"); DPRINT_EXIT(NETVSC_DRV); return 0; } if (!net_drv_obj->Base.OnDeviceRemove) { DPRINT_EXIT(NETVSC_DRV); return -1; } /* Stop outbound asap */ netif_stop_queue(net); /* netif_carrier_off(net); */ unregister_netdev(net); /* * Call to the vsc driver to let it know that the device is being * removed */ ret = net_drv_obj->Base.OnDeviceRemove(device_obj); if (ret != 0) { /* TODO: */ DPRINT_ERR(NETVSC, "unable to remove vsc device (ret %d)", ret); } free_netdev(net); DPRINT_EXIT(NETVSC_DRV); return ret; }
static int netvsc_close(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj; int ret; DPRINT_ENTER(NETVSC_DRV); netif_stop_queue(net); ret = RndisFilterOnClose(device_obj); if (ret != 0) DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret); DPRINT_EXIT(NETVSC_DRV); return ret; }
/* * Time Sync Channel message handler. */ static void timesync_onchannelcallback(void *context) { struct vmbus_channel *channel = context; u8 *buf; u32 buflen, recvlen; u64 requestid; struct icmsg_hdr *icmsghdrp; struct ictimesync_data *timedatap; DPRINT_ENTER(VMBUS); buflen = PAGE_SIZE; buf = kmalloc(buflen, GFP_ATOMIC); VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid); if (recvlen > 0) { DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld", recvlen, requestid); icmsghdrp = (struct icmsg_hdr *)&buf[ sizeof(struct vmbuspipe_hdr)]; if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { prep_negotiate_resp(icmsghdrp, NULL, buf); } else { timedatap = (struct ictimesync_data *)&buf[ sizeof(struct vmbuspipe_hdr) + sizeof(struct icmsg_hdr)]; adj_guesttime(timedatap->parenttime, timedatap->flags); } icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; VmbusChannelSendPacket(channel, buf, recvlen, requestid, VmbusPacketTypeDataInBand, 0); } kfree(buf); DPRINT_EXIT(VMBUS); }
int BlkVscInitialize(struct hv_driver *Driver) { struct storvsc_driver_object *storDriver; int ret = 0; DPRINT_ENTER(BLKVSC); storDriver = (struct storvsc_driver_object *)Driver; /* Make sure we are at least 2 pages since 1 page is used for control */ ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); Driver->name = gBlkDriverName; memcpy(&Driver->deviceType, &gBlkVscDeviceType, sizeof(struct hv_guid)); storDriver->RequestExtSize = sizeof(struct storvsc_request_extension); /* * Divide the ring buffer data size (which is 1 page less than the ring * buffer size since that page is reserved for the ring buffer indices) * by the max request size (which is * VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER + struct vstor_packet + u64) */ storDriver->MaxOutstandingRequestsPerChannel = ((storDriver->RingBufferSize - PAGE_SIZE) / ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET + sizeof(struct vstor_packet) + sizeof(u64), sizeof(u64))); DPRINT_INFO(BLKVSC, "max io outstd %u", storDriver->MaxOutstandingRequestsPerChannel); /* Setup the dispatch table */ storDriver->Base.OnDeviceAdd = BlkVscOnDeviceAdd; storDriver->Base.OnDeviceRemove = StorVscOnDeviceRemove; storDriver->Base.OnCleanup = StorVscOnCleanup; storDriver->OnIORequest = StorVscOnIORequest; DPRINT_EXIT(BLKVSC); return ret; }
/** * VmbusChannelSetEvent - Trigger an event notification on the specified channel. */ static void VmbusChannelSetEvent(struct vmbus_channel *Channel) { struct hv_monitor_page *monitorPage; DPRINT_ENTER(VMBUS); if (Channel->OfferMsg.MonitorAllocated) { /* Each u32 represents 32 channels */ set_bit(Channel->OfferMsg.ChildRelId & 31, (unsigned long *) gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5)); monitorPage = gVmbusConnection.MonitorPages; monitorPage++; /* Get the child to parent monitor page */ set_bit(Channel->MonitorBit, (unsigned long *)&monitorPage->TriggerGroup [Channel->MonitorGroup].Pending); } else {
void netvsc_xmit_completion(void *context) { NETVSC_PACKET *packet = (NETVSC_PACKET *)context; struct mbuf *m; unsigned char *buf; void *sc; DPRINT_ENTER(NETVSC_DRV); m = (struct mbuf *)(ULONG_PTR)packet->Completion.Send.SendCompletionTid; buf = ((unsigned char *)packet) - 16; sc = (void *)(*(vm_offset_t *)buf); free(buf, M_DEVBUF); if (m) { m_freem(m); } DPRINT_EXIT(NETVSC_DRV); }
static void netvsc_drv_exit(void) { struct netvsc_driver *netvsc_drv_obj = &g_netvsc_drv.drv_obj; struct driver_context *drv_ctx = &g_netvsc_drv.drv_ctx; struct device *current_dev; int ret; DPRINT_ENTER(NETVSC_DRV); while (1) { current_dev = NULL; /* Get the device */ ret = driver_for_each_device(&drv_ctx->driver, NULL, ¤t_dev, netvsc_drv_exit_cb); if (ret) DPRINT_WARN(NETVSC_DRV, "driver_for_each_device returned %d", ret); if (current_dev == NULL) break; /* Initiate removal from the top-down */ DPRINT_INFO(NETVSC_DRV, "unregistering device (%p)...", current_dev); device_unregister(current_dev); } if (netvsc_drv_obj->Base.OnCleanup) netvsc_drv_obj->Base.OnCleanup(&netvsc_drv_obj->Base); vmbus_child_driver_unregister(drv_ctx); DPRINT_EXIT(NETVSC_DRV); return; }
static int netvsc_close(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver); struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context *)driver_ctx; struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj; struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj; int ret; DPRINT_ENTER(NETVSC_DRV); netif_stop_queue(net); ret = net_drv_obj->OnClose(device_obj); if (ret != 0) DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret); DPRINT_EXIT(NETVSC_DRV); return ret; }
static void netvsc_xmit_completion(void *context) { struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; struct sk_buff *skb = (struct sk_buff *) (unsigned long)packet->Completion.Send.SendCompletionTid; DPRINT_ENTER(NETVSC_DRV); kfree(packet); if (skb) { struct net_device *net = skb->dev; struct net_device_context *net_device_ctx = netdev_priv(net); unsigned int num_pages = skb_shinfo(skb)->nr_frags + 2; dev_kfree_skb_any(skb); if ((net_device_ctx->avail += num_pages) >= PACKET_PAGES_HIWATER) netif_wake_queue(net); } DPRINT_EXIT(NETVSC_DRV); }
/** * NetVscInitialize - Main entry point */ int NetVscInitialize(struct hv_driver *drv) { struct netvsc_driver *driver = (struct netvsc_driver *)drv; DPRINT_ENTER(NETVSC); DPRINT_DBG(NETVSC, "sizeof(struct hv_netvsc_packet)=%zd, " "sizeof(struct nvsp_message)=%zd, " "sizeof(struct vmtransfer_page_packet_header)=%zd", sizeof(struct hv_netvsc_packet), sizeof(struct nvsp_message), sizeof(struct vmtransfer_page_packet_header)); /* Make sure we are at least 2 pages since 1 page is used for control */ ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); drv->name = gDriverName; memcpy(&drv->deviceType, &gNetVscDeviceType, sizeof(struct hv_guid)); /* Make sure it is set by the caller */ ASSERT(driver->OnReceiveCallback); ASSERT(driver->OnLinkStatusChanged); /* Setup the dispatch table */ driver->Base.OnDeviceAdd = NetVscOnDeviceAdd; driver->Base.OnDeviceRemove = NetVscOnDeviceRemove; driver->Base.OnCleanup = NetVscOnCleanup; driver->OnSend = NetVscOnSend; RndisFilterInit(driver); DPRINT_EXIT(NETVSC); return 0; }
int NetVscInitialize(struct hv_driver *drv) { struct netvsc_driver *driver = (struct netvsc_driver *)drv; DPRINT_ENTER(NETVSC); DPRINT_DBG(NETVSC, "sizeof(struct hv_netvsc_packet)=%zd, " "sizeof(struct nvsp_message)=%zd, " "sizeof(struct vmtransfer_page_packet_header)=%zd", sizeof(struct hv_netvsc_packet), sizeof(struct nvsp_message), sizeof(struct vmtransfer_page_packet_header)); ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); drv->name = gDriverName; memcpy(&drv->deviceType, &gNetVscDeviceType, sizeof(struct hv_guid)); ASSERT(driver->OnReceiveCallback); ASSERT(driver->OnLinkStatusChanged); driver->Base.OnDeviceAdd = NetVscOnDeviceAdd; driver->Base.OnDeviceRemove = NetVscOnDeviceRemove; driver->Base.OnCleanup = NetVscOnCleanup; driver->OnSend = NetVscOnSend; RndisFilterInit(driver); DPRINT_EXIT(NETVSC); return 0; }