Intel-2D: sna_blit_copy

i915: i915_gem_execbuffer2.  It's full of bugs!

git-svn-id: svn://kolibrios.org@3263 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2013-02-23 09:47:31 +00:00
parent 3dd2cc0db3
commit 75968b0534
18 changed files with 2066 additions and 96 deletions

View File

@ -1149,6 +1149,9 @@ static bool gen6_rectangle_begin(struct sna *sna,
int id = 1 << GEN6_VERTEX(op->u.gen6.flags);
int ndwords;
if (sna_vertex_wait__locked(&sna->render) && sna->render.vertex_offset)
return true;
ndwords = op->need_magic_ca_pass ? 60 : 6;
if ((sna->render.vb_id & id) == 0)
ndwords += 5;
@ -1165,6 +1168,12 @@ static bool gen6_rectangle_begin(struct sna *sna,
static int gen6_get_rectangles__flush(struct sna *sna,
const struct sna_composite_op *op)
{
/* Preventing discarding new vbo after lock contention */
if (sna_vertex_wait__locked(&sna->render)) {
int rem = vertex_space(sna);
if (rem > op->floats_per_rect)
return rem;
}
if (!kgem_check_batch(&sna->kgem, op->need_magic_ca_pass ? 65 : 5))
return 0;
@ -1218,7 +1227,7 @@ flush:
gen4_vertex_flush(sna);
gen6_magic_ca_pass(sna, op);
}
// sna_vertex_wait__locked(&sna->render);
sna_vertex_wait__locked(&sna->render);
_kgem_submit(&sna->kgem);
emit_state(sna, op);
goto start;
@ -2014,7 +2023,17 @@ gen6_render_composite(struct sna *sna,
}
tmp->done = gen6_render_composite_done;
kgem_set_mode(&sna->kgem, KGEM_RENDER, tmp->dst.bo);
if (!kgem_check_bo(&sna->kgem,
tmp->dst.bo, tmp->src.bo, tmp->mask.bo,
NULL)) {
kgem_submit(&sna->kgem);
if (!kgem_check_bo(&sna->kgem,
tmp->dst.bo, tmp->src.bo, tmp->mask.bo,
NULL))
goto cleanup_mask;
_kgem_set_mode(&sna->kgem, KGEM_RENDER);
}
gen6_emit_composite_state(sna, tmp);
gen6_align_vertex(sna, tmp);
@ -2654,6 +2673,13 @@ fallback:
assert(GEN6_SAMPLER(op->base.u.gen6.flags) == COPY_SAMPLER);
assert(GEN6_VERTEX(op->base.u.gen6.flags) == COPY_VERTEX);
kgem_set_mode(&sna->kgem, KGEM_RENDER, dst_bo);
if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
kgem_submit(&sna->kgem);
if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL))
goto fallback;
_kgem_set_mode(&sna->kgem, KGEM_RENDER);
}
gen6_emit_copy_state(sna, &op->base);
gen6_align_vertex(sna, &op->base);
@ -3149,7 +3175,13 @@ gen6_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
assert(GEN6_SAMPLER(tmp.u.gen6.flags) == FILL_SAMPLER);
assert(GEN6_VERTEX(tmp.u.gen6.flags) == FILL_VERTEX);
if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
kgem_submit(&sna->kgem);
if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
kgem_bo_destroy(&sna->kgem, tmp.src.bo);
return false;
}
}
gen6_emit_fill_state(sna, &tmp);
gen6_align_vertex(sna, &tmp);
@ -3173,6 +3205,7 @@ gen6_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
return true;
}
#endif
static void gen6_render_flush(struct sna *sna)
{
@ -3182,7 +3215,17 @@ static void gen6_render_flush(struct sna *sna)
assert(sna->render.vertex_offset == 0);
}
#endif
static void
gen6_render_context_switch(struct kgem *kgem,
int new_mode)
{
if (kgem->nbatch) {
DBG(("%s: from %d to %d\n", __FUNCTION__, kgem->mode, new_mode));
_kgem_submit(kgem);
}
kgem->ring = new_mode;
}
static void
gen6_render_retire(struct kgem *kgem)
@ -3200,6 +3243,23 @@ gen6_render_retire(struct kgem *kgem)
}
}
static void
gen6_render_expire(struct kgem *kgem)
{
struct sna *sna;
sna = container_of(kgem, struct sna, kgem);
if (sna->render.vbo && !sna->render.vertex_used) {
DBG(("%s: discarding vbo handle=%d\n", __FUNCTION__, sna->render.vbo->handle));
kgem_bo_destroy(kgem, sna->render.vbo);
assert(!sna->render.active);
sna->render.vbo = NULL;
sna->render.vertices = sna->render.vertex_data;
sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
sna->render.vertex_used = 0;
sna->render.vertex_index = 0;
}
}
static void gen6_render_reset(struct sna *sna)
{
@ -3319,8 +3379,9 @@ bool gen6_render_init(struct sna *sna)
if (!gen6_render_setup(sna))
return false;
// sna->kgem.context_switch = gen6_render_context_switch;
sna->kgem.context_switch = gen6_render_context_switch;
sna->kgem.retire = gen6_render_retire;
sna->kgem.expire = gen6_render_expire;
// sna->render.composite = gen6_render_composite;
// sna->render.video = gen6_render_video;
@ -3445,3 +3506,90 @@ int gen4_vertex_finish(struct sna *sna)
return sna->render.vertex_size - sna->render.vertex_used;
}
void gen4_vertex_close(struct sna *sna)
{
struct kgem_bo *bo, *free_bo = NULL;
unsigned int i, delta = 0;
assert(sna->render.vertex_offset == 0);
if (!sna->render.vb_id)
return;
DBG(("%s: used=%d, vbo active? %d, vb=%x, nreloc=%d\n",
__FUNCTION__, sna->render.vertex_used, sna->render.vbo ? sna->render.vbo->handle : 0,
sna->render.vb_id, sna->render.nvertex_reloc));
assert(!sna->render.active);
bo = sna->render.vbo;
if (bo) {
if (sna->render.vertex_size - sna->render.vertex_used < 64) {
DBG(("%s: discarding vbo (full), handle=%d\n", __FUNCTION__, sna->render.vbo->handle));
sna->render.vbo = NULL;
sna->render.vertices = sna->render.vertex_data;
sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
free_bo = bo;
} else if (IS_CPU_MAP(bo->map) && !sna->kgem.has_llc) {
DBG(("%s: converting CPU map to GTT\n", __FUNCTION__));
sna->render.vertices =
kgem_bo_map__gtt(&sna->kgem, sna->render.vbo);
if (sna->render.vertices == NULL) {
sna->render.vbo = NULL;
sna->render.vertices = sna->render.vertex_data;
sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
free_bo = bo;
}
}
} else {
if (sna->kgem.nbatch + sna->render.vertex_used <= sna->kgem.surface) {
DBG(("%s: copy to batch: %d @ %d\n", __FUNCTION__,
sna->render.vertex_used, sna->kgem.nbatch));
memcpy(sna->kgem.batch + sna->kgem.nbatch,
sna->render.vertex_data,
sna->render.vertex_used * 4);
delta = sna->kgem.nbatch * 4;
bo = NULL;
sna->kgem.nbatch += sna->render.vertex_used;
} else {
bo = kgem_create_linear(&sna->kgem,
4*sna->render.vertex_used,
CREATE_NO_THROTTLE);
if (bo && !kgem_bo_write(&sna->kgem, bo,
sna->render.vertex_data,
4*sna->render.vertex_used)) {
kgem_bo_destroy(&sna->kgem, bo);
bo = NULL;
}
DBG(("%s: new vbo: %d\n", __FUNCTION__,
sna->render.vertex_used));
free_bo = bo;
}
}
assert(sna->render.nvertex_reloc);
for (i = 0; i < sna->render.nvertex_reloc; i++) {
DBG(("%s: reloc[%d] = %d\n", __FUNCTION__,
i, sna->render.vertex_reloc[i]));
sna->kgem.batch[sna->render.vertex_reloc[i]] =
kgem_add_reloc(&sna->kgem,
sna->render.vertex_reloc[i], bo,
I915_GEM_DOMAIN_VERTEX << 16,
delta);
}
sna->render.nvertex_reloc = 0;
sna->render.vb_id = 0;
if (sna->render.vbo == NULL) {
assert(!sna->render.active);
sna->render.vertex_used = 0;
sna->render.vertex_index = 0;
assert(sna->render.vertices == sna->render.vertex_data);
assert(sna->render.vertex_size == ARRAY_SIZE(sna->render.vertex_data));
}
if (free_bo)
kgem_bo_destroy(&sna->kgem, free_bo);
}

