#define _PSB_DRV_H_
#include <linux/version.h>
+#include <linux/kref.h>
#include <drm/drmP.h>
#include "drm_global.h"
int enabled;
};
+
struct drm_psb_private {
struct drm_device *dev;
struct psb_gtt *pg;
- /*GTT Memory manager*/
+ /* GTT Memory manager */
struct psb_gtt_mm *gtt_mm;
struct page *scratch_page;
+ struct mutex gtt_mutex;
+ struct resource *gtt_mem; /* Our PCI resource */
+ struct gtt_range *gtt_handles[GTT_MAX];
+
+ struct gtt_range *fb; /* System frame buffer */
+
struct psb_mmu_driver *mmu;
struct psb_mmu_pd *pf_pd;
+ /*
+ * Register base
+ */
+
uint8_t *sgx_reg;
uint8_t *vdc_reg;
uint32_t gatt_free_offset;
/*
- *Fencing / irq.
+ * Fencing / irq.
*/
uint32_t vdc_irq_mask;
DRM_DEBUG("vm_pgoff 0x%lx, screen base %p vram_addr %p\n",
vma->vm_pgoff, fb_screen_base, pg->vram_addr);
- /*if using stolen memory, */
- if (fb_screen_base == pg->vram_addr) {
+ /* FIXME: ultimately this needs to become 'if entirely stolen memory' */
+ if (1 || fb_screen_base == pg->vram_addr) {
vma->vm_ops = &psbfb_vm_ops;
vma->vm_private_data = (void *)psbfb;
vma->vm_flags |= VM_RESERVED | VM_IO |
VM_MIXEDMAP | VM_DONTEXPAND;
} else {
- /*using IMG meminfo, can I use pvrmmap to map it?*/
-
+ /* GTT memory backed by kernel/user pages, needs a different
+ approach ? */
}
return 0;
drm_helper_mode_fill_fb_struct(&fb->base, r);
- fb->bo = mm_private;
+ fb->mem = mm_private;
return &fb->base;
struct psb_framebuffer *psbfb;
struct drm_mode_fb_cmd mode_cmd;
struct device *device = &dev->pdev->dev;
-
- struct ttm_buffer_object *fbo = NULL;
int size, aligned_size;
int ret;
size = mode_cmd.pitch * mode_cmd.height;
aligned_size = ALIGN(size, PAGE_SIZE);
+ /* Allocate the framebuffer in the GTT */
+ /* FIXME: this cannot live in dev_priv once we go multi head */
+ dev_priv->fb = psb_gtt_alloc_range(dev, aligned_size, "fb");
+ if (dev_priv->fb == NULL)
+ return -ENOMEM;
+
mutex_lock(&dev->struct_mutex);
- fb = psb_framebuffer_create(dev, &mode_cmd, fbo);
+ fb = psb_framebuffer_create(dev, &mode_cmd, dev_priv->fb);
if (!fb) {
DRM_ERROR("failed to allocate fb.\n");
ret = -ENOMEM;
info->fbops = &psbfb_ops;
info->fix.smem_start = dev->mode_config.fb_base;
info->fix.smem_len = size;
- info->screen_base = (char *)pg->vram_addr;
+
+ /* Accessed via stolen memory directly, This only works for stolem
+ memory however. Need to address this once we start using gtt
+ pages we allocate */
+ info->screen_base = (char *)pg->vram_addr + dev_priv->fb->offset;
info->screen_size = size;
memset(info->screen_base, 0, size);
fb->funcs->destroy(fb);
out_err1:
mutex_unlock(&dev->struct_mutex);
+ psb_gtt_free_range(dev, dev_priv->fb);
+ dev_priv->fb = NULL;
return ret;
}
if (fbdev->psb_fb_helper.fbdev) {
info = fbdev->psb_fb_helper.fbdev;
+ psb_gtt_free_range(dev, psbfb->mem);
unregister_framebuffer(info);
iounmap(info->screen_base);
framebuffer_release(info);
}
drm_fb_helper_fini(&fbdev->psb_fb_helper);
-
drm_framebuffer_cleanup(&psbfb->base);
-
return 0;
}
return 0;
info = psbfb->fbdev;
- psbfb->pvrBO = NULL;
if (info)
framebuffer_release(info);
#include "psb_drv.h"
-/*IMG Headers*/
-/*#include "servicesint.h"*/
-
struct psb_framebuffer {
struct drm_framebuffer base;
struct address_space *addr_space;
- struct ttm_buffer_object *bo;
- struct fb_info * fbdev;
- /* struct ttm_bo_kmap_obj kmap; */
- void *pvrBO; /* FIXME: sort this out */
+ struct fb_info *fbdev;
+ struct gtt_range *mem;
void * hKernelMemInfo;
uint32_t size;
uint32_t offset;
struct psb_fbdev {
struct drm_fb_helper psb_fb_helper;
- struct psb_framebuffer * pfb;
+ struct psb_framebuffer *pfb;
};
#define to_psb_fb(x) container_of(x, struct psb_framebuffer, base)
-
extern int psb_intel_connector_clones(struct drm_device *dev, int type_mask);
-
#endif
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);
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);
+}
uint32_t *offset);
extern int psb_gtt_unmap_meminfo(struct drm_device *dev,
void * hKernelMemInfo);
-extern int psb_gtt_map_meminfo_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int psb_gtt_unmap_meminfo_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
extern int psb_gtt_mm_init(struct psb_gtt *pg);
extern void psb_gtt_mm_takedown(void);
+/* Each gtt_range describes an allocation in the GTT area */
+struct gtt_range {
+ struct resource resource;
+ u32 offset;
+ int handle;
+ struct kref kref;
+};
+
+/* Most GTT handles we allow allocation of - for now five is fine: we need
+ - Two framebuffers
+ - Maybe an upload area
+ - One cursor (eventually)
+ - One fence page (possibly)
+*/
+
+#define GTT_MAX 5
+
+extern int psb_gtt_alloc_handle(struct drm_device *dev, struct gtt_range *gt);
+extern int psb_gtt_release_handle(struct drm_device *dev, struct gtt_range *gt);
+extern struct gtt_range *psb_gtt_lookup_handle(struct drm_device *dev,
+ int handle);
+extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len,
+ const char *name);
+extern void psb_gtt_kref_put(struct gtt_range *gt);
+extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt);
+
#endif