|
@@ -94,8 +94,10 @@ int psb_gtt_init(struct psb_gtt *pg, int resume)
|
|
|
PSB_WVDC32(pg->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL);
|
|
|
(void) PSB_RVDC32(PSB_PGETBL_CTL);
|
|
|
|
|
|
- pg->initialized = 1;
|
|
|
+ /* The root resource we allocate address space from */
|
|
|
+ dev_priv->gtt_mem = &dev->pdev->resource[PSB_GATT_RESOURCE];
|
|
|
|
|
|
+ pg->initialized = 1;
|
|
|
pg->gtt_phys_start = pg->pge_ctl & PAGE_MASK;
|
|
|
|
|
|
pg->gatt_start = pci_resource_start(dev->pdev, PSB_GATT_RESOURCE);
|
|
@@ -884,3 +886,154 @@ int psb_gtt_unmap_meminfo(struct drm_device *dev, void * hKernelMemInfo)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * GTT resource allocator
|
|
|
+ */
|
|
|
+
|
|
|
+/**
|
|
|
+ * psb_gtt_alloc_handle - allocate a handle to a GTT map
|
|
|
+ * @dev: our DRM device
|
|
|
+ * @gt: Our GTT range
|
|
|
+ *
|
|
|
+ * Assign a handle to a gtt range object. For the moment we use a very
|
|
|
+ * simplistic interface.
|
|
|
+ */
|
|
|
+int psb_gtt_alloc_handle(struct drm_device *dev, struct gtt_range *gt)
|
|
|
+{
|
|
|
+ struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
+ int h;
|
|
|
+
|
|
|
+ mutex_lock(&dev_priv->gtt_mutex);
|
|
|
+ for (h = 0; h < GTT_MAX; h++) {
|
|
|
+ if (dev_priv->gtt_handles[h] == NULL) {
|
|
|
+ dev_priv->gtt_handles[h] = gt;
|
|
|
+ gt->handle = h;
|
|
|
+ kref_get(>->kref);
|
|
|
+ mutex_unlock(&dev_priv->gtt_mutex);
|
|
|
+ return h;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mutex_unlock(&dev_priv->gtt_mutex);
|
|
|
+ return -ENOSPC;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * psb_gtt_release_handle - release a handle to a GTT map
|
|
|
+ * @dev: our DRM device
|
|
|
+ * @gt: Our GTT range
|
|
|
+ *
|
|
|
+ * Remove the handle from a gtt range object
|
|
|
+ */
|
|
|
+int psb_gtt_release_handle(struct drm_device *dev, struct gtt_range *gt)
|
|
|
+{
|
|
|
+ struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
+
|
|
|
+ if (gt->handle < 0 || gt->handle >= GTT_MAX) {
|
|
|
+ gt->handle = -1;
|
|
|
+ WARN_ON(1);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ mutex_lock(&dev_priv->gtt_mutex);
|
|
|
+ dev_priv->gtt_handles[gt->handle] = NULL;
|
|
|
+ gt->handle = -1;
|
|
|
+ mutex_unlock(&dev_priv->gtt_mutex);
|
|
|
+ psb_gtt_kref_put(gt);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * psb_gtt_lookup_handle - look up a GTT handle
|
|
|
+ * @dev: our DRM device
|
|
|
+ * @handle: our handle
|
|
|
+ *
|
|
|
+ * Look up a gtt handle and return the gtt or NULL. The object returned
|
|
|
+ * has a reference held so the caller must drop this when finished.
|
|
|
+ */
|
|
|
+struct gtt_range *psb_gtt_lookup_handle(struct drm_device *dev, int handle)
|
|
|
+{
|
|
|
+ struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
+ struct gtt_range *gt;
|
|
|
+
|
|
|
+ if (handle < 0 || handle > GTT_MAX)
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
+
|
|
|
+ mutex_lock(&dev_priv->gtt_mutex);
|
|
|
+ gt = dev_priv->gtt_handles[handle];
|
|
|
+ kref_get(>->kref);
|
|
|
+ mutex_unlock(&dev_priv->gtt_mutex);
|
|
|
+
|
|
|
+ if (gt == NULL)
|
|
|
+ return ERR_PTR(-ENOENT);
|
|
|
+ return gt;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * psb_gtt_alloc_range - allocate GTT address space
|
|
|
+ * @dev: Our DRM device
|
|
|
+ * @len: length (bytes) of address space required
|
|
|
+ * @name: resource name
|
|
|
+ *
|
|
|
+ * Ask the kernel core to find us a suitable range of addresses
|
|
|
+ * to use for a GTT mapping.
|
|
|
+ *
|
|
|
+ * Returns a gtt_range structure describing the object, or NULL on
|
|
|
+ * error. On successful return the resource is both allocated and marked
|
|
|
+ * as in use.
|
|
|
+ */
|
|
|
+struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len,
|
|
|
+ const char *name)
|
|
|
+{
|
|
|
+ struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
+ struct gtt_range *gt;
|
|
|
+ struct resource *r = dev_priv->gtt_mem;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ gt = kzalloc(sizeof(struct gtt_range), GFP_KERNEL);
|
|
|
+ if (gt == NULL)
|
|
|
+ return NULL;
|
|
|
+ gt->handle = -1;
|
|
|
+ gt->resource.name = name;
|
|
|
+ kref_init(>->kref);
|
|
|
+
|
|
|
+ ret = allocate_resource(dev_priv->gtt_mem, >->resource,
|
|
|
+ len, 0, -1, /*r->start, r->end - 1, */
|
|
|
+ PAGE_SIZE, NULL, NULL);
|
|
|
+ if (ret == 0) {
|
|
|
+ gt->offset = gt->resource.start - r->start;
|
|
|
+ return gt;
|
|
|
+ }
|
|
|
+ kfree(gt);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static void psb_gtt_destroy(struct kref *kref)
|
|
|
+{
|
|
|
+ struct gtt_range *gt = container_of(kref, struct gtt_range, kref);
|
|
|
+ release_resource(>->resource);
|
|
|
+ kfree(gt);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * psb_gtt_kref_put - drop reference to a GTT object
|
|
|
+ * @gt: the GT being dropped
|
|
|
+ *
|
|
|
+ * Drop a reference to a psb gtt
|
|
|
+ */
|
|
|
+void psb_gtt_kref_put(struct gtt_range *gt)
|
|
|
+{
|
|
|
+ kref_put(>->kref, psb_gtt_destroy);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * psb_gtt_free_range - release GTT address space
|
|
|
+ * @dev: our DRM device
|
|
|
+ * @gt: a mapping created with psb_gtt_alloc_range
|
|
|
+ *
|
|
|
+ * Release a resource that was allocated with psb_gtt_alloc_range
|
|
|
+ */
|
|
|
+void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt)
|
|
|
+{
|
|
|
+ if (gt->handle != -1)
|
|
|
+ psb_gtt_release_handle(dev, gt);
|
|
|
+ psb_gtt_kref_put(gt);
|
|
|
+}
|