View File

@ -218,13 +218,13 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_HWS_ADDR
#define DRM_IOCTL_I915_GEM_INIT
#define DRM_IOCTL_I915_GEM_EXECBUFFER
#define DRM_IOCTL_I915_GEM_EXECBUFFER2
#define DRM_IOCTL_I915_GEM_EXECBUFFER2 SRV_I915_GEM_EXECBUFFER2
#define DRM_IOCTL_I915_GEM_PIN SRV_I915_GEM_PIN
#define DRM_IOCTL_I915_GEM_UNPIN
#define DRM_IOCTL_I915_GEM_BUSY SRV_I915_GEM_BUSY
#define DRM_IOCTL_I915_GEM_SET_CACHEING SRV_I915_GEM_SET_CACHEING
#define DRM_IOCTL_I915_GEM_GET_CACHEING
#define DRM_IOCTL_I915_GEM_THROTTLE
#define DRM_IOCTL_I915_GEM_THROTTLE SRV_I915_GEM_THROTTLE
#define DRM_IOCTL_I915_GEM_ENTERVT
#define DRM_IOCTL_I915_GEM_LEAVEVT
#define DRM_IOCTL_I915_GEM_CREATE SRV_I915_GEM_CREATE

View File

@ -108,6 +108,15 @@ search_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags);
#define LOCAL_I915_EXEC_IS_PINNED (1<<10)
#define LOCAL_I915_EXEC_NO_RELOC (1<<11)
#define LOCAL_I915_EXEC_HANDLE_LUT (1<<12)
struct local_i915_gem_userptr {
uint64_t user_ptr;
uint32_t user_size;
uint32_t flags;
#define I915_USERPTR_READ_ONLY (1<<0)
#define I915_USERPTR_UNSYNCHRONIZED (1<<31)
uint32_t handle;
};
#define UNCACHED 0
#define SNOOPED 1
@ -118,6 +127,13 @@ struct local_i915_gem_cacheing {
#define LOCAL_IOCTL_I915_GEM_SET_CACHEING SRV_I915_GEM_SET_CACHEING
struct local_fbinfo {
int width;
int height;
int pitch;
int tiling;
};
struct kgem_buffer {
struct kgem_bo base;
void *mem;
@ -189,7 +205,7 @@ static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
ret = ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
*/
return ret == 0;
return false;//ret == 0;
}
static bool gem_set_cacheing(int fd, uint32_t handle, int cacheing)
@ -260,19 +276,19 @@ retry_gtt:
retry_mmap:
// ptr = mmap(0, bytes(bo), PROT_READ | PROT_WRITE, MAP_SHARED,
// kgem->fd, mmap_arg.offset);
if (ptr == 0) {
// if (ptr == 0) {
printf("%s: failed to mmap %d, %d bytes, into GTT domain: %d\n",
__FUNCTION__, bo->handle, bytes(bo), 0);
if (__kgem_throttle_retire(kgem, 0))
goto retry_mmap;
// if (__kgem_throttle_retire(kgem, 0))
// goto retry_mmap;
if (kgem->need_expire) {
kgem_cleanup_cache(kgem);
goto retry_mmap;
}
// if (kgem->need_expire) {
// kgem_cleanup_cache(kgem);
// goto retry_mmap;
// }
ptr = NULL;
}
// }
return ptr;
}
@ -639,10 +655,10 @@ static bool test_has_semaphores_enabled(struct kgem *kgem)
static bool __kgem_throttle(struct kgem *kgem)
{
// if (drmIoctl(kgem->fd, DRM_IOCTL_I915_GEM_THROTTLE, NULL) == 0)
if (drmIoctl(kgem->fd, DRM_IOCTL_I915_GEM_THROTTLE, NULL) == 0)
return false;
// return errno == EIO;
return errno == EIO;
}
static bool is_hw_supported(struct kgem *kgem,
@ -1073,7 +1089,138 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
kgem->batch_flags_base |= LOCAL_I915_EXEC_HANDLE_LUT;
if (kgem->has_pinned_batches)
kgem->batch_flags_base |= LOCAL_I915_EXEC_IS_PINNED;
}
/* XXX hopefully a good approximation */
static uint32_t kgem_get_unique_id(struct kgem *kgem)
{
uint32_t id;
id = ++kgem->unique_id;
if (id == 0)
id = ++kgem->unique_id;
return id;
}
inline static uint32_t kgem_pitch_alignment(struct kgem *kgem, unsigned flags)
{
if (flags & CREATE_PRIME)
return 256;
if (flags & CREATE_SCANOUT)
return 64;
return kgem->min_alignment;
}
static uint32_t kgem_untiled_pitch(struct kgem *kgem,
uint32_t width, uint32_t bpp,
unsigned flags)
{
width = ALIGN(width, 2) * bpp >> 3;
return ALIGN(width, kgem_pitch_alignment(kgem, flags));
}
static uint32_t kgem_surface_size(struct kgem *kgem,
bool relaxed_fencing,
unsigned flags,
uint32_t width,
uint32_t height,
uint32_t bpp,
uint32_t tiling,
uint32_t *pitch)
{
uint32_t tile_width, tile_height;
uint32_t size;
assert(width <= MAXSHORT);
assert(height <= MAXSHORT);
if (kgem->gen <= 030) {
if (tiling) {
if (kgem->gen < 030) {
tile_width = 128;
tile_height = 32;
} else {
tile_width = 512;
tile_height = 16;
}
} else {
tile_width = 2 * bpp >> 3;
tile_width = ALIGN(tile_width,
kgem_pitch_alignment(kgem, flags));
tile_height = 2;
}
} else switch (tiling) {
default:
case I915_TILING_NONE:
tile_width = 2 * bpp >> 3;
tile_width = ALIGN(tile_width,
kgem_pitch_alignment(kgem, flags));
tile_height = 2;
break;
/* XXX align to an even tile row */
case I915_TILING_X:
tile_width = 512;
tile_height = 16;
break;
case I915_TILING_Y:
tile_width = 128;
tile_height = 64;
break;
}
*pitch = ALIGN(width * bpp / 8, tile_width);
height = ALIGN(height, tile_height);
if (kgem->gen >= 040)
return PAGE_ALIGN(*pitch * height);
/* If it is too wide for the blitter, don't even bother. */
if (tiling != I915_TILING_NONE) {
if (*pitch > 8192)
return 0;
for (size = tile_width; size < *pitch; size <<= 1)
;
*pitch = size;
} else {
if (*pitch >= 32768)
return 0;
}
size = *pitch * height;
if (relaxed_fencing || tiling == I915_TILING_NONE)
return PAGE_ALIGN(size);
/* We need to allocate a pot fence region for a tiled buffer. */
if (kgem->gen < 030)
tile_width = 512 * 1024;
else
tile_width = 1024 * 1024;
while (tile_width < size)
tile_width *= 2;
return tile_width;
}
static uint32_t kgem_aligned_height(struct kgem *kgem,
uint32_t height, uint32_t tiling)
{
uint32_t tile_height;
if (kgem->gen <= 030) {
tile_height = tiling ? kgem->gen < 030 ? 32 : 16 : 1;
} else switch (tiling) {
/* XXX align to an even tile row */
default:
case I915_TILING_NONE:
tile_height = 1;
break;
case I915_TILING_X:
tile_height = 16;
break;
case I915_TILING_Y:
tile_height = 64;
break;
}
return ALIGN(height, tile_height);
}
static struct drm_i915_gem_exec_object2 *
@ -1763,11 +1910,27 @@ bool kgem_retire(struct kgem *kgem)
return retired;
}
bool __kgem_ring_is_idle(struct kgem *kgem, int ring)
{
struct kgem_request *rq;
assert(!list_is_empty(&kgem->requests[ring]));
rq = list_last_entry(&kgem->requests[ring],
struct kgem_request, list);
if (__kgem_busy(kgem, rq->bo->handle)) {
DBG(("%s: last requests handle=%d still busy\n",
__FUNCTION__, rq->bo->handle));
return false;
}
DBG(("%s: ring=%d idle (handle=%d)\n",
__FUNCTION__, ring, rq->bo->handle));
kgem_retire__requests_ring(kgem, ring);
assert(list_is_empty(&kgem->requests[ring]));
return true;
}
static void kgem_commit(struct kgem *kgem)
{
@ -2328,15 +2491,15 @@ void _kgem_submit(struct kgem *kgem)
// ret = drmIoctl(kgem->fd,
// DRM_IOCTL_I915_GEM_EXECBUFFER2,
// &execbuf);
// while (ret == -1 && errno == EBUSY && retry--) {
// __kgem_throttle(kgem);
// ret = drmIoctl(kgem->fd,
// DRM_IOCTL_I915_GEM_EXECBUFFER2,
// &execbuf);
// }
ret = drmIoctl(kgem->fd,
DRM_IOCTL_I915_GEM_EXECBUFFER2,
&execbuf);
while (ret == -1 && errno == EBUSY && retry--) {
__kgem_throttle(kgem);
ret = drmIoctl(kgem->fd,
DRM_IOCTL_I915_GEM_EXECBUFFER2,
&execbuf);
}
if (DEBUG_SYNC && ret == 0) {
struct drm_i915_gem_set_domain set_domain;
@ -2898,8 +3061,6 @@ inline int kgem_bo_fenced_size(struct kgem *kgem, struct kgem_bo *bo)
return size;
}
#if 0
struct kgem_bo *kgem_create_2d(struct kgem *kgem,
int width,
int height,
@ -3379,6 +3540,7 @@ create:
return bo;
}
#if 0
struct kgem_bo *kgem_create_cpu_2d(struct kgem *kgem,
int width,
int height,
@ -3497,11 +3659,80 @@ void _kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
__kgem_bo_destroy(kgem, bo);
}
void __kgem_flush(struct kgem *kgem, struct kgem_bo *bo)
{
assert(bo->rq);
assert(bo->exec == NULL);
assert(bo->needs_flush);
/* The kernel will emit a flush *and* update its own flushing lists. */
if (!__kgem_busy(kgem, bo->handle))
__kgem_bo_clear_busy(bo);
DBG(("%s: handle=%d, busy?=%d\n",
__FUNCTION__, bo->handle, bo->rq != NULL));
}
inline static bool needs_semaphore(struct kgem *kgem, struct kgem_bo *bo)
{
return kgem->nreloc && bo->rq && RQ_RING(bo->rq) != kgem->ring;
}
bool kgem_check_bo(struct kgem *kgem, ...)
{
va_list ap;
struct kgem_bo *bo;
int num_exec = 0;
int num_pages = 0;
bool flush = false;
va_start(ap, kgem);
while ((bo = va_arg(ap, struct kgem_bo *))) {
while (bo->proxy)
bo = bo->proxy;
if (bo->exec)
continue;
if (needs_semaphore(kgem, bo))
return false;
num_pages += num_pages(bo);
num_exec++;
flush |= bo->flush;
}
va_end(ap);
DBG(("%s: num_pages=+%d, num_exec=+%d\n",
__FUNCTION__, num_pages, num_exec));
if (!num_pages)
return true;
if (kgem_flush(kgem, flush))
return false;
if (kgem->aperture > kgem->aperture_low &&
kgem_ring_is_idle(kgem, kgem->ring)) {
DBG(("%s: current aperture usage (%d) is greater than low water mark (%d)\n",
__FUNCTION__, kgem->aperture, kgem->aperture_low));
return false;
}
if (num_pages + kgem->aperture > kgem->aperture_high) {
DBG(("%s: final aperture usage (%d) is greater than high water mark (%d)\n",
__FUNCTION__, num_pages + kgem->aperture, kgem->aperture_high));
return false;
}
if (kgem->nexec + num_exec >= KGEM_EXEC_SIZE(kgem)) {
DBG(("%s: out of exec slots (%d + %d / %d)\n", __FUNCTION__,
kgem->nexec, num_exec, KGEM_EXEC_SIZE(kgem)));
return false;
}
return true;
}
@ -3545,6 +3776,9 @@ uint32_t kgem_add_reloc(struct kgem *kgem,
assert((read_write_domain & 0x7fff) == 0 || bo != NULL);
// if( bo != NULL && bo->handle == -1)
// return 0;
index = kgem->nreloc++;
assert(index < ARRAY_SIZE(kgem->reloc));
kgem->reloc[index].offset = pos * sizeof(kgem->batch[0]);
@ -3851,6 +4085,42 @@ void kgem_clear_dirty(struct kgem *kgem)
}
}
struct kgem_bo *kgem_create_proxy(struct kgem *kgem,
struct kgem_bo *target,
int offset, int length)
{
struct kgem_bo *bo;
DBG(("%s: target handle=%d [proxy? %d], offset=%d, length=%d, io=%d\n",
__FUNCTION__, target->handle, target->proxy ? target->proxy->delta : -1,
offset, length, target->io));
bo = __kgem_bo_alloc(target->handle, length);
if (bo == NULL)
return NULL;
bo->unique_id = kgem_get_unique_id(kgem);
bo->reusable = false;
bo->size.bytes = length;
bo->io = target->io && target->proxy == NULL;
bo->dirty = target->dirty;
bo->tiling = target->tiling;
bo->pitch = target->pitch;
assert(!bo->scanout);
bo->proxy = kgem_bo_reference(target);
bo->delta = offset;
if (target->exec) {
list_move_tail(&bo->request, &kgem->next_request->buffers);
bo->exec = &_kgem_dummy_exec;
}
bo->rq = target->rq;
return bo;
}
uint32_t kgem_bo_get_binding(struct kgem_bo *bo, uint32_t format)
{
struct kgem_bo_binding *b;
@ -3889,5 +4159,37 @@ void kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset)
}
int kgem_init_fb(struct kgem *kgem, struct sna_fb *fb)
{
struct kgem_bo *bo;
size_t size;
int ret;
ret = drmIoctl(kgem->fd, SRV_FBINFO, fb);
if( ret != 0 )
return 0;
size = fb->pitch * fb->height / PAGE_SIZE;
bo = __kgem_bo_alloc(-2, size);
if (!bo) {
return 0;
}
bo->domain = DOMAIN_GTT;
bo->unique_id = kgem_get_unique_id(kgem);
bo->pitch = fb->pitch;
bo->tiling = I915_TILING_NONE;
bo->scanout = 1;
fb->fb_bo = bo;
printf("fb width %d height %d pitch %d bo %p\n",
fb->width, fb->height, fb->pitch, fb->fb_bo);
return 1;
};

