X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=linux_module%2Fiface-host-dev.c;h=c9c586e5321564e5da9be33c47f300985bca91b6;hb=145dbb97d24518a80348a2aec5494b6d7805081b;hp=b9d754d686cee05a5a9943c3093cfa72ec884c89;hpb=5c40a15de52c320b70c94331e482b25fdcf768c4;p=palacios.git diff --git a/linux_module/iface-host-dev.c b/linux_module/iface-host-dev.c index b9d754d..c9c586e 100644 --- a/linux_module/iface-host-dev.c +++ b/linux_module/iface-host-dev.c @@ -126,14 +126,14 @@ struct palacios_host_dev { #define DEEP_DEBUG 0 #define SHALLOW_DEBUG 0 -#if DEEP_DEBUG -#define DEEP_DEBUG_PRINT(fmt, args...) DEBUG((fmt), ##args) +#if DEEP_DEBUG == 1 +#define DEEP_DEBUG_PRINT(fmt, args...) DEBUG(fmt, ##args) #else #define DEEP_DEBUG_PRINT(fmt, args...) #endif -#if SHALLOW_DEBUG -#define SHALLOW_DEBUG_PRINT(fmt, args...) INFO((fmt), ##args) +#if SHALLOW_DEBUG == 1 +#define SHALLOW_DEBUG_PRINT(fmt, args...) INFO(fmt, ##args) #else #define SHALLOW_DEBUG_PRINT(fmt, args...) #endif @@ -149,6 +149,7 @@ struct palacios_host_device_user { char url[MAX_URL]; // what is the url describing the device v3_guest_dev_t guestdev; // what is the palacios-side device + v3_guest_dev_intr_t guestintr; // what is the palacios-side device interrupt info wait_queue_head_t user_wait_queue; // user space processes waiting on us (should be only one) wait_queue_head_t host_wait_queue; // host threads (should only be one) waiting on user space @@ -434,11 +435,18 @@ static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg } break; - case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: { + case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_RAISE_GUEST: { - DEEP_DEBUG_PRINT("palacios: hostdev: irq guest\n"); + DEEP_DEBUG_PRINT("palacios: hostdev: irq raise guest\n"); - return v3_host_dev_raise_irq(dev, dev->guestdev, op.irq); + return v3_host_dev_raise_irq(dev, dev->guestdev, dev->guestintr, op.irq); + } + break; + case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_LOWER_GUEST: { + + DEEP_DEBUG_PRINT("palacios: hostdev: irq lower guest\n"); + + return v3_host_dev_lower_irq(dev, dev->guestdev, dev->guestintr, op.irq); } break; @@ -465,7 +473,11 @@ static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg schedule(); // avoid livelock for polling user space process SUSPICOUS return 0; // no request available now } - + + // safe to unlock here since if we are in the waiting state + // the palacios side will not modify the request + palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) { palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url); @@ -473,8 +485,6 @@ static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg } - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - DEEP_DEBUG_PRINT("palacios: hostdev: have request\n"); return 1; // have request for you @@ -497,15 +507,15 @@ static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg return 0; // no request available now } + // Safe to unlock here since if we are in the waiting + // state, the request will not be modified by the palacios side + palacios_spinlock_unlock_irqrestore(&(dev->lock),f); if (copy_to_user(argp,dev->req,dev->req->data_len)) { - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url); return -EFAULT; // failed to copy! } - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n"); return 1; // copied request for you @@ -528,37 +538,31 @@ static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg return 0; // no request outstanding, so we do not need a response! } + // Safe to unlock here as the palacios side will not + // modify the request or copy the response until we + // reset dev->waiting + palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) { - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url); return -EFAULT; // failed to copy! } if (user_datalenlock),f); ERROR("palacios: user has response that is too small on host device \"%s\"\n",dev->url); return -EFAULT; } if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) { // not enough room. - // we drop the lock, turn on interrupts, resize, and then retry - DEEP_DEBUG_PRINT("palacios: response not big enough, dropping lock to resize on device \"%s\"\n",dev->url); + DEEP_DEBUG_PRINT("palacios: response not big enough, resizing on device \"%s\"\n",dev->url); - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); if (palacios_resize_reqresp(&(dev->resp),user_datalen-sizeof(struct palacios_host_dev_host_request_response),0)) { ERROR("palacios: unable to resize to accept response of size %llu from user for host device \"%s\"\n",user_datalen,dev->url); return -EFAULT; - } else { - // reacquire the lock - // There shouldn't be a race here, since there should - // be exactly one user space thread giving us a response for this device - // and it is blocked waiting for us to finish - palacios_spinlock_lock_irqsave(&(dev->lock),f); - DEEP_DEBUG_PRINT("palacios: reacuired lock on device \"%s\"\n",dev->url); - } + } } //We only copy data_len bytes from user, but we will @@ -566,7 +570,6 @@ static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg old_len = dev->resp->len; if (copy_from_user(dev->resp, argp, user_datalen)) { dev->resp->len=old_len; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url); return -EFAULT; // failed to copy! } @@ -576,8 +579,6 @@ static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg // now have valid response! dev->waiting=0; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - // wake the palacios side up so that it sees it cycle_response_request(dev); @@ -728,6 +729,7 @@ static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev) static v3_host_dev_t palacios_host_dev_open_deferred(char *url, v3_bus_class_t bus, v3_guest_dev_t gdev, + v3_guest_dev_intr_t gintr, void *host_priv_data) { struct v3_guest *guest= (struct v3_guest*)host_priv_data; @@ -786,6 +788,8 @@ static v3_host_dev_t palacios_host_dev_open_deferred(char *url, dev->guestdev = gdev; + dev->guestintr = gintr; + dev->guest = guest; palacios_spinlock_init(&(dev->lock)); @@ -861,14 +865,11 @@ static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev, DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port); - - palacios_spinlock_lock_irqsave(&(dev->lock),f); - if (palacios_host_dev_rendezvous(dev)) { - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url); return 0; } + palacios_spinlock_lock_irqsave(&(dev->lock),f); if (dev->waiting) { palacios_spinlock_unlock_irqrestore(&(dev->lock),f); @@ -876,26 +877,19 @@ static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev, return 0; } - + // if we're not waiting on user, we have access to + // to the request and response fields + palacios_spinlock_unlock_irqrestore(&(dev->lock),f); // resize request (no data) if (!palacios_bigenough_reqresp(dev->req,0)) { // not enough room. - // we drop the lock, turn on interrupts, resize, and then retry - DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); - - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url); if (palacios_resize_reqresp(&(dev->req),0,0)) { ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); return 0; - } else { - // reacquire the lock - // There shouldn't be a race here since there should not be another - // request from palacios until this one finishes - palacios_spinlock_lock_irqsave(&(dev->lock),f); - DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); - } + } } @@ -908,21 +902,17 @@ static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev, dev->waiting=1; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - // hand over to the user space and wait for it to respond cycle_request_response(dev); // We're back! So now we'll hand the response back to Palacios - - palacios_spinlock_lock_irqsave(&(dev->lock),f); + // no need to lock, we own the response since + // waiting is now 0 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ; memcpy(dest,dev->resp->data, op_len); - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - return op_len; } @@ -937,37 +927,31 @@ static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev, DEEP_DEBUG_PRINT("palacios: hostdev: read mem 0x%p\n",gpa); - palacios_spinlock_lock_irqsave(&(dev->lock),f); if (palacios_host_dev_rendezvous(dev)) { - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + //palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url); return 0; } + palacios_spinlock_lock_irqsave(&(dev->lock),f); if (dev->waiting) { palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: guest issued memory read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected); return 0; } + + // We now are assured to have ownership over request + palacios_spinlock_unlock_irqrestore(&(dev->lock),f); // resize request (no data) if (!palacios_bigenough_reqresp(dev->req,0)) { // not enough room. - // we drop the lock, turn on interrupts, resize, and then retry - DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); - - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url); if (palacios_resize_reqresp(&(dev->req),0,0)) { ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); return 0; - } else { - // reacquire the lock - // There shouldn't be a race here since there should not be another - // request from palacios until this one finishes - palacios_spinlock_lock_irqsave(&(dev->lock),f); - DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); } } @@ -980,21 +964,15 @@ static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev, dev->waiting=1; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - // hand over to the user space and wait for it to respond cycle_request_response(dev); // We're back! So now we'll hand the response back to Palacios - palacios_spinlock_lock_irqsave(&(dev->lock),f); - op_len = dev->resp->op_len < len ? dev->resp->op_len : len ; memcpy(dest,dev->resp->data, op_len); - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - return op_len; } @@ -1007,15 +985,15 @@ static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev, unsigned long f; uint64_t op_len; - DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p\n",(void*)offset); + DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p (len=%lld)\n",(void*)offset, len); - palacios_spinlock_lock_irqsave(&(dev->lock),f); if (palacios_host_dev_rendezvous(dev)) { - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + //palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url); return 0; } + palacios_spinlock_lock_irqsave(&(dev->lock),f); if (dev->waiting) { palacios_spinlock_unlock_irqrestore(&(dev->lock),f); @@ -1023,24 +1001,18 @@ static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev, return 0; } + // Now have exclusive access to request + palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + // resize request (no data) if (!palacios_bigenough_reqresp(dev->req,0)) { // not enough room. - // we drop the lock, turn on interrupts, resize, and then retry - DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); - - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url); if (palacios_resize_reqresp(&(dev->req),0,0)) { ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); return 0; - } else { - // reacquire the lock - // There shouldn't be a race here since there should not be another - // request from palacios until this one finishes - palacios_spinlock_lock_irqsave(&(dev->lock),f); - DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); - } + } } dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF; @@ -1052,21 +1024,15 @@ static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev, dev->waiting=1; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - // hand over to the user space and wait for it to respond cycle_request_response(dev); // We're back! So now we'll hand the response back to Palacios - palacios_spinlock_lock_irqsave(&(dev->lock),f); - op_len = dev->resp->op_len < len ? dev->resp->op_len : len ; memcpy(dest,dev->resp->data, op_len); - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - return op_len; } @@ -1082,13 +1048,13 @@ static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev, DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port); - palacios_spinlock_lock_irqsave(&(dev->lock),f); if (palacios_host_dev_rendezvous(dev)) { - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + //palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url); return 0; } + palacios_spinlock_lock_irqsave(&(dev->lock),f); if (dev->waiting) { palacios_spinlock_unlock_irqrestore(&(dev->lock),f); @@ -1096,24 +1062,18 @@ static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev, return 0; } + // have exclusive access to request + palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + // resize request if (!palacios_bigenough_reqresp(dev->req,len)) { // not enough room. - // we drop the lock, turn on interrupts, resize, and then retry - DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); - - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url); if (palacios_resize_reqresp(&(dev->req),len,0)) { ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); return 0; - } else { - // reacquire the lock - // There shouldn't be a race here since there should not be another - // request from palacios until this one finishes - palacios_spinlock_lock_irqsave(&(dev->lock),f); - DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); - } + } } dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO; @@ -1127,19 +1087,13 @@ static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev, dev->waiting=1; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - // hand over to the user space and wait for it to respond cycle_request_response(dev); // We're back! So now we'll hand the response back to Palacios - palacios_spinlock_lock_irqsave(&(dev->lock),f); - op_len = dev->resp->op_len < len ? dev->resp->op_len : len ; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - return op_len; } @@ -1155,38 +1109,33 @@ static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev, DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa); - palacios_spinlock_lock_irqsave(&(dev->lock),f); if (palacios_host_dev_rendezvous(dev)) { - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + //palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url); return 0; } + palacios_spinlock_lock_irqsave(&(dev->lock),f); + if (dev->waiting) { palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: guest issued memory write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected); return 0; } + // Now have exclusive access to request + palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + // resize request if (!palacios_bigenough_reqresp(dev->req,len)) { // not enough room. - // we drop the lock, turn on interrupts, resize, and then retry - DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); - - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url); if (palacios_resize_reqresp(&(dev->req),len,0)) { ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); return 0; - } else { - // reacquire the lock - // There shouldn't be a race here since there should not be another - // request from palacios until this one finishes - palacios_spinlock_lock_irqsave(&(dev->lock),f); - DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); - } + } } dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM; @@ -1200,19 +1149,13 @@ static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev, dev->waiting=1; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - // hand over to the user space and wait for it to respond cycle_request_response(dev); // We're back! So now we'll hand the response back to Palacios - palacios_spinlock_lock_irqsave(&(dev->lock),f); - op_len= dev->resp->op_len < len ? dev->resp->op_len : len ; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - return op_len; } @@ -1230,13 +1173,13 @@ static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev, DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset); - palacios_spinlock_lock_irqsave(&(dev->lock),f); if (palacios_host_dev_rendezvous(dev)) { - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + //palacios_spinlock_unlock_irqrestore(&(dev->lock),f); ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url); return 0; } + palacios_spinlock_lock_irqsave(&(dev->lock),f); if (dev->waiting) { palacios_spinlock_unlock_irqrestore(&(dev->lock),f); @@ -1244,24 +1187,18 @@ static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev, return 0; } + // Have exclusive access to request + palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + // resize request if (!palacios_bigenough_reqresp(dev->req,len)) { // not enough room. - // we drop the lock, turn on interrupts, resize, and then retry - DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); - - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url); if (palacios_resize_reqresp(&(dev->req),len,0)) { ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); return 0; - } else { - // reacquire the lock - // There shouldn't be a race here since there should not be another - // request from palacios until this one finishes - palacios_spinlock_lock_irqsave(&(dev->lock),f); - DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); - } + } } dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF; @@ -1274,20 +1211,14 @@ static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev, memcpy(dev->req->data,src,len); dev->waiting=1; - - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); // hand over to the user space and wait for it to respond cycle_request_response(dev); // We're back! So now we'll hand the response back to Palacios - palacios_spinlock_lock_irqsave(&(dev->lock),f); - op_len = dev->resp->op_len < len ? dev->resp->op_len : len ; - palacios_spinlock_unlock_irqrestore(&(dev->lock),f); - return op_len; } @@ -1323,6 +1254,11 @@ static int host_dev_init( void ) { } +static int host_dev_deinit(void) { + // nothing to do + return 0; +} + static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) { struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev)); @@ -1347,6 +1283,7 @@ static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) { static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) { struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data; + remove_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT); palacios_spinlock_deinit(&(host_dev->lock)); palacios_free(host_dev); return 0; @@ -1358,7 +1295,7 @@ static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) { static struct linux_ext host_dev_ext = { .name = "HOST_DEVICE_INTERFACE", .init = host_dev_init, - .deinit = NULL, + .deinit = host_dev_deinit, .guest_init = host_dev_guest_init, .guest_deinit = host_dev_guest_deinit };