Skip to content
Browse files

gdev: made QUERY_CHIPSET and QUERY_DEVICE_MEM_SIZE and QUERY_DMA_MEM_…

…SIZE be common queries but not nvidia specific ones

cuda: fixed query functions accordingly
gdev: added gdev_init.{c,h}, and moved gdev initialization functions to this file
gdev: added initial implementation of the Gdev scheduler (just a kernel thread)
gdev: added /proc filesystem functions
gdev: added initial support for virtual devices
  • Loading branch information...
1 parent 71df14d commit 3ddab5efe9c3b7745609a5efdd740df0505e3686 Shinpei Kato committed
View
40 common/gdev_api.c
@@ -25,6 +25,7 @@
#include "gdev_conf.h"
#include "gdev_mm.h"
#include "gdev_proto.h"
+#include "gdev_sched.h"
#define __max(x, y) (x) > (y) ? (x) : (y)
#define __min(x, y) (x) < (y) ? (x) : (y)
@@ -569,7 +570,7 @@ struct gdev_handle *gopen(int minor)
goto fail_vas;
/* create a new GPU context object. */
- ctx = gdev_ctx_new(gdev, vas, h);
+ ctx = gdev_ctx_new(gdev, vas);
if (!ctx)
goto fail_ctx;
@@ -587,21 +588,21 @@ struct gdev_handle *gopen(int minor)
/* insert the created VAS object to the device VAS list. */
gdev_vas_list_add(vas);
- GDEV_PRINT("Opened gdev%d.\n", minor);
+ GDEV_PRINT("Opened gdev%d\n", minor);
return h;
fail_dma:
- GDEV_PRINT("Failed to allocate static DMA buffer object.\n");
+ GDEV_PRINT("Failed to allocate static DMA buffer object\n");
gdev_ctx_free(ctx);
fail_ctx:
- GDEV_PRINT("Failed to create a context object.\n");
+ GDEV_PRINT("Failed to create a context object\n");
gdev_vas_free(vas);
fail_vas:
- GDEV_PRINT("Failed to create a virtual address space object.\n");
+ GDEV_PRINT("Failed to create a virtual address space object\n");
gdev_dev_close(gdev);
fail_open:
- GDEV_PRINT("Failed to open gdev%d.\n", minor);
+ GDEV_PRINT("Failed to open gdev%d\n", minor);
return NULL;
}
@@ -632,7 +633,7 @@ int gclose(struct gdev_handle *h)
gdev_vas_free(h->vas);
gdev_dev_close(h->gdev);
- GDEV_PRINT("Closed gdev%d.\n", h->dev_id);
+ GDEV_PRINT("Closed gdev%d\n", h->dev_id);
FREE(h);
@@ -645,19 +646,26 @@ int gclose(struct gdev_handle *h)
*/
uint64_t gmalloc(struct gdev_handle *h, uint64_t size)
{
+ struct gdev_device *gdev = h->gdev;
gdev_vas_t *vas = h->vas;
gdev_mem_t *mem;
- if (!(mem = gdev_mem_alloc(vas, size, GDEV_MEM_DEVICE))) {
+ gdev->mem_used += size;
+
+ if (gdev->mem_used > gdev->mem_size) {
/* a second chance with shared memory (only for device memory). */
if (!(mem = gdev_shmem_request(vas, NULL, size)))
goto fail;
}
+ else if (!(mem = gdev_mem_alloc(vas, size, GDEV_MEM_DEVICE)))
+ goto fail;
+
gdev_mem_list_add(mem, GDEV_MEM_DEVICE);
return GDEV_MEM_ADDR(mem);
fail:
+ gdev->mem_used -= size;
return 0;
}
@@ -667,6 +675,7 @@ uint64_t gmalloc(struct gdev_handle *h, uint64_t size)
*/
uint64_t gfree(struct gdev_handle *h, uint64_t addr)
{
+ struct gdev_device *gdev = h->gdev;
gdev_vas_t *vas = h->vas;
gdev_mem_t *mem;
uint64_t size;
@@ -677,6 +686,8 @@ uint64_t gfree(struct gdev_handle *h, uint64_t addr)
gdev_mem_list_del(mem);
gdev_mem_free(mem);
+ gdev->mem_used -= size;
+
return size;
fail:
@@ -689,16 +700,22 @@ uint64_t gfree(struct gdev_handle *h, uint64_t addr)
*/
void *gmalloc_dma(struct gdev_handle *h, uint64_t size)
{
+ struct gdev_device *gdev = h->gdev;
gdev_vas_t *vas = h->vas;
gdev_mem_t *mem;
- if (!(mem = gdev_mem_alloc(vas, size, GDEV_MEM_DMA)))
+ gdev->dma_mem_used += size;
+
+ if (gdev->dma_mem_used > gdev->dma_mem_size)
+ goto fail;
+ else if (!(mem = gdev_mem_alloc(vas, size, GDEV_MEM_DMA)))
goto fail;
gdev_mem_list_add(mem, GDEV_MEM_DMA);
return GDEV_MEM_BUF(mem);
fail:
+ gdev->dma_mem_used -= size;
return 0;
}
@@ -708,6 +725,7 @@ void *gmalloc_dma(struct gdev_handle *h, uint64_t size)
*/
uint64_t gfree_dma(struct gdev_handle *h, void *buf)
{
+ struct gdev_device *gdev = h->gdev;
gdev_vas_t *vas = h->vas;
gdev_mem_t *mem;
uint64_t size;
@@ -718,6 +736,8 @@ uint64_t gfree_dma(struct gdev_handle *h, void *buf)
gdev_mem_list_del(mem);
gdev_mem_free(mem);
+ gdev->dma_mem_used -= size;
+
return size;
fail:
@@ -847,6 +867,8 @@ int glaunch(struct gdev_handle *h, struct gdev_kernel *kernel, uint32_t *id)
gdev_vas_t *vas = h->vas;
gdev_ctx_t *ctx = h->ctx;
+ //gdev_schedule_launch(ctx);
+
gdev_shmem_lock_all(vas);
gdev_shmem_reload_all(ctx, vas); /* this reloads data only if necessary */
*id = gdev_launch(ctx, kernel);
View
7 common/gdev_api.h
@@ -73,4 +73,11 @@ int gtune(Ghandle h, uint32_t type, uint32_t value);
#define GDEV_TUNE_MEMCPY_PIPELINE_COUNT 1
#define GDEV_TUNE_MEMCPY_CHUNK_SIZE 2
+/**
+ * common queries:
+ */
+#define GDEV_QUERY_DEVICE_MEM_SIZE 1
+#define GDEV_QUERY_DMA_MEM_SIZE 2
+#define GDEV_QUERY_CHIPSET 3
+
#endif
View
4 common/gdev_conf.h
@@ -29,7 +29,9 @@
// #include "gdev_amd.h"
// #include "gdev_intel.h"
-#define GDEV_DEVICE_MAX_COUNT 32
+#define GDEV_VDEVICE_COUNT 4 /* # of virtual devices */
+
+#define GDEV_CONTEXT_MAX_COUNT 128 /* # of GPU contexts */
#define GDEV_PIPELINE_MAX_COUNT 4
#define GDEV_PIPELINE_MIN_COUNT 1
View
107 common/gdev_init.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2011 Shinpei Kato
+ *
+ * University of California, Santa Cruz
+ * Systems Research Lab.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "gdev_init.h"
+
+/* initialize the physical device information. */
+int gdev_init_device(struct gdev_device *gdev, int minor, void *priv)
+{
+ gdev->id = minor;
+ gdev->users = 0;
+ gdev->mem_size = 0;
+ gdev->mem_used = 0;
+ gdev->dma_mem_size = 0;
+ gdev->dma_mem_used = 0;
+ gdev->proc_util = 100; /* 100% */
+ gdev->mem_util = 100; /* 100% */
+ gdev->swap = NULL;
+ gdev->sched_thread = NULL;
+ gdev->parent = NULL;
+ gdev->priv = priv; /* this must be set before calls to gdev_query(). */
+ gdev_list_init(&gdev->vas_list, NULL); /* VAS list. */
+ LOCK_INIT(&gdev->vas_lock);
+ MUTEX_INIT(&gdev->shmem_mutex);
+
+ /* architecture-dependent chipset.
+ this call must be prior to the following. */
+ gdev_query(gdev, GDEV_QUERY_CHIPSET, (uint64_t*) &gdev->chipset);
+
+ /* device memory size available for users. */
+ gdev_query(gdev, GDEV_QUERY_DEVICE_MEM_SIZE, &gdev->mem_size);
+ /* FIXME: substract the amount of memory used not for users' data but
+ this shouldn't be hardcoded. */
+ gdev->mem_size -= 0xc010000;
+
+ /* host DMA memory size available for users. */
+ gdev_query(gdev, GDEV_QUERY_DMA_MEM_SIZE, &gdev->dma_mem_size);
+
+ /* set up the compute engine. */
+ gdev_compute_setup(gdev);
+
+ GDEV_PRINT("Device %d: memory size (device 0x%llx, host 0x%llx)\n",
+ gdev->id, gdev->mem_size, gdev->dma_mem_size);
+
+ return 0;
+}
+
+/* finalize the physical device. */
+void gdev_exit_device(struct gdev_device *gdev)
+{
+}
+
+/* initialize the virtual device information. */
+int gdev_init_vdevice
+(struct gdev_device *gdev, int id, uint32_t proc_util, uint32_t mem_util,
+ struct gdev_device *phys)
+{
+ gdev->id = id;
+ gdev->users = 0;
+ gdev->proc_util = proc_util;
+ gdev->mem_util = mem_util;
+ gdev->swap = NULL;
+ gdev->sched_thread = NULL;
+ gdev->parent = phys;
+ gdev->priv = phys->priv;
+ gdev->compute = phys->compute;
+ gdev->mem_size = phys->mem_size * mem_util / 100;
+ gdev->dma_mem_size = phys->dma_mem_size * mem_util / 100;
+ gdev->chipset = phys->chipset;
+ gdev_list_init(&gdev->vas_list, NULL); /* VAS list. */
+ LOCK_INIT(&gdev->vas_lock);
+ MUTEX_INIT(&gdev->shmem_mutex);
+
+ GDEV_PRINT("Virtual device %d: memory size (device 0x%llx, host 0x%llx)\n",
+ gdev->id, gdev->mem_size, gdev->dma_mem_size);
+
+ return 0;
+}
+
+/* finalize the virtual device. */
+void gdev_exit_vdevice(struct gdev_device *gdev)
+{
+}
View
40 common/gdev_init.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 Shinpei Kato
+ *
+ * University of California, Santa Cruz
+ * Systems Research Lab.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __GDEV_INIT_H__
+#define __GDEV_INIT_H__
+
+#include "gdev_proto.h"
+
+int gdev_init_device(struct gdev_device*, int, void*);
+void gdev_exit_device(struct gdev_device*);
+int gdev_init_vdevice(struct gdev_device*, int, uint32_t, uint32_t, struct gdev_device *);
+void gdev_exit_vdevice(struct gdev_device*);
+
+
+#endif
View
133 common/gdev_nvidia.c
@@ -1,7 +1,7 @@
/*
* Copyright 2011 Shinpei Kato
*
- * University of California at Santa Cruz
+ * University of California, Santa Cruz
* Systems Research Lab.
*
* All Rights Reserved.
@@ -60,37 +60,9 @@ static uint32_t (*gdev_memcpy_func[2])
gdev_memcpy_async
};
-/* initialize the common Gdev members. */
-int gdev_init_common(struct gdev_device *gdev, int minor, void *obj)
-{
- /* setup common members. */
- gdev->id = minor;
- gdev->users = 0;
- gdev->priv = obj;
- gdev_query(gdev, GDEV_NVIDIA_QUERY_DEVICE_MEM_SIZE, &gdev->mem_size);
- gdev_query(gdev, GDEV_NVIDIA_QUERY_CHIPSET, (uint64_t*) &gdev->chipset);
- gdev_list_init(&gdev->vas_list, NULL); /* VAS list. */
- LOCK_INIT(&gdev->vas_lock);
- MUTEX_INIT(&gdev->shmem_mutex);
- if (GDEV_SWAP_MEM_SIZE > 0) {
- gdev->swap = gdev_raw_swap_alloc(gdev, GDEV_SWAP_MEM_SIZE);
- if (gdev->swap) {
- struct gdev_shmem *shmem;
- shmem = MALLOC(sizeof(*shmem));
- if (shmem)
- shmem->holder = NULL;
- else
- gdev->swap = NULL;
- gdev->swap->shmem = shmem;
- }
- else {
- gdev->swap = NULL;
- }
- }
- else {
- gdev->swap = NULL;
- }
-
+/* set up the architecture-dependent compute engine. */
+int gdev_compute_setup(struct gdev_device *gdev)
+{
switch (gdev->chipset & 0xf0) {
case 0xC0:
nvc0_compute_setup(gdev);
@@ -107,25 +79,9 @@ int gdev_init_common(struct gdev_device *gdev, int minor, void *obj)
return -EINVAL;
}
- gdev_init_private(gdev);
-
return 0;
}
-/* finalize the common Gdev members. */
-void gdev_exit_common(struct gdev_device *gdev)
-{
- gdev_exit_private(gdev);
-
- if (GDEV_SWAP_MEM_SIZE > 0) {
- if (gdev->swap) {
- if (gdev->swap->shmem)
- FREE(gdev->swap->shmem);
- gdev_raw_swap_free(gdev->swap);
- }
- }
-}
-
/* launch the kernel onto the GPU. */
uint32_t gdev_launch(struct gdev_ctx *ctx, struct gdev_kernel *kern)
{
@@ -154,6 +110,9 @@ uint32_t gdev_launch(struct gdev_ctx *ctx, struct gdev_kernel *kern)
compute->fence_reset(ctx, seq);
compute->launch(ctx, kern);
compute->fence_write(ctx, GDEV_SUBCH_COMPUTE, seq);
+
+ /* set an interrupt to be caused when compute done. */
+ compute->notify_intr(ctx);
return seq;
}
@@ -271,13 +230,25 @@ int gdev_query(struct gdev_device *gdev, uint32_t type, uint64_t *result)
{
int ret;
- if ((ret = gdev_raw_query(gdev, type, result)))
- return ret;
-
switch (type) {
- case GDEV_NVIDIA_QUERY_DEVICE_MEM_SIZE:
- *result -= 0xc010000; /* FIXME: this shouldn't be hardcoded. */
+ case GDEV_QUERY_DEVICE_MEM_SIZE:
+ if (gdev->mem_size)
+ *result = gdev->mem_size;
+ else if ((ret = gdev_raw_query(gdev, type, result)))
+ return ret;
break;
+ case GDEV_QUERY_DMA_MEM_SIZE:
+ if (gdev->dma_mem_size)
+ *result = gdev->dma_mem_size;
+ /* FIXME: this is valid only for PCIE. */
+ else if (gdev->chipset > 0x40)
+ *result = 512 * 1024 * 1024;
+ else
+ *result = 64 * 1024 * 1024;
+ break;
+ default:
+ if ((ret = gdev_raw_query(gdev, type, result)))
+ return ret;
}
return 0;
@@ -322,8 +293,7 @@ void gdev_vas_free(struct gdev_vas *vas)
}
/* create a new GPU context object. */
-struct gdev_ctx *gdev_ctx_new
-(struct gdev_device *gdev, struct gdev_vas *vas, void *h)
+struct gdev_ctx *gdev_ctx_new(struct gdev_device *gdev, struct gdev_vas *vas)
{
struct gdev_ctx *ctx;
struct gdev_compute *compute = gdev->compute;
@@ -332,7 +302,6 @@ struct gdev_ctx *gdev_ctx_new
return NULL;
}
- ctx->handle = h;
ctx->vas = vas;
/* initialize the channel. */
@@ -514,6 +483,7 @@ int gdev_shmem_evict(struct gdev_ctx *ctx, struct gdev_mem *mem)
int ret;
if (mem->shmem) {
+ void *h = ctx->vas->handle;
if (mem->shmem->holder && mem->shmem->holder != mem) {
struct gdev_mem *dev_swap = gdev->swap;
holder = mem->shmem->holder;
@@ -521,16 +491,14 @@ int gdev_shmem_evict(struct gdev_ctx *ctx, struct gdev_mem *mem)
size = mem->shmem->size;
if (dev_swap && !dev_swap->shmem->holder) {
uint64_t dst_addr = holder->swap_mem->addr;
- ret = gdev_callback_evict_to_device(ctx->handle, dst_addr,
- src_addr, size);
+ ret = gdev_callback_evict_to_device(h,dst_addr,src_addr,size);
if (ret)
goto fail_evict;
dev_swap->shmem->holder = mem;
}
else {
void *dst_buf = holder->swap_buf;
- ret = gdev_callback_evict_to_host(ctx->handle, dst_buf,
- src_addr, size);
+ ret = gdev_callback_evict_to_host(h,dst_buf,src_addr,size);
if (ret)
goto fail_evict;
}
@@ -571,6 +539,7 @@ int gdev_shmem_reload(struct gdev_ctx *ctx, struct gdev_mem *mem)
int ret;
if (mem->evicted) {
+ void *h = vas->handle;
/* evict the corresponding memory space first. */
gdev_shmem_evict(ctx, mem);
/* reload data regardless whether eviction succeeded or failed. */
@@ -579,15 +548,13 @@ int gdev_shmem_reload(struct gdev_ctx *ctx, struct gdev_mem *mem)
size = mem->size;
if (dev_swap && dev_swap->shmem->holder == mem) {
uint64_t src_addr = mem->swap_mem->addr;
- ret = gdev_callback_reload_from_device(ctx->handle, dst_addr,
- src_addr, size);
+ ret = gdev_callback_reload_from_device(h, dst_addr, src_addr, size);
if (ret)
goto fail_reload;
}
else {
void *src_buf = mem->swap_buf;
- ret = gdev_callback_reload_from_host(ctx->handle, dst_addr,
- src_buf, size);
+ ret = gdev_callback_reload_from_host(h, dst_addr, src_buf, size);
if (ret)
goto fail_reload;
}
@@ -788,6 +755,44 @@ void gdev_shmem_unlock_all(struct gdev_vas *vas)
MUTEX_UNLOCK(&gdev->shmem_mutex);
}
+/* create swap memory object for the device. */
+int gdev_swap_create(struct gdev_device *gdev, uint32_t size)
+{
+ struct gdev_mem *swap;
+ struct gdev_shmem *shmem;
+ int ret = 0;
+
+ swap = gdev_raw_swap_alloc(gdev, size);
+ if (swap) {
+ shmem = MALLOC(sizeof(*shmem));
+ if (shmem)
+ shmem->holder = NULL;
+ else {
+ gdev_raw_swap_free(swap);
+ swap = NULL;
+ ret = -ENOMEM;
+ }
+ swap->shmem = shmem;
+ }
+ else {
+ ret = -ENOMEM;
+ }
+
+ gdev->swap = swap;
+
+ return ret;
+}
+
+/* remove swap memory object from the device. */
+void gdev_swap_destroy(struct gdev_device *gdev)
+{
+ if (gdev->swap) {
+ if (gdev->swap->shmem)
+ FREE(gdev->swap->shmem);
+ gdev_raw_swap_free(gdev->swap);
+ }
+}
+
/* add a new VAS object into the device VAS list. */
void gdev_vas_list_add(struct gdev_vas *vas)
{
View
8 common/gdev_nvidia.h
@@ -97,6 +97,7 @@ struct gdev_shmem {
* mapped on SRAM present in each MP.
*/
struct gdev_vas {
+ int vid; /* vritual address space ID. */
void *handle; /* Gdev API handle. */
void *pvas; /* driver private object. */
struct gdev_device *gdev; /* vas is associated with a specific device. */
@@ -111,7 +112,7 @@ struct gdev_vas {
* GPU context object struct:
*/
struct gdev_ctx {
- void *handle; /* Gdev API handle. */
+ int cid; /* context ID. */
void *pctx; /* driver private object. */
struct gdev_vas *vas; /* chan is associated with a specific vas object. */
struct gdev_fifo {
@@ -139,6 +140,10 @@ struct gdev_ctx {
uint64_t addr;
uint32_t seq;
} fence;
+ struct gdev_intr { /* notifier objects (for compute and dma). */
+ void *bo; /* driver private object. */
+ uint64_t addr;
+ } notify;
uint32_t dummy;
};
@@ -171,6 +176,7 @@ struct gdev_compute {
void (*memcpy)(struct gdev_ctx *, uint64_t, uint64_t, uint32_t);
void (*memcpy_async)(struct gdev_ctx *, uint64_t, uint64_t, uint32_t);
void (*membar)(struct gdev_ctx *);
+ void (*notify_intr)(struct gdev_ctx *);
void (*init)(struct gdev_ctx *);
};
View
3 common/gdev_nvidia_def.h
@@ -42,9 +42,6 @@
* they should be >= 0x100.
*/
#define GDEV_NVIDIA_QUERY_MP_COUNT 0x100
-#define GDEV_NVIDIA_QUERY_DEVICE_MEM_SIZE 0x101
-#define GDEV_NVIDIA_QUERY_DMA_MEM_SIZE 0x102
-#define GDEV_NVIDIA_QUERY_CHIPSET 0x103
/**
* GPGPU kernel object struct:
View
30 common/gdev_proto.h
@@ -1,7 +1,7 @@
/*
* Copyright 2011 Shinpei Kato
*
- * University of California at Santa Cruz
+ * University of California, Santa Cruz
* Systems Research Lab.
*
* All Rights Reserved.
@@ -49,15 +49,19 @@ typedef struct gdev_mem gdev_mem_t;
* Gdev device struct:
*/
struct gdev_device {
- int id;
+ int id; /* physical device minor ID */
int users; /* the number of threads/processes using the device */
uint32_t chipset;
uint64_t mem_size;
uint64_t mem_used;
uint64_t dma_mem_size;
uint64_t dma_mem_used;
+ uint32_t proc_util; /* available processor utilization */
+ uint32_t mem_util; /* available memory utilization */
void *priv; /* private device object */
void *compute; /* private set of compute functions */
+ void *sched_thread; /* scheduler thread */
+ struct gdev_device *parent; /* only for virtual devices */
struct gdev_list vas_list; /* list of VASes allocated to this device */
gdev_lock_t vas_lock;
gdev_mutex_t shmem_mutex;
@@ -67,10 +71,7 @@ struct gdev_device {
/**
* architecture-dependent compute functions.
*/
-int gdev_init_common(struct gdev_device*, int, void*);
-int gdev_init_private(struct gdev_device*);
-void gdev_exit_common(struct gdev_device*);
-void gdev_exit_private(struct gdev_device*);
+int gdev_compute_setup(struct gdev_device*);
uint32_t gdev_launch(gdev_ctx_t*, struct gdev_kernel*);
uint32_t gdev_memcpy(gdev_ctx_t*, uint64_t, uint64_t, uint32_t, int);
uint32_t gdev_read32(gdev_mem_t*, uint64_t);
@@ -87,7 +88,7 @@ struct gdev_device *gdev_dev_open(int);
void gdev_dev_close(struct gdev_device*);
gdev_vas_t *gdev_vas_new(struct gdev_device*, uint64_t, void*);
void gdev_vas_free(gdev_vas_t*);
-gdev_ctx_t *gdev_ctx_new(struct gdev_device*, gdev_vas_t*, void*);
+gdev_ctx_t *gdev_ctx_new(struct gdev_device*, gdev_vas_t*);
void gdev_ctx_free(gdev_ctx_t*);
gdev_mem_t *gdev_mem_alloc(gdev_vas_t*, uint64_t, int);
void gdev_mem_free(gdev_mem_t*);
@@ -101,6 +102,8 @@ void gdev_shmem_lock(gdev_mem_t*);
void gdev_shmem_unlock(gdev_mem_t*);
void gdev_shmem_lock_all(gdev_vas_t*);
void gdev_shmem_unlock_all(gdev_vas_t*);
+int gdev_swap_create(struct gdev_device*, uint32_t);
+void gdev_swap_destroy(struct gdev_device*);
void gdev_vas_list_add(gdev_vas_t*);
void gdev_vas_list_del(gdev_vas_t*);
void gdev_mem_list_add(gdev_mem_t*, int);
@@ -108,7 +111,7 @@ void gdev_mem_list_del(gdev_mem_t*);
gdev_mem_t *gdev_mem_lookup(gdev_vas_t*, uint64_t, int);
/**
- * driver/runtime-dependent functions.
+ * architecture-dependent and runtime-dependent functions.
*/
int gdev_raw_query(struct gdev_device*, uint32_t, uint64_t*);
struct gdev_device *gdev_raw_dev_open(int);
@@ -129,5 +132,16 @@ void gdev_raw_write32(gdev_mem_t*, uint64_t, uint32_t);
int gdev_raw_read(gdev_mem_t*, void*, uint64_t, uint32_t);
int gdev_raw_write(gdev_mem_t*, uint64_t, const void*, uint32_t);
+/**
+ * architecture-independent but runtime-dependent scheduler functions.
+ */
+int gdev_init_scheduler_thread(struct gdev_device*);
+void gdev_exit_scheduler_thread(struct gdev_device*);
+
+/**
+ * architecture-independent and runtime-independent scheduler functions.
+ */
+int gdev_init_scheduler(struct gdev_device*);
+void gdev_exit_scheduler(struct gdev_device*);
#endif
View
73 common/gdev_sched.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Shinpei Kato
+ *
+ * University of California, Santa Cruz
+ * Systems Research Lab.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "gdev_proto.h"
+#include "gdev_sched.h"
+
+struct gdev_sched_entity *sched_entity_ptr[GDEV_CONTEXT_MAX_COUNT];
+
+/**
+ * initialize the scheduler for the device.
+ */
+int gdev_init_scheduler(struct gdev_device *gdev)
+{
+ gdev_init_scheduler_thread(gdev);
+
+ return 0;
+}
+
+/**
+ * finalized the scheduler for the device.
+ */
+void gdev_exit_scheduler(struct gdev_device *gdev)
+{
+ gdev_exit_scheduler_thread(gdev);
+}
+
+/**
+ * schedule kernel-launch calls.
+ */
+void gdev_schedule_launch(struct gdev_sched_entity *se)
+{
+}
+
+/**
+ * schedule memcpy-copy calls.
+ */
+void gdev_schedule_memcpy(struct gdev_sched_entity *se)
+{
+}
+
+/**
+ * schedule next contexts.
+ * invoked upon the completion of preceding contexts.
+ */
+void gdev_schedule_invoked(int subc, uint32_t data)
+{
+}
+
View
47 common/gdev_sched.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 Shinpei Kato
+ *
+ * University of California, Santa Cruz
+ * Systems Research Lab.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __GDEV_SCHED_H__
+#define __GDEV_SCHED_H__
+
+#include "gdev_proto.h"
+
+struct gdev_sched_entity {
+ int rt_prio;
+};
+
+void gdev_schedule_launch(struct gdev_sched_entity *se);
+void gdev_schedule_memcpy(struct gdev_sched_entity *se);
+void gdev_schedule_invoked(int subc, uint32_t data);
+
+/**
+ * export the pointers to the scheduling entity.
+ */
+extern struct gdev_sched_entity *sched_entity_ptr[GDEV_CONTEXT_MAX_COUNT];
+
+#endif
View
16 cuda/driver_api/context.c
@@ -122,19 +122,20 @@ CUresult cuCtxCreate(CUcontext *pctx, unsigned int flags, CUdevice dev)
#ifdef __KERNEL__
/* chunk size of 0x40000 seems best when using OS runtime. */
if (gtune(handle, GDEV_TUNE_MEMCPY_CHUNK_SIZE, 0x40000)) {
- return NULL;
+ res = CUDA_ERROR_UNKNOWN;
+ goto fail_tune_chunk;
}
#endif
/* get the CUDA-specific device information. */
cuda_info = &ctx->cuda_info;
- if (gquery(handle, GDEV_NVIDIA_QUERY_MP_COUNT, &cuda_info->mp_count)) {
+ if (gquery(handle, GDEV_QUERY_CHIPSET, &cuda_info->chipset)) {
res = CUDA_ERROR_UNKNOWN;
- goto fail_query_mp_count;
+ goto fail_query_chipset;
}
- if (gquery(handle, GDEV_NVIDIA_QUERY_CHIPSET, &cuda_info->chipset)) {
+ if (gquery(handle, GDEV_NVIDIA_QUERY_MP_COUNT, &cuda_info->mp_count)) {
res = CUDA_ERROR_UNKNOWN;
- goto fail_query_chipset;
+ goto fail_query_mp_count;
}
/* FIXME: per-thread warp size and active warps */
@@ -170,8 +171,11 @@ CUresult cuCtxCreate(CUcontext *pctx, unsigned int flags, CUdevice dev)
return CUDA_SUCCESS;
-fail_query_chipset:
fail_query_mp_count:
+fail_query_chipset:
+#ifdef __KERNEL__
+fail_tune_chunk:
+#endif
gclose(handle);
fail_open_gdev:
FREE(ctx);
View
2 cuda/driver_api/device.c
@@ -278,7 +278,7 @@ CUresult cuDeviceTotalMem(size_t *bytes, CUdevice dev)
handle = gdev_ctx_current->gdev_handle;
- if (gquery(handle, GDEV_NVIDIA_QUERY_DEVICE_MEM_SIZE, &total_mem)) {
+ if (gquery(handle, GDEV_QUERY_DEVICE_MEM_SIZE, &total_mem)) {
return CUDA_ERROR_UNKNOWN;
}
View
180 driver/gdev/gdev_drv.c
@@ -1,5 +1,9 @@
/*
* Copyright 2011 Shinpei Kato
+ *
+ * University of California, Santa Cruz
+ * Systems Research Lab.
+ *
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -34,13 +38,25 @@
#include "gdev_api.h"
#include "gdev_conf.h"
#include "gdev_drv.h"
+#include "gdev_init.h"
#include "gdev_ioctl.h"
+#include "gdev_proc.h"
#include "gdev_proto.h"
+/**
+ * global variables.
+ */
dev_t dev;
-struct cdev *cdevs;
-struct gdev_device *gdevs;
-int gdev_count;
+struct cdev *cdevs; /* character devices for virtual devices */
+int gdev_count; /* # of physical devices. */
+int gdev_vcount; /* # of virtual devices. */
+struct gdev_device *gdevs; /* physical devices */
+struct gdev_device *gdev_vds; /* virtual devices */
+
+/**
+ * pointers to callback functions.
+ */
+void (*gdev_callback_notify)(int subc, uint32_t data);
static int __get_minor(struct file *filp)
{
@@ -183,54 +199,78 @@ static struct file_operations gdev_fops = {
.mmap = gdev_mmap,
};
+static void __gdev_notify_handler(int subc, uint32_t data)
+{
+#if 0
+ struct gdev_device *gdev;
+ struct gdev_sched_entity *se;
+ int cid = (int)data;
+
+ if (cid < GDEV_CONTEXT_MAX_COUNT) {
+ se = sched_entity_ptr[cid];
+ gdev = se->gdev;
+ wake_up_process(gdev->sched_thread);
+ }
+#endif
+}
+
+/**
+ * called for each minor physical device.
+ */
int gdev_minor_init(struct drm_device *drm)
{
- int ret;
- int i = drm->primary->index;
- struct gdev_device *gdev = &gdevs[i];
- struct cdev *cdev = &cdevs[i];
+ int minor = drm->primary->index;
- if (i >= gdev_count) {
- GDEV_PRINT("Could not find gdev%d.\n", i);
+ if (minor >= gdev_count) {
+ GDEV_PRINT("Could not find device %d\n", minor);
return -EINVAL;
}
- /* register a new character device. */
- GDEV_PRINT("Adding gdev%d.\n", i);
- cdev_init(cdev, &gdev_fops);
- ret = cdev_add(cdev, dev, 1);
- if (ret < 0) {
- GDEV_PRINT("Failed to register gdev%d.\n", i);
- return ret;
- }
+ /* initialize the physical device. */
+ gdev_init_device(&gdevs[minor], minor, drm);
+
+ /* initialize the virtual device.
+ when Gdev first loaded, one-to-one map physical and virtual device. */
+ gdev_init_vdevice(&gdev_vds[minor], minor, 100, 100, &gdevs[minor]);
- /* initialize the Gdev engine. */
- gdev_init_common(gdev, i, drm);
+ /* initialize the scheduler for the virtual device. */
+ gdev_init_scheduler(&gdev_vds[minor]);
+
+ /* create the swap memory object, if configured, for the virtual device. */
+ if (GDEV_SWAP_MEM_SIZE > 0) {
+ gdev_swap_create(&gdev_vds[minor], GDEV_SWAP_MEM_SIZE);
+ }
return 0;
}
+/**
+ * called for each minor physical device.
+ */
int gdev_minor_exit(struct drm_device *drm)
{
- int i = drm->primary->index;
- struct gdev_device *gdev = &gdevs[i];
- struct cdev *cdev = &cdevs[i];
+ int minor = drm->primary->index;
+ int i;
- if (gdev->users) {
- GDEV_PRINT("gdev%d still has %d users.\n", i, gdev->users);
+ if (gdevs[minor].users) {
+ GDEV_PRINT("Device %d has %d users\n", minor, gdevs[minor].users);
}
- if (i < gdev_count) {
- GDEV_PRINT("Removing gdev%d.\n", i);
- gdev_exit_common(gdev);
- cdev_del(cdev);
+ if (minor < gdev_count) {
+ for (i = 0; i < gdev_vcount; i++) {
+ if (gdev_vds[i].parent == &gdevs[minor]) {
+ if (GDEV_SWAP_MEM_SIZE > 0) {
+ gdev_swap_destroy(&gdev_vds[i]);
+ }
+ gdev_exit_scheduler(&gdev_vds[i]);
+ }
+ }
+ gdev_exit_device(&gdevs[minor]);
}
return 0;
}
-#include "gdev_proc.c"
-
int gdev_major_init(struct pci_driver *pdriver)
{
int i, ret;
@@ -239,7 +279,7 @@ int gdev_major_init(struct pci_driver *pdriver)
GDEV_PRINT("Initializing module...\n");
- /* count how many devices are installed. */
+ /* count how many physical devices are installed. */
gdev_count = 0;
for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
pid = &pdriver->id_table[i];
@@ -253,40 +293,96 @@ int gdev_major_init(struct pci_driver *pdriver)
}
}
- GDEV_PRINT("Found %d GPU device(s).\n", gdev_count);
+ GDEV_PRINT("Found %d GPU physical device(s).\n", gdev_count);
+
+ /* virtual device count. */
+ gdev_vcount = GDEV_VDEVICE_COUNT;
+ GDEV_PRINT("Configured %d GPU virtual device(s).\n", gdev_vcount);
- ret = alloc_chrdev_region(&dev, 0, gdev_count, MODULE_NAME);
- if (ret < 0) {
+ /* allocate vdev_count character devices. */
+ if ((ret = alloc_chrdev_region(&dev, 0, gdev_vcount, MODULE_NAME))) {
GDEV_PRINT("Failed to allocate module.\n");
- return ret;
+ goto fail_alloc_chrdev;
}
- /* allocate Gdev device objects. */
- gdevs = kmalloc(sizeof(struct gdev_device) * gdev_count, GFP_KERNEL);
+ /* allocate Gdev physical device objects. */
+ if (!(gdevs = kzalloc(sizeof(*gdevs) * gdev_count, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto fail_alloc_gdevs;
+ }
+ /* allocate Gdev virtual device objects. */
+ if (!(gdev_vds = kzalloc(sizeof(*gdev_vds) * gdev_vcount, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto fail_alloc_gdev_vds;
+ }
/* allocate character device objects. */
- cdevs = kmalloc(sizeof(struct cdev) * gdev_count, GFP_KERNEL);
+ if (!(cdevs = kzalloc(sizeof(*cdevs) * gdev_vcount, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto fail_alloc_cdevs;
+ }
+
+ /* register character devices. */
+ for (i = 0; i < gdev_vcount; i++) {
+ cdev_init(&cdevs[i], &gdev_fops);
+ if ((ret = cdev_add(&cdevs[i], dev, 1))){
+ GDEV_PRINT("Failed to register virtual device %d\n", i);
+ goto fail_cdevs_add;
+ }
+ }
/* create /proc entries. */
- gdev_create_proc();
+ if ((ret = gdev_proc_create())) {
+ GDEV_PRINT("Failed to create /proc entry\n");
+ goto fail_proc_create;
+ }
+
+ /* interrupt handler. */
+ gdev_callback_notify = __gdev_notify_handler;
return 0;
+
+fail_proc_create:
+fail_cdevs_add:
+ for (i = 0; i < gdev_vcount; i++) {
+ cdev_del(&cdevs[i]);
+ }
+ kfree(cdevs);
+fail_alloc_cdevs:
+ kfree(gdev_vds);
+fail_alloc_gdev_vds:
+ kfree(gdevs);
+fail_alloc_gdevs:
+ unregister_chrdev_region(dev, gdev_vcount);
+fail_alloc_chrdev:
+ return ret;
}
int gdev_major_exit(void)
{
+ int i;
+
GDEV_PRINT("Exiting module...\n");
- gdev_delete_proc();
+ gdev_callback_notify = NULL;
+
+ gdev_proc_delete();
+
+ for (i = 0; i < gdev_vcount; i++) {
+ cdev_del(&cdevs[i]);
+ }
+
kfree(cdevs);
+ kfree(gdev_vds);
kfree(gdevs);
- unregister_chrdev_region(dev, gdev_count);
+
+ unregister_chrdev_region(dev, gdev_vcount);
return 0;
}
int gdev_getinfo_device_count(void)
{
- return gdev_count;
+ return gdev_vcount; /* return virtual device count. */
}
EXPORT_SYMBOL(gdev_getinfo_device_count);
View
8 driver/gdev/gdev_drv.h
@@ -126,7 +126,13 @@ int gdev_minor_exit(struct drm_device *);
*/
int gdev_getinfo_device_count(void);
-extern struct gdev_device *gdevs;
+/**
+ * exported variables.
+ */
extern int gdev_count;
+extern int gdev_vcount;
+extern struct gdev_device *gdevs;
+extern struct gdev_device *gdev_vds;
+extern void (*gdev_callback_notify)(int subc, uint32_t data);
#endif
View
68 driver/gdev/gdev_kthread.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011 Shinpei Kato
+ *
+ * University of California, Santa Cruz
+ * Systems Research Lab.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include "gdev_proto.h"
+#include "gdev_sched.h"
+
+static int __gdev_sched_thread(void *__data)
+{
+ while (!kthread_should_stop()) {
+ /* push data into the list here! */
+ /*gdev_schedule_invoked();*/
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+
+ return 0;
+}
+
+int gdev_init_scheduler_thread(struct gdev_device *gdev)
+{
+ struct sched_param sp = { .sched_priority = MAX_RT_PRIO - 1 };
+ struct task_struct *p;
+ char name[64];
+
+ /* create scheduler threads. */
+ sprintf(name, "gsched%d", gdev->id);
+ p = kthread_create(__gdev_sched_thread, (void*)(uint64_t)gdev->id, name);
+ if (p) {
+ sched_setscheduler(p, SCHED_FIFO, &sp);
+ wake_up_process(p);
+ gdev->sched_thread = p;
+ }
+
+ return 0;
+}
+
+void gdev_exit_scheduler_thread(struct gdev_device *gdev)
+{
+ if (gdev->sched_thread)
+ kthread_stop(gdev->sched_thread);
+}
View
218 driver/gdev/gdev_proc.c
@@ -1,80 +1,244 @@
+/*
+ * Copyright 2011 Shinpei Kato
+ *
+ * University of California, Santa Cruz
+ * Systems Research Lab.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
#include <linux/proc_fs.h>
#include "gdev_drv.h"
+#include "gdev_proto.h"
#define GDEV_PROC_MAX_BUF 64
-static struct proc_dir_entry *gproc_dir;
-static struct semaphore gproc_sem;
+static struct proc_dir_entry *gdev_proc;
+static struct proc_dir_entry *proc_dev_count;
+static struct proc_dir_entry *proc_virt_dev_count;
+static struct gdev_proc_vd {
+ struct proc_dir_entry *dir;
+ struct proc_dir_entry *processor;
+ struct proc_dir_entry *memory;
+} *proc_vd;
+static struct semaphore proc_sem;
static int gdev_proc_read(char *kbuf, char *page, int count, int *eof)
{
- down(&gproc_sem);
- //strncpy(page, kbuf, count);
+ down(&proc_sem);
sprintf(page, "%s", kbuf);
count = strlen(page);
*eof = 1;
- up(&gproc_sem);
+ up(&proc_sem);
return count;
}
static int gdev_proc_write(char *kbuf, const char *buf, int count)
{
- down(&gproc_sem);
+ down(&proc_sem);
if (count > GDEV_PROC_MAX_BUF - 1)
count = GDEV_PROC_MAX_BUF - 1;
if (copy_from_user(kbuf, buf, count)) {
GDEV_PRINT("Failed to write /proc entry\n");
- up(&gproc_sem);
+ up(&proc_sem);
return -EFAULT;
}
- up(&gproc_sem);
+ up(&proc_sem);
return count;
}
+/* show virutal and physical device counts. */
static int device_count_read
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
char kbuf[64];
- sprintf(kbuf, "%d", gdev_count);
+ uint32_t dev_count = *((uint32_t*)data);
+
+ sprintf(kbuf, "%u", dev_count);
+
return gdev_proc_read(kbuf, page, count, eof);
}
-static int device_count_write
+/* show virutal device processor/memory utilization. */
+static int vd_util_read
+(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ char kbuf[64];
+ uint32_t util = *((uint32_t*)data);
+
+ sprintf(kbuf, "%u", util);
+
+ return gdev_proc_read(kbuf, page, count, eof);
+}
+
+/* set virutal device processor/memory utilization. */
+static int vd_util_write
(struct file *filp, const char __user *buf, unsigned long count, void *data)
{
char kbuf[64];
+ uint32_t *ptr = (uint32_t*)data;
+ uint32_t old = *ptr;
+ int i;
+
count = gdev_proc_write(kbuf, buf, count);
- sscanf(kbuf, "%d", &gdev_count);
+ sscanf(kbuf, "%u", ptr);
+ if (*ptr > 100) {
+ GDEV_PRINT("Invalid virtual device utilization %u\n", *ptr);
+ *ptr = old;
+ }
+
+ /* detect any changes in memory size and reallocate swap.
+ FIXME: we don't guarantee safety when user administrators change the
+ memory utilization after virtual devices start being used. */
+ for (i = 0; i < gdev_vcount; i++) {
+ struct gdev_device *virt = &gdev_vds[i];
+ struct gdev_device *phys = virt->parent;
+ if (!phys)
+ continue;
+ if (virt->mem_size != phys->mem_size * virt->mem_util / 100) {
+ virt->mem_size = phys->mem_size * virt->mem_util / 100;
+ if (virt->swap) {
+ uint32_t swap_size = GDEV_SWAP_MEM_SIZE * virt->mem_util / 100;
+ gdev_swap_destroy(virt);
+ gdev_swap_create(virt, swap_size);
+ }
+ }
+ if (virt->dma_mem_size != phys->dma_mem_size * virt->mem_util / 100) {
+ virt->dma_mem_size = phys->dma_mem_size * virt->mem_util / 100;
+ }
+ }
+
return count;
}
-int gdev_create_proc(void)
+int gdev_proc_create(void)
{
- struct proc_dir_entry *proc_device_count;
+ int i;
+ char name[256];
+
+ gdev_proc = proc_mkdir("gdev", NULL);
+ if (!gdev_proc) {
+ GDEV_PRINT("Failed to create /proc/gdev\n");
+ goto fail_proc;
+ }
+
+ /* device count */
+ sprintf(name, "device_count");
+ proc_dev_count = create_proc_entry(name, 0644, gdev_proc);
+ if (!proc_dev_count) {
+ GDEV_PRINT("Failed to create /proc/gdev/%s\n", name);
+ goto fail_proc_dev_count;
+ }
+ proc_dev_count->read_proc = device_count_read;
+ proc_dev_count->write_proc = NULL;
+ proc_dev_count->data = (void*)&gdev_count;
+
+ /* virtual device count */
+ sprintf(name, "virtual_device_count");
+ proc_virt_dev_count = create_proc_entry(name, 0644, gdev_proc);
+ if (!proc_virt_dev_count) {
+ GDEV_PRINT("Failed to create /proc/gdev/%s\n", name);
+ goto fail_proc_virt_dev_count;
+ }
+ proc_virt_dev_count->read_proc = device_count_read;
+ proc_virt_dev_count->write_proc = NULL;
+ proc_virt_dev_count->data = (void*)&gdev_vcount;
- gproc_dir = proc_mkdir("gdev", NULL);
- if (!gproc_dir) {
- GDEV_PRINT("Failed to create /proc entry\n");
- return 0;
+ /* virtual devices information */
+ proc_vd = kzalloc(sizeof(*proc_vd) * gdev_vcount, GFP_KERNEL);
+ if (!proc_vd) {
+ GDEV_PRINT("Failed to create /proc/gdev/%s\n", name);
+ goto fail_alloc_proc_vd;
}
+ for (i = 0; i < gdev_vcount; i++) {
+ sprintf(name, "vd%d", i);
+ proc_vd[i].dir = proc_mkdir(name, gdev_proc);
+ if (!proc_vd[i].dir) {
+ GDEV_PRINT("Failed to create /proc/gdev/%s\n", name);
+ goto fail_proc_vd;
+ }
- proc_device_count = create_proc_entry("device_count", 0644, gproc_dir);
- if (!proc_device_count) {
- GDEV_PRINT("Failed to create /proc entry\n");
- return 0;
+ sprintf(name, "processor");
+ proc_vd[i].processor = create_proc_entry(name, 0644, proc_vd[i].dir);
+ if (!proc_vd[i].processor) {
+ GDEV_PRINT("Failed to create /proc/gdev/vd%d/%s\n", i, name);
+ goto fail_proc_vd;
+ }
+ proc_vd[i].processor->read_proc = vd_util_read;
+ proc_vd[i].processor->write_proc = vd_util_write;
+ proc_vd[i].processor->data = (void*)&gdev_vds[i].proc_util;
+
+ sprintf(name, "memory");
+ proc_vd[i].memory = create_proc_entry(name, 0644, proc_vd[i].dir);
+ if (!proc_vd[i].memory) {
+ GDEV_PRINT("Failed to create /proc/gdev/vd%d/%s\n", i, name);
+ goto fail_proc_vd;
+ }
+ proc_vd[i].memory->read_proc = vd_util_read;
+ proc_vd[i].memory->write_proc = vd_util_write;
+ proc_vd[i].memory->data = (void*)&gdev_vds[i].mem_util;
}
- proc_device_count->read_proc = device_count_read;
- proc_device_count->write_proc = device_count_write;
- proc_device_count->data = (void*) NULL;
- sema_init(&gproc_sem, 1);
+ sema_init(&proc_sem, 1);
return 0;
+
+fail_proc_vd:
+ for (i = 0; i < gdev_vcount; i++) {
+ if (proc_vd[i].dir) {
+ sprintf(name, "gdev/vd%d", i);
+ remove_proc_entry(name, gdev_proc);
+ }
+ if (proc_vd[i].processor)
+ remove_proc_entry("processor", proc_vd[i].dir);
+ if (proc_vd[i].memory)
+ remove_proc_entry("memory", proc_vd[i].memory);
+ }
+ kfree(proc_vd);
+fail_alloc_proc_vd:
+ remove_proc_entry("gdev/virtual_device_count", gdev_proc);
+fail_proc_virt_dev_count:
+ remove_proc_entry("gdev/device_count", gdev_proc);
+fail_proc_dev_count:
+ remove_proc_entry("gdev", NULL);
+fail_proc:
+ return -EINVAL;
}
-int gdev_delete_proc(void)
+int gdev_proc_delete(void)
{
- remove_proc_entry("gdev/device_count", gproc_dir);
+ int i;
+ char name[256];
+
+ for (i = 0; i < gdev_vcount; i++) {
+ sprintf(name, "gdev/vd%d", i);
+ remove_proc_entry(name, gdev_proc);
+ remove_proc_entry("processor", proc_vd[i].dir);
+ remove_proc_entry("memory", proc_vd[i].memory);
+ }
+ kfree(proc_vd);
+
+ remove_proc_entry("gdev/virtual_device_count", gdev_proc);
+ remove_proc_entry("gdev/device_count", gdev_proc);
remove_proc_entry("gdev", NULL);
return 0;
View
35 driver/gdev/gdev_proc.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011 Shinpei Kato
+ *
+ * University of California, Santa Cruz
+ * Systems Research Lab.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __GDEV_PROC_H__
+#define __GDEV_PROC_H__
+
+int gdev_proc_create(void);
+int gdev_proc_delete(void);
+
+#endif
View
2 driver/gdev/install.sh
@@ -14,7 +14,7 @@ rm -f /dev/gdev*
# make nodes
major=$(awk "\$2==\"gdev\" {print \$1}" /proc/devices)
-devnum=$(ls /dev/dri/card* | awk "{print \$1}" | wc -l)
+devnum=$(less /proc/gdev/virtual_device_count | awk "{print \$1}")
minor=0
while [ $minor -lt $devnum ]
do
View
6 driver/pscnv/Makefile
@@ -17,9 +17,9 @@ pscnv-y := nouveau_drv.o nouveau_state.o \
nvc0_vram.o nvc0_vm.o nvc0_chan.o nvc0_copy.o nvc0_fifo.o \
nvc0_graph.o nvc0_grctx.o \
pscnv_gdev.o \
- gdev_api.o gdev_drv.o gdev_ioctl.o gdev_nvidia.o gdev_mm.o \
- gdev_nvidia_nvc0.o
-
+ gdev_drv.o gdev_ioctl.o gdev_kthread.o gdev_proc.o \
+ gdev_api.o gdev_init.o gdev_sched.o \
+ gdev_nvidia.o gdev_nvidia_nvc0.o
pscnv-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
pscnv-$(CONFIG_COMPAT) += nouveau_ioc32.o
View
3 driver/pscnv/nouveau_irq.c
@@ -1054,8 +1054,7 @@ nv50_pgraph_irq_handler(struct drm_device *dev)
if (status & 0x00000001) {
nouveau_graph_trap_info(dev, &trap);
if (nouveau_ratelimit())
- nouveau_graph_dump_trap_info(dev,
- "PGRAPH_NOTIFY", &trap);
+ nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap);
status &= ~0x00000001;
nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001);
}
View
9 driver/pscnv/nvc0_graph.c
@@ -1048,6 +1048,8 @@ nvc0_graph_trap_handler(struct drm_device *dev, int cid)
}
}
+#include "gdev_drv.h"
+
void nvc0_graph_irq_handler(struct drm_device *dev, int irq)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1077,7 +1079,12 @@ void nvc0_graph_irq_handler(struct drm_device *dev, int irq)
cid = -1;
if (status & NVC0_PGRAPH_INTR_NOTIFY) {
- PGRAPH_ERROR("PGRAPH_NOTIFY");
+ if (gdev_callback_notify) {
+ gdev_callback_notify(subc, datal);
+ }
+ else {
+ PGRAPH_ERROR("PGRAPH_NOTIFY");
+ }
nv_wr32(dev, NVC0_PGRAPH_INTR, NVC0_PGRAPH_INTR_NOTIFY);
status &= ~NVC0_PGRAPH_INTR_NOTIFY;
}
View
56 driver/pscnv/pscnv_gdev.c
@@ -26,6 +26,7 @@
#include "gdev_list.h"
#include "gdev_nvidia.h"
#include "gdev_proto.h"
+#include "gdev_sched.h"
#include "nouveau_drv.h"
#include "pscnv_chan.h"
#include "pscnv_fifo.h"
@@ -36,54 +37,45 @@
extern uint32_t *nvc0_fifo_ctrl_ptr(struct drm_device *, struct pscnv_chan *);
-int gdev_init_private(struct gdev_device *gdev)
-{
- return 0;
-}
-
-/* finalize the private Gdev members. */
-void gdev_exit_private(struct gdev_device *gdev)
-{
-}
-
/* query device-specific information. */
int gdev_raw_query(struct gdev_device *gdev, uint32_t type, uint64_t *result)
{
struct drm_device *drm = (struct drm_device *) gdev->priv;
struct drm_pscnv_getparam getparam;
+ int ret;
switch (type) {
case GDEV_NVIDIA_QUERY_MP_COUNT:
getparam.param = PSCNV_GETPARAM_MP_COUNT;
- pscnv_ioctl_getparam(drm, &getparam, NULL);
+ ret = pscnv_ioctl_getparam(drm, &getparam, NULL);
*result = getparam.value;
break;
- case GDEV_NVIDIA_QUERY_DEVICE_MEM_SIZE:
+ case GDEV_QUERY_DEVICE_MEM_SIZE:
getparam.param = PSCNV_GETPARAM_FB_SIZE;
- pscnv_ioctl_getparam(drm, &getparam, NULL);
+ ret = pscnv_ioctl_getparam(drm, &getparam, NULL);
*result = getparam.value;
break;
- case GDEV_NVIDIA_QUERY_DMA_MEM_SIZE:
+ case GDEV_QUERY_DMA_MEM_SIZE:
getparam.param = PSCNV_GETPARAM_AGP_SIZE;
- pscnv_ioctl_getparam(drm, &getparam, NULL);
+ ret = pscnv_ioctl_getparam(drm, &getparam, NULL);
*result = getparam.value;
break;
- case GDEV_NVIDIA_QUERY_CHIPSET:
+ case GDEV_QUERY_CHIPSET:
getparam.param = PSCNV_GETPARAM_CHIPSET_ID;
- pscnv_ioctl_getparam(drm, &getparam, NULL);
+ ret = pscnv_ioctl_getparam(drm, &getparam, NULL);
*result = getparam.value;
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ return ret;
}
/* open a new Gdev object associated with the specified device. */
struct gdev_device *gdev_raw_dev_open(int minor)
{
- struct gdev_device *gdev = &gdevs[minor];
+ struct gdev_device *gdev = &gdev_vds[minor]; /* virutal device */
gdev->users++;
@@ -111,6 +103,7 @@ struct gdev_vas *gdev_raw_vas_new(struct gdev_device *gdev, uint64_t size)
vspace->filp = NULL; /* we don't need vspace->filp in Gdev. */
vas->pvas = (void *) vspace; /* driver private object. */
+ vas->vid = vspace->vid; /* VAS ID. */
return vas;
@@ -141,8 +134,8 @@ struct gdev_ctx *gdev_raw_ctx_new
uint32_t chipset = priv->chipset;
struct pscnv_vspace *vspace = vas->pvas;
struct pscnv_chan *chan;
- struct pscnv_bo *ib_bo, *pb_bo, *fence_bo;
- struct pscnv_mm_node *ib_mm, *pb_mm, *fence_mm;
+ struct pscnv_bo *ib_bo, *pb_bo, *fence_bo, *notify_bo;
+ struct pscnv_mm_node *ib_mm, *pb_mm, *fence_mm, *notify_mm;
int ret;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -211,7 +204,7 @@ struct gdev_ctx *gdev_raw_ctx_new
goto fail_fifo_reg;
}
- /* fences init. */
+ /* fence buffer. */
fence_bo = pscnv_mem_alloc(drm, GDEV_FENCE_BUF_SIZE,
PSCNV_GEM_SYSRAM_SNOOP, 0, 0);
if (!fence_bo)
@@ -226,11 +219,28 @@ struct gdev_ctx *gdev_raw_ctx_new
ctx->fence.addr = fence_mm->start;
ctx->fence.seq = 0;
+ /* notify buffer. */
+ notify_bo = pscnv_mem_alloc(drm, 8 /* 64bit */, PSCNV_GEM_VRAM_SMALL, 0, 0);
+ if (!notify_bo)
+ goto fail_notify_alloc;
+ ret = pscnv_vspace_map(vspace, notify_bo, GDEV_VAS_USER_START,
+ GDEV_VAS_USER_END, 0, &notify_mm);
+ if (ret)
+ goto fail_notify_map;
+ ctx->notify.bo = notify_bo;
+ ctx->notify.addr = notify_mm->start;
+
/* private data. */
ctx->pctx = (void *) chan;
+ /* context ID = channel ID. */
+ ctx->cid = chan->cid;
return ctx;
+fail_notify_map:
+ pscnv_mem_free(notify_bo);
+fail_notify_alloc:
+ pscnv_vspace_unmap(vspace, fence_mm->start);
fail_fence_map:
pscnv_mem_free(fence_bo);
fail_fence_alloc:
View
37 runtime/user/pscnv/pscnv_gdev.c
@@ -33,22 +33,12 @@
#include <sys/unistd.h>
#define PSCNV_BO_FLAGS_HOST (PSCNV_GEM_SYSRAM_SNOOP | PSCNV_GEM_MAPPABLE)
+#define GDEV_DEVICE_MAX_COUNT 32
struct gdev_device gdevs[GDEV_DEVICE_MAX_COUNT] = {
- [0 ... GDEV_DEVICE_MAX_COUNT-1] = {0, 0, 0, 0, 0, 0, 0, NULL, NULL}
+ [0 ... GDEV_DEVICE_MAX_COUNT-1] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
-/* initialize the private Gdev members. */
-int gdev_init_private(struct gdev_device *gdev)
-{
- return 0;
-}
-
-/* finalize the private Gdev members. */
-void gdev_exit_private(struct gdev_device *gdev)
-{
-}
-
/* query a piece of the device-specific information. */
int gdev_raw_query(struct gdev_device *gdev, uint32_t type, uint64_t *result)
{
@@ -89,7 +79,7 @@ struct gdev_device *gdev_raw_dev_open(int minor)
sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
if ((fd = open(buf, O_RDWR, 0)) < 0)
return NULL;
- gdev_init_common(gdev, minor, (void *) (unsigned long) fd);
+ gdev_init_device(gdev, minor, (void *) (unsigned long) fd);
}
gdev->users++;
@@ -103,7 +93,7 @@ void gdev_raw_dev_close(struct gdev_device *gdev)
int fd = ((unsigned long) gdev->priv & 0xffffffff); /* avoid warning :) */
if (--gdev->users == 0) {
- gdev_exit_common(gdev);
+ gdev_exit_device(gdev);
close(fd);
}
}
@@ -125,6 +115,8 @@ struct gdev_vas *gdev_raw_vas_new(struct gdev_device *gdev, uint64_t size)
/* private data */
vas->pvas = (void *) chan;
+ /* VAS ID */
+ vas->vid = chan->vid;
return vas;
@@ -158,6 +150,7 @@ struct gdev_ctx *gdev_raw_ctx_new
{
struct gdev_ctx *ctx;
struct pscnv_ib_bo *fence_bo;
+ struct pscnv_ib_bo *notify_bo;
struct pscnv_ib_chan *chan = (struct pscnv_ib_chan *) vas->pvas;
uint32_t chipset = gdev->chipset;
@@ -192,7 +185,7 @@ struct gdev_ctx *gdev_raw_ctx_new
goto fail_fifo_reg;
}
- /* fences init. */
+ /* fence buffer. */
if (pscnv_ib_bo_alloc(chan->fd, chan->vid, 1, PSCNV_BO_FLAGS_HOST, 0,
GDEV_FENCE_BUF_SIZE, 0, &fence_bo))
goto fail_fence_alloc;
@@ -201,11 +194,22 @@ struct gdev_ctx *gdev_raw_ctx_new
ctx->fence.addr = fence_bo->vm_base;
ctx->fence.seq = 0;
+ /* interrupt buffer. */
+ if (pscnv_ib_bo_alloc(chan->fd, chan->vid, 1, PSCNV_GEM_VRAM_SMALL, 0,
+ 8 /* 64 bits */, 0, &notify_bo))
+ goto fail_notify_alloc;
+ ctx->notify.bo = notify_bo;
+ ctx->notify.addr = notify_bo->vm_base;
+
/* private data */
ctx->pctx = (void *) chan;
+ /* context ID = channel ID. */
+ ctx->cid = chan->cid;
return ctx;
-
+
+fail_notify_alloc:
+ pscnv_ib_bo_free(fence_bo);
fail_fence_alloc:
fail_fifo_reg:
free(ctx);
@@ -217,6 +221,7 @@ struct gdev_ctx *gdev_raw_ctx_new
void gdev_raw_ctx_free(struct gdev_ctx *ctx)
{
pscnv_ib_bo_free(ctx->fence.bo);
+ pscnv_ib_bo_free(ctx->notify.bo);
free(ctx);
}

0 comments on commit 3ddab5e

Please sign in to comment.
Something went wrong with that request. Please try again.