View File

@ -28,7 +28,7 @@
#ifndef KGEM_H
#define KGEM_H
#define HAS_DEBUG_FULL 1
#define HAS_DEBUG_FULL 0
#include <stdint.h>
#include <stdbool.h>

View File

@ -5,6 +5,10 @@
#include "sna.h"
#include <pixlib2.h>
static struct sna_fb sna_fb;
typedef struct __attribute__((packed))
{
unsigned handle;
@ -64,7 +68,7 @@ void no_render_init(struct sna *sna)
// render->clear = no_render_clear;
render->reset = no_render_reset;
render->flush = no_render_flush;
// render->flush = no_render_flush;
// render->fini = no_render_fini;
// sna->kgem.context_switch = no_render_context_switch;
@ -129,24 +133,9 @@ bool sna_accel_init(struct sna *sna)
// return false;
sna_device = sna;
#if 0
{
struct kgem_bo *screen_bo;
bitmap_t screen;
screen.pitch = 1024*4;
screen.gaddr = 0;
screen.width = 1024;
screen.height = 768;
screen.obj = (void*)-1;
screen_bo = create_bo(&screen);
sna->render.clear(sna, &screen, screen_bo);
}
#endif
return true;
return kgem_init_fb(&sna->kgem, &sna_fb);
}
int sna_init(uint32_t service)
@ -339,37 +328,69 @@ done:
#endif
int sna_blit_copy(uint32_t dst_bitmap, int dst_x, int dst_y,
int w, int h, uint32_t src_bitmap, int src_x, int src_y)
int sna_blit_copy(bitmap_t *src_bitmap, int dst_x, int dst_y,
int w, int h, int src_x, int src_y)
{
struct sna_copy_op copy;
struct kgem_bo src_bo, dst_bo;
struct _Pixmap src, dst;
struct kgem_bo *src_bo;
memset(&src_bo, 0, sizeof(src_bo));
memset(&dst_bo, 0, sizeof(dst_bo));
memset(&src, 0, sizeof(src));
memset(&dst, 0, sizeof(dst));
// src_bo.gaddr = src_bitmap->gaddr;
// src_bo.pitch = src_bitmap->pitch;
// src_bo.tiling = 0;
src.drawable.bitsPerPixel = 32;
src.drawable.width = src_bitmap->width;
src.drawable.height = src_bitmap->height;
// dst_bo.gaddr = dst_bitmap->gaddr;
// dst_bo.pitch = dst_bitmap->pitch;
// dst_bo.tiling = 0;
dst.drawable.bitsPerPixel = 32;
dst.drawable.width = sna_fb.width;
dst.drawable.height = sna_fb.height;
memset(&copy, 0, sizeof(copy));
sna_device->render.copy(sna_device, GXcopy, NULL, &src_bo, NULL, &dst_bo, &copy);
src_bo = (struct kgem_bo*)src_bitmap->handle;
if( sna_device->render.copy(sna_device, GXcopy,
&src, src_bo,
&dst, sna_fb.fb_bo, &copy) )
{
copy.blt(sna_device, &copy, src_x, src_y, w, h, dst_x, dst_y);
copy.done(sna_device, &copy);
}
kgem_submit(&sna_device->kgem);
// _kgem_submit(&sna_device->kgem, &execbuffer);
// __asm__ __volatile__("int3");
};
int sna_create_bitmap(bitmap_t *bitmap)
{
struct kgem_bo *bo;
bo = kgem_create_2d(&sna_device->kgem, bitmap->width, bitmap->height,
32,I915_TILING_NONE, CREATE_CPU_MAP);
if(bo == NULL)
goto err_1;
void *map = kgem_bo_map(&sna_device->kgem, bo);
if(map == NULL)
goto err_2;
bitmap->handle = (uint32_t)bo;
bitmap->pitch = bo->pitch;
bitmap->data = map;
return 0;
err_2:
kgem_bo_destroy(&sna_device->kgem, bo);
err_1:
return -1;
};
/*
int sna_blit_tex(bitmap_t *dst_bitmap, int dst_x, int dst_y,

View File

@ -44,7 +44,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <stdint.h>
#include <memory.h>
#include <malloc.h>
#include <errno.h>
#include "intel_driver.h"
#include "pciaccess.h"
@ -69,11 +69,13 @@ int drmIoctl(int fd, unsigned long request, void *arg);
#define SRV_I915_GEM_GET_APERTURE 26
#define SRV_I915_GEM_PWRITE 27
#define SRV_I915_GEM_BUSY 28
#define SRV_I915_GEM_SET_DOMAIN 29
#define SRV_I915_GEM_MMAP 30
#define SRV_I915_GEM_MMAP_GTT 31
#define SRV_I915_GEM_THROTTLE 32
#define SRV_FBINFO 33
#define SRV_I915_GEM_EXECBUFFER2 34
#define SRV_I915_GEM_MMAP_GTT 31
#define DRM_IOCTL_GEM_CLOSE SRV_DRM_GEM_CLOSE
@ -153,6 +155,15 @@ typedef struct _Pixmap {
} PixmapRec;
struct sna_fb
{
uint32_t width;
uint32_t height;
uint32_t pitch;
uint32_t tiling;
struct kgem_bo *fb_bo;
};
struct pixman_box16
{

View File

@ -471,7 +471,6 @@ unsigned sna_static_stream_compile_wm(struct sna *sna,
struct kgem_bo *sna_static_stream_fini(struct sna *sna,
struct sna_static_stream *stream);
/*
struct kgem_bo *
sna_render_get_solid(struct sna *sna,
uint32_t color);
@ -479,9 +478,6 @@ sna_render_get_solid(struct sna *sna,
void
sna_render_flush_solid(struct sna *sna);
struct kgem_bo *
sna_render_get_gradient(struct sna *sna,
PictGradient *pattern);
uint32_t sna_rgba_for_color(uint32_t color, int depth);
uint32_t sna_rgba_to_color(uint32_t rgba, uint32_t format);
@ -493,8 +489,6 @@ bool sna_get_rgba_from_pixel(uint32_t pixel,
uint32_t format);
bool sna_picture_is_solid(PicturePtr picture, uint32_t *color);
*/
void no_render_init(struct sna *sna);
bool gen2_render_init(struct sna *sna);
@ -683,8 +677,37 @@ bool
sna_composite_mask_is_opaque(PicturePtr mask);
#endif
void sna_vertex_init(struct sna *sna);
static inline void sna_vertex_lock(struct sna_render *r)
{
// pthread_mutex_lock(&r->lock);
}
static inline void sna_vertex_acquire__locked(struct sna_render *r)
{
r->active++;
}
static inline void sna_vertex_unlock(struct sna_render *r)
{
// pthread_mutex_unlock(&r->lock);
}
static inline void sna_vertex_release__locked(struct sna_render *r)
{
assert(r->active > 0);
--r->active;
// if (--r->active == 0)
// pthread_cond_signal(&r->wait);
}
static inline bool sna_vertex_wait__locked(struct sna_render *r)
{
bool was_active = r->active;
// while (r->active)
// pthread_cond_wait(&r->wait, &r->lock);
return was_active;
}
#endif /* SNA_RENDER_H */

