/* note: we use upper 8 bits of flags for driver-internal flags: */ #define OMAP_BO_MEM_DMA_API 0x01000000 /* memory allocated with the dma_alloc_* API */ #define OMAP_BO_MEM_SHMEM 0x02000000 /* memory allocated through shmem backing */ #define OMAP_BO_MEM_DMABUF 0x08000000 /* memory imported from a dmabuf */
/* To deal with userspace mmap'ings of 2d tiled buffers, which (a) are *notnecessarilypinnedinTILERallthetime,and(b)whentheyare *theyarenotnecessarilypagealigned,wereserveoneormoresmall *regionsineachofthe2dcontainerstouseasauser-GARTwherewe *cancreateasecondpage-alignedmappingofpartsofthebuffer *beingaccessedfromuserspace. * *Notethatwecouldoptimizeslightlywhenweknowthatmultiple *tilercontainersarebackedbythesamePAT..butI'llleavethat *forlater..
*/ #define NUM_USERGART_ENTRIES 2 struct omap_drm_usergart_entry { struct tiler_block *block; /* the reserved tiler block */
dma_addr_t dma_addr; struct drm_gem_object *obj; /* the current pinned obj */
pgoff_t obj_pgoff; /* page offset of obj currently
mapped in */
};
struct omap_drm_usergart { struct omap_drm_usergart_entry entry[NUM_USERGART_ENTRIES]; int height; /* height in rows */ int height_shift; /* ilog2(height in rows) */ int slot_shift; /* ilog2(width per slot) */ int stride_pfn; /* stride in pages */ int last; /* index of last used entry */
};
/** get mmap offset */
u64 omap_gem_mmap_offset(struct drm_gem_object *obj)
{ struct drm_device *dev = obj->dev; int ret;
size_t size;
/* Make it mmapable */
size = omap_gem_mmap_size(obj);
ret = drm_gem_create_mmap_offset_size(obj, size); if (ret) {
dev_err(dev->dev, "could not allocate mmap offset\n"); return0;
}
if (m > 1) { int i; /* if stride > than PAGE_SIZE then sparse mapping: */ for (i = n; i > 0; i--) {
unmap_mapping_range(obj->dev->anon_inode->i_mapping,
off, PAGE_SIZE, 1);
off += PAGE_SIZE * m;
}
} else {
unmap_mapping_range(obj->dev->anon_inode->i_mapping,
off, size, 1);
}
entry->obj = NULL;
}
/* Evict a buffer from usergart, if it is mapped there */ staticvoid omap_gem_evict(struct drm_gem_object *obj)
{ struct omap_gem_object *omap_obj = to_omap_bo(obj); struct omap_drm_private *priv = obj->dev->dev_private;
if (omap_obj->flags & OMAP_BO_TILED_MASK) { enum tiler_fmt fmt = gem2fmt(omap_obj->flags); int i;
for (i = 0; i < NUM_USERGART_ENTRIES; i++) { struct omap_drm_usergart_entry *entry =
&priv->usergart[fmt].entry[i];
if (entry->obj == obj)
omap_gem_evict_entry(obj, fmt, entry);
}
}
}
pages = drm_gem_get_pages(obj); if (IS_ERR(pages)) {
dev_err(obj->dev->dev, "could not get pages: %ld\n", PTR_ERR(pages)); return PTR_ERR(pages);
}
/* for non-cached buffers, ensure the new pages are clean because *DSS,GPU,etc.arenotcachecoherent:
*/ if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) {
addrs = kmalloc_array(npages, sizeof(*addrs), GFP_KERNEL); if (!addrs) {
ret = -ENOMEM; goto free_pages;
}
for (i = 0; i < npages; i++) {
addrs[i] = dma_map_page(dev->dev, pages[i], 0, PAGE_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(dev->dev, addrs[i])) {
dev_warn(dev->dev, "%s: failed to map page\n", __func__);
for (i = i - 1; i >= 0; --i) {
dma_unmap_page(dev->dev, addrs[i],
PAGE_SIZE, DMA_TO_DEVICE);
}
ret = -ENOMEM; goto free_addrs;
}
}
} else {
addrs = kcalloc(npages, sizeof(*addrs), GFP_KERNEL); if (!addrs) {
ret = -ENOMEM; goto free_pages;
}
}
/* Special handling for the case of faulting in 2d tiled buffers */ static vm_fault_t omap_gem_fault_2d(struct drm_gem_object *obj, struct vm_area_struct *vma, struct vm_fault *vmf)
{ struct omap_gem_object *omap_obj = to_omap_bo(obj); struct omap_drm_private *priv = obj->dev->dev_private; struct omap_drm_usergart_entry *entry; enum tiler_fmt fmt = gem2fmt(omap_obj->flags); struct page *pages[64]; /* XXX is this too much to have on stack? */ unsignedlong pfn;
pgoff_t pgoff, base_pgoff; unsignedlong vaddr; int i, err, slots;
vm_fault_t ret = VM_FAULT_NOPAGE;
/* evict previous buffer using this usergart entry, if any: */ if (entry->obj)
omap_gem_evict_entry(entry->obj, fmt, entry);
entry->obj = obj;
entry->obj_pgoff = base_pgoff;
/* now convert base_pgoff to phys offset from virt offset: */
base_pgoff = (base_pgoff >> n_shift) * slots;
/* for wider-than 4k.. figure out which part of the slot-row we want: */ if (m > 1) { int off = pgoff % m;
entry->obj_pgoff += off;
base_pgoff /= m;
slots = min(slots - (off << n_shift), n);
base_pgoff += off << n_shift;
vaddr += off << PAGE_SHIFT;
}
for (i = n; i > 0; i--) {
ret = vmf_insert_mixed(vma, vaddr, pfn); if (ret & VM_FAULT_ERROR) break;
pfn += priv->usergart[fmt].stride_pfn;
vaddr += PAGE_SIZE * m;
}
/* Make sure we don't parallel update on a fault, nor move or remove *somethingfrombeneathourfeet
*/
mutex_lock(&omap_obj->lock);
/* if a shmem backed object, make sure we have pages attached now */
err = omap_gem_attach_pages(obj); if (err) {
ret = vmf_error(err); goto fail;
}
/* where should we do corresponding put_pages().. we are mapping *theoriginalpage,ratherthanthruaGART,sowecan'trely *onevictiontotriggerthis.Butmunmap()orallmappingsshould *probablytriggerput_pages()?
*/
if (omap_obj->flags & OMAP_BO_TILED_MASK)
ret = omap_gem_fault_2d(obj, vma, vmf); else
ret = omap_gem_fault_1d(obj, vma, vmf);
/** *omap_gem_dumb_map_offset-createanoffsetforadumbbuffer *@file:ourdrmclientfile *@dev:drmdevice *@handle:GEMhandletotheobject(fromdumb_create) *@offset:memorymapoffsetplaceholder * *Dothenecessarysetuptoallowthemappingoftheframebuffer *intousermemory.Wedon'thavetodomuchhereatthemoment.
*/ int omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
u32 handle, u64 *offset)
{ struct drm_gem_object *obj; int ret = 0;
/* GEM does all our handle to object mapping */
obj = drm_gem_object_lookup(file, handle); if (obj == NULL) {
ret = -ENOENT; goto fail;
}
*offset = omap_gem_mmap_offset(obj);
drm_gem_object_put(obj);
fail: return ret;
}
#ifdef CONFIG_DRM_FBDEV_EMULATION /* Set scrolling position. This allows us to implement fast scrolling *forconsole. * *Callonlyfromnon-atomiccontexts.
*/ int omap_gem_roll(struct drm_gem_object *obj, u32 roll)
{ struct omap_gem_object *omap_obj = to_omap_bo(obj);
u32 npages = obj->size >> PAGE_SHIFT; int ret = 0;
/* Get rotated scanout address (only valid if already pinned), at the *specifiedorientationandx,yoffsetfromtop-leftcornerofbuffer *(onlyvalidfortiled2dbuffers)
*/ int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient, int x, int y, dma_addr_t *dma_addr)
{ struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = -EINVAL;
/* Get tiler stride for the buffer (only valid for 2d tiled buffers) */ int omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient)
{ struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = -EINVAL; if (omap_obj->flags & OMAP_BO_TILED_MASK)
ret = tiler_stride(gem2fmt(omap_obj->flags), orient); return ret;
}
/* if !remap, and we don't have pages backing, then fail, rather than *increasingthepincount(whichwedon'treallydoyetanyways, *becausewedon'tsupportswappingpagesbackout).And'remap' *mightnotbequitetherightname,butIwantedtokeepitworking *similarlytoomap_gem_pin().Notethoughthatmutexisnot *aquiredif!remap(becausethiscanbecalledinatomicctxt), *butprobablyomap_gem_unpin()shouldbechangedtoworkinthe *sameway.If!remap,amatchingomap_gem_put_pages()callisnot *required(andshouldnotbemade).
*/ int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, bool remap)
{ struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = 0;
mutex_lock(&omap_obj->lock);
if (remap) {
ret = omap_gem_attach_pages(obj); if (ret) goto unlock;
}
if (!omap_obj->pages) {
ret = -ENOMEM; goto unlock;
}
*pages = omap_obj->pages;
unlock:
mutex_unlock(&omap_obj->lock);
return ret;
}
/* release pages when DMA no longer being performed */ int omap_gem_put_pages(struct drm_gem_object *obj)
{ /* do something here if we dynamically attach/detach pages.. at *leasttheywouldnolongerneedtobepinnedifeveryonehas *releasedthepages..
*/ return0;
}
if (!omap_gem_validate_flags(dev, flags)) return NULL;
/* Validate the flags and compute the memory and cache flags. */ if (flags & OMAP_BO_TILED_MASK) { /* *Tiledbuffersarealwaysshmempagedbacked.Whentheyare *scannedout,theyareremappedintoDMM/TILER.
*/
flags |= OMAP_BO_MEM_SHMEM;
/* Without a DMM only physically contiguous buffers can be supported. */ if (!omap_gem_sgt_is_contiguous(sgt, size) && !priv->has_dmm) return ERR_PTR(-EINVAL);
/* If DMM is used, we need to set some stuff up.. */ void omap_gem_init(struct drm_device *dev)
{ struct omap_drm_private *priv = dev->dev_private; struct omap_drm_usergart *usergart; constenum tiler_fmt fmts[] = {
TILFMT_8BIT, TILFMT_16BIT, TILFMT_32BIT
}; int i, j;
if (!dmm_is_available()) { /* DMM only supported on OMAP4 and later, so this isn't fatal */
dev_warn(dev->dev, "DMM not available, disable DMM support\n"); return;
}
usergart = kcalloc(3, sizeof(*usergart), GFP_KERNEL); if (!usergart) return;
/* reserve 4k aligned/wide regions for userspace mappings: */ for (i = 0; i < ARRAY_SIZE(fmts); i++) {
u16 h = 1, w = PAGE_SIZE >> i;
tiler_align(fmts[i], &w, &h); /* note: since each region is 1 4kb page wide, and minimum *numberofrows,theheightendsupbeingthesameasthe *#ofpagesintheregion
*/
usergart[i].height = h;
usergart[i].height_shift = ilog2(h);
usergart[i].stride_pfn = tiler_stride(fmts[i], 0) >> PAGE_SHIFT;
usergart[i].slot_shift = ilog2((PAGE_SIZE / h) >> i); for (j = 0; j < NUM_USERGART_ENTRIES; j++) { struct omap_drm_usergart_entry *entry; struct tiler_block *block;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.