View File

@ -0,0 +1,150 @@
#include <stdint.h>
#include <stdio.h>
static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
/* ecx is often an input as well as an output. */
asm volatile("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "0" (*eax), "2" (*ecx)
: "memory");
}
/* Some CPUID calls want 'count' to be placed in ecx */
static inline void cpuid_count(unsigned int op, int count,
unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
*eax = op;
*ecx = count;
native_cpuid(eax, ebx, ecx, edx);
}
enum _cache_type {
CACHE_TYPE_NULL = 0,
CACHE_TYPE_DATA = 1,
CACHE_TYPE_INST = 2,
CACHE_TYPE_UNIFIED = 3
};
union _cpuid4_leaf_eax {
struct {
enum _cache_type type:5;
unsigned int level:3;
unsigned int is_self_initializing:1;
unsigned int is_fully_associative:1;
unsigned int reserved:4;
unsigned int num_threads_sharing:12;
unsigned int num_cores_on_die:6;
} split;
uint32_t full;
};
union _cpuid4_leaf_ebx {
struct {
unsigned int coherency_line_size:12;
unsigned int physical_line_partition:10;
unsigned int ways_of_associativity:10;
} split;
uint32_t full;
};
union _cpuid4_leaf_ecx {
struct {
unsigned int number_of_sets:32;
} split;
uint32_t full;
};
struct _cpuid4_info_regs {
union _cpuid4_leaf_eax eax;
union _cpuid4_leaf_ebx ebx;
union _cpuid4_leaf_ecx ecx;
unsigned long size;
};
static int
cpuid4_cache_lookup_regs(int index,
struct _cpuid4_info_regs *this_leaf)
{
union _cpuid4_leaf_eax eax;
union _cpuid4_leaf_ebx ebx;
union _cpuid4_leaf_ecx ecx;
unsigned edx;
cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
if (eax.split.type == CACHE_TYPE_NULL)
return -1; /* better error ? */
this_leaf->eax = eax;
this_leaf->ebx = ebx;
this_leaf->ecx = ecx;
this_leaf->size = (ecx.split.number_of_sets + 1) *
(ebx.split.coherency_line_size + 1) *
(ebx.split.physical_line_partition + 1) *
(ebx.split.ways_of_associativity + 1);
return 0;
}
static int find_num_cache_leaves()
{
unsigned int eax, ebx, ecx, edx, op;
union _cpuid4_leaf_eax cache_eax;
int i = -1;
do {
++i;
/* Do cpuid(op) loop to find out num_cache_leaves */
cpuid_count(4, i, &eax, &ebx, &ecx, &edx);
cache_eax.full = eax;
} while (cache_eax.split.type != CACHE_TYPE_NULL);
return i;
};
unsigned int cpu_cache_size()
{
unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
unsigned int num_cache_leaves;
num_cache_leaves = find_num_cache_leaves();
for (i = 0; i < num_cache_leaves; i++)
{
struct _cpuid4_info_regs this_leaf;
int retval;
retval = cpuid4_cache_lookup_regs(i, &this_leaf);
if (retval >= 0) {
switch (this_leaf.eax.split.level)
{
case 1:
if (this_leaf.eax.split.type == CACHE_TYPE_DATA)
new_l1d = this_leaf.size;
else if (this_leaf.eax.split.type == CACHE_TYPE_INST)
new_l1i = this_leaf.size;
break;
case 2:
new_l2 = this_leaf.size;
break;
case 3:
new_l3 = this_leaf.size;
break;
default:
break;
}
}
}
printf("l2 cache %d l3 cache %d\n", new_l2, new_l3);
return new_l3 != 0 ? new_l3 : new_l2;
};

View File

@ -1547,12 +1547,15 @@ int i915_driver_unload(struct drm_device *dev)
return 0;
}
#endif
int i915_driver_open(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv;
DRM_DEBUG_DRIVER("\n");
ENTER();
file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
return -ENOMEM;
@ -1564,9 +1567,11 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file)
idr_init(&file_priv->context_idr);
LEAVE();
return 0;
}
#if 0
/**
* i915_driver_lastclose - clean up after all DRM clients have exited
* @dev: DRM device

View File

@ -492,7 +492,7 @@ static struct drm_driver driver = {
// DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME,
// .load = i915_driver_load,
// .unload = i915_driver_unload,
// .open = i915_driver_open,
.open = i915_driver_open,
// .lastclose = i915_driver_lastclose,
// .preclose = i915_driver_preclose,
// .postclose = i915_driver_postclose,
@ -577,6 +577,12 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->driver = &driver;
if (dev->driver->open) {
ret = dev->driver->open(dev, priv);
if (ret < 0)
goto err_g4;
}
ret = i915_driver_load(dev, ent->driver_data );
if (ret)

View File

@ -37,6 +37,10 @@
extern int x86_clflush_size;
#define PROT_READ 0x1 /* page can be read */
#define PROT_WRITE 0x2 /* page can be written */
#define MAP_SHARED 0x01 /* Share changes */
#undef mb
#undef rmb
#undef wmb
@ -44,6 +48,10 @@ extern int x86_clflush_size;
#define rmb() asm volatile ("lfence")
#define wmb() asm volatile ("sfence")
unsigned long vm_mmap(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flag, unsigned long offset);
static inline void clflush(volatile void *__p)
{
asm volatile("clflush %0" : "+m" (*(volatile char*)__p));
@ -1296,8 +1304,8 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
if (obj == NULL)
return -ENOENT;
dbgprintf("%s offset %lld size %lld not supported\n",
args->offset, args->size);
dbgprintf("%s offset %lld size %lld\n",
__FUNCTION__, args->offset, args->size);
/* prime objects have no backing filp to GEM mmap
* pages from.
*/
@ -1306,17 +1314,16 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
// addr = vm_mmap(obj->filp, 0, args->size,
// PROT_READ | PROT_WRITE, MAP_SHARED,
// args->offset);
addr = vm_mmap(obj->filp, 0, args->size,
PROT_READ | PROT_WRITE, MAP_SHARED,
args->offset);
drm_gem_object_unreference_unlocked(obj);
// if (IS_ERR((void *)addr))
// return addr;
if (IS_ERR((void *)addr))
return addr;
args->addr_ptr = (uint64_t) addr;
return -EINVAL;
// return 0;
return 0;
}
@ -1444,8 +1451,8 @@ i915_gem_object_truncate(struct drm_i915_gem_object *obj)
// i915_gem_object_free_mmap_offset(obj);
// if (obj->base.filp == NULL)
// return;
if (obj->base.filp == NULL)
return;
/* Our goal here is to return as much of the memory as
* is possible back to the system as we are called from OOM.
@ -1491,7 +1498,7 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
page_cache_release(page);
// page_cache_release(page);
}
//DRM_DEBUG_KMS("%s release %d pages\n", __FUNCTION__, page_count);
obj->dirty = 0;
@ -1784,7 +1791,17 @@ i915_add_request(struct intel_ring_buffer *ring,
list_add_tail(&request->list, &ring->request_list);
request->file_priv = NULL;
if (file) {
struct drm_i915_file_private *file_priv = file->driver_priv;
spin_lock(&file_priv->mm.lock);
request->file_priv = file_priv;
list_add_tail(&request->client_list,
&file_priv->mm.request_list);
spin_unlock(&file_priv->mm.lock);
}
trace_i915_gem_request_add(ring, request->seqno);
ring->outstanding_lazy_request = 0;
if (!dev_priv->mm.suspended) {
@ -1805,8 +1822,21 @@ i915_add_request(struct intel_ring_buffer *ring,
return 0;
}
static inline void
i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
{
struct drm_i915_file_private *file_priv = request->file_priv;
if (!file_priv)
return;
spin_lock(&file_priv->mm.lock);
if (request->file_priv) {
list_del(&request->client_list);
request->file_priv = NULL;
}
spin_unlock(&file_priv->mm.lock);
}
static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
struct intel_ring_buffer *ring)
@ -1819,7 +1849,7 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
list);
list_del(&request->list);
// i915_gem_request_remove_from_client(request);
i915_gem_request_remove_from_client(request);
kfree(request);
}
@ -1887,6 +1917,8 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
{
uint32_t seqno;
ENTER();
if (list_empty(&ring->request_list))
return;
@ -1913,6 +1945,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
ring->last_retired_head = request->tail;
list_del(&request->list);
i915_gem_request_remove_from_client(request);
kfree(request);
}
@ -1939,6 +1972,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
}
WARN_ON(i915_verify_lists(ring->dev));
LEAVE();
}
void
@ -1961,6 +1995,8 @@ i915_gem_retire_work_handler(struct work_struct *work)
bool idle;
int i;
ENTER();
dev_priv = container_of(work, drm_i915_private_t,
mm.retire_work.work);
dev = dev_priv->dev;
@ -1990,6 +2026,8 @@ i915_gem_retire_work_handler(struct work_struct *work)
intel_mark_idle(dev);
mutex_unlock(&dev->struct_mutex);
LEAVE();
}
/**
@ -2127,6 +2165,9 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
int ret = 0;
if(obj == get_fb_obj())
return 0;
if (obj->gtt_space == NULL)
return 0;
@ -3105,7 +3146,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
return 0;
}
#if 0
/* Throttle our rendering by waiting until the ring has completed our requests
* emitted over 20 msec ago.
*
@ -3121,7 +3161,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_file_private *file_priv = file->driver_priv;
unsigned long recent_enough = GetTimerTics() - msecs_to_jiffies(20);
unsigned long recent_enough = GetTimerTicks() - msecs_to_jiffies(20);
struct drm_i915_gem_request *request;
struct intel_ring_buffer *ring = NULL;
u32 seqno = 0;
@ -3149,7 +3189,6 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
return ret;
}
#endif
int
i915_gem_object_pin(struct drm_i915_gem_object *obj,
@ -3162,7 +3201,6 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
return -EBUSY;
#if 0
if (obj->gtt_space != NULL) {
if ((alignment && obj->gtt_offset & (alignment - 1)) ||
(map_and_fenceable && !obj->map_and_fenceable)) {
@ -3178,7 +3216,6 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
return ret;
}
}
#endif
if (obj->gtt_space == NULL) {
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
@ -3342,7 +3379,6 @@ unlock:
return ret;
}
#if 0
int
i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
@ -3350,6 +3386,8 @@ i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
return i915_gem_ring_throttle(dev, file_priv);
}
#if 0
int
i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
@ -3545,7 +3583,7 @@ i915_gem_idle(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
/* Cancel the retire work handler, which should be idle now. */
// cancel_delayed_work_sync(&dev_priv->mm.retire_work);
cancel_delayed_work_sync(&dev_priv->mm.retire_work);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -23,5 +23,7 @@
#define trace_i915_reg_rw(a, b, c, d)
#define trace_i915_ring_wait_begin(a)
#define trace_i915_gem_object_pwrite(a, b, c)
#define trace_i915_gem_request_add(a, b)
#define trace_i915_gem_ring_dispatch(a, b, c);
#endif

View File

@ -6985,6 +6985,8 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj)
struct drm_device *dev = obj->base.dev;
struct drm_crtc *crtc;
ENTER();
if (!i915_powersave)
return;
@ -7002,6 +7004,8 @@ void intel_mark_fb_idle(struct drm_i915_gem_object *obj)
struct drm_device *dev = obj->base.dev;
struct drm_crtc *crtc;
ENTER();
if (!i915_powersave)
return;

View File

@ -43,6 +43,12 @@
#include <drm/i915_drm.h>
#include "i915_drv.h"
static struct drm_i915_gem_object *fb_obj;
struct drm_i915_gem_object *get_fb_obj()
{
return fb_obj;
};
struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
{
@ -144,6 +150,10 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
obj->gtt_space = &lfb_vm_node;
obj->gtt_offset = 0;
obj->pin_count = 2;
obj->cache_level = I915_CACHE_NONE;
obj->base.write_domain = 0;
obj->base.read_domains = I915_GEM_DOMAIN_GTT;
}
/***********************************************************************/
@ -182,7 +192,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
info->fix.smem_len = size;
info->screen_base = 0xFE000000;
info->screen_base = (void*) 0xFE000000;
info->screen_size = size;
// memset(info->screen_base, 0, size);
@ -200,6 +210,8 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
mutex_unlock(&dev->struct_mutex);
// vga_switcheroo_client_fb_set(dev->pdev, info);
fb_obj = obj;
return 0;
out_unpin:

View File

@ -624,6 +624,23 @@ cursor_t* __stdcall select_cursor_kms(cursor_t *cursor)
return old;
};
struct sna_fb
{
uint32_t width;
uint32_t height;
uint32_t pitch;
uint32_t tiling;
};
int i915_fbinfo(struct sna_fb *fb)
{
fb->width = os_display->width;
fb->height = os_display->height;
fb->pitch = os_display->pitch;
fb->tiling = 0;
return 0;
};
#ifdef __HWA__

View File

@ -70,8 +70,8 @@ u32_t drvEntry(int action, char *cmdline)
if(!dbg_open(log))
{
// strcpy(log, "/tmp1/1/i915.log");
strcpy(log, "/RD/1/DRIVERS/i915.log");
strcpy(log, "/tmp1/1/i915.log");
// strcpy(log, "/RD/1/DRIVERS/i915.log");
if(!dbg_open(log))
{
@ -132,6 +132,12 @@ u32_t drvEntry(int action, char *cmdline)
#define SRV_I915_GEM_PWRITE 27
#define SRV_I915_GEM_BUSY 28
#define SRV_I915_GEM_SET_DOMAIN 29
#define SRV_I915_GEM_MMAP 30
#define SRV_I915_GEM_THROTTLE 32
#define SRV_FBINFO 33
#define SRV_I915_GEM_EXECBUFFER2 34
#define check_input(size) \
@ -247,6 +253,22 @@ int _stdcall display_handler(ioctl_t *io)
retval = i915_gem_set_domain_ioctl(main_device, inp, file);
break;
case SRV_I915_GEM_THROTTLE:
retval = i915_gem_throttle_ioctl(main_device, inp, file);
break;
case SRV_I915_GEM_MMAP:
retval = i915_gem_mmap_ioctl(main_device, inp, file);
break;
case SRV_FBINFO:
retval = i915_fbinfo(inp);
break;
case SRV_I915_GEM_EXECBUFFER2:
retval = i915_gem_execbuffer2(main_device, inp, file);
break;
};
return retval;

View File

@ -1,3 +1,5 @@
#include <ddk.h>
#include <linux/mm.h>
#include <drm/drmP.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
@ -57,3 +59,39 @@ struct page *shmem_read_mapping_page_gfp(struct file *filep,
return page;
};
unsigned long vm_mmap(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flag, unsigned long offset)
{
char *mem, *ptr;
int i;
if (unlikely(offset + PAGE_ALIGN(len) < offset))
return -EINVAL;
if (unlikely(offset & ~PAGE_MASK))
return -EINVAL;
mem = UserAlloc(len);
if(unlikely(mem == NULL))
return -ENOMEM;
for(i = offset, ptr = mem; i < offset+len; i+= 4096, ptr+= 4096)
{
struct page *page;
page = shmem_read_mapping_page_gfp(file, i/PAGE_SIZE,0);
if (unlikely(IS_ERR(page)))
goto err;
MapPage(ptr, (addr_t)page, PG_SHARED|PG_UW);
}
return (unsigned long)mem;
err:
UserFree(mem);
return -ENOMEM;
};