Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

More VM.

  • Loading branch information...
commit 2b72f9addbb18df1c1a6cfabdec177d3388c39c6 1 parent a617d7b
@koriakin koriakin authored
View
5 pscnv/nouveau_drv.h
@@ -41,6 +41,7 @@
#include "pscnv_drm.h"
#include "nouveau_bios.h"
#include "pscnv_vram.h"
+#include "pscnv_vm.h"
struct nouveau_grctx;
#define MAX_NUM_DCB_ENTRIES 16
@@ -1254,6 +1255,8 @@ static inline uint32_t nv_rv32(struct pscnv_vo *vo,
struct drm_nouveau_private *dev_priv = vo->dev->dev_private;
uint32_t res;
uint64_t addr = vo->start + offset;
+ if (vo->map3 && dev_priv->barvm)
+ return ioread32_native(dev_priv->ramin + vo->map3->start - dev_priv->fb_size + offset);
spin_lock(&dev_priv->pramin_lock);
if (addr >> 16 != dev_priv->pramin_start) {
dev_priv->pramin_start = addr >> 16;
@@ -1269,6 +1272,8 @@ static inline void nv_wv32(struct pscnv_vo *vo,
{
struct drm_nouveau_private *dev_priv = vo->dev->dev_private;
uint64_t addr = vo->start + offset;
+ if (vo->map3 && dev_priv->barvm)
+ return iowrite32_native(val, dev_priv->ramin + vo->map3->start - dev_priv->fb_size + offset);
spin_lock(&dev_priv->pramin_lock);
if (addr >> 16 != dev_priv->pramin_start) {
dev_priv->pramin_start = addr >> 16;
View
487 pscnv/pscnv_tree.h
@@ -0,0 +1,487 @@
+/*
+ * Originally sys/tree.h from FreeBSD. Changes:
+ * - SPLAY removed
+ * - name changed to avoid collisions
+ */
+
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PSCNV_TREE_H__
+#define __PSCNV_TREE_H__
+
+#define __unused __attribute__((__unused__))
+
+/* Macros that define a red-black tree */
+#define PSCNV_RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define PSCNV_RB_INITIALIZER(root) \
+ { NULL }
+
+#define PSCNV_RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define PSCNV_RB_BLACK 0
+#define PSCNV_RB_RED 1
+#define PSCNV_RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define PSCNV_RB_LEFT(elm, field) (elm)->field.rbe_left
+#define PSCNV_RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define PSCNV_RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define PSCNV_RB_COLOR(elm, field) (elm)->field.rbe_color
+#define PSCNV_RB_ROOT(head) (head)->rbh_root
+#define PSCNV_RB_EMPTY(head) (PSCNV_RB_ROOT(head) == NULL)
+
+#define PSCNV_RB_SET(elm, parent, field) do { \
+ PSCNV_RB_PARENT(elm, field) = parent; \
+ PSCNV_RB_LEFT(elm, field) = PSCNV_RB_RIGHT(elm, field) = NULL; \
+ PSCNV_RB_COLOR(elm, field) = PSCNV_RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#define PSCNV_RB_SET_BLACKRED(black, red, field) do { \
+ PSCNV_RB_COLOR(black, field) = PSCNV_RB_BLACK; \
+ PSCNV_RB_COLOR(red, field) = PSCNV_RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#ifndef PSCNV_RB_AUGMENT
+#define PSCNV_RB_AUGMENT(x) (void)(x)
+#endif
+
+#define PSCNV_RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = PSCNV_RB_RIGHT(elm, field); \
+ if ((PSCNV_RB_RIGHT(elm, field) = PSCNV_RB_LEFT(tmp, field)) != NULL) { \
+ PSCNV_RB_PARENT(PSCNV_RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ PSCNV_RB_AUGMENT(elm); \
+ if ((PSCNV_RB_PARENT(tmp, field) = PSCNV_RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == PSCNV_RB_LEFT(PSCNV_RB_PARENT(elm, field), field)) \
+ PSCNV_RB_LEFT(PSCNV_RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ PSCNV_RB_RIGHT(PSCNV_RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ PSCNV_RB_LEFT(tmp, field) = (elm); \
+ PSCNV_RB_PARENT(elm, field) = (tmp); \
+ PSCNV_RB_AUGMENT(tmp); \
+ if ((PSCNV_RB_PARENT(tmp, field))) \
+ PSCNV_RB_AUGMENT(PSCNV_RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+#define PSCNV_RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = PSCNV_RB_LEFT(elm, field); \
+ if ((PSCNV_RB_LEFT(elm, field) = PSCNV_RB_RIGHT(tmp, field)) != NULL) { \
+ PSCNV_RB_PARENT(PSCNV_RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ PSCNV_RB_AUGMENT(elm); \
+ if ((PSCNV_RB_PARENT(tmp, field) = PSCNV_RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == PSCNV_RB_LEFT(PSCNV_RB_PARENT(elm, field), field)) \
+ PSCNV_RB_LEFT(PSCNV_RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ PSCNV_RB_RIGHT(PSCNV_RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ PSCNV_RB_RIGHT(tmp, field) = (elm); \
+ PSCNV_RB_PARENT(elm, field) = (tmp); \
+ PSCNV_RB_AUGMENT(tmp); \
+ if ((PSCNV_RB_PARENT(tmp, field))) \
+ PSCNV_RB_AUGMENT(PSCNV_RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+#define PSCNV_RB_PROTOTYPE(name, type, field, cmp) \
+ PSCNV_RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define PSCNV_RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ PSCNV_RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
+#define PSCNV_RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+attr void name##_PSCNV_RB_INSERT_COLOR(struct name *, struct type *); \
+attr void name##_PSCNV_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+attr struct type *name##_PSCNV_RB_REMOVE(struct name *, struct type *); \
+attr struct type *name##_PSCNV_RB_INSERT(struct name *, struct type *); \
+attr struct type *name##_PSCNV_RB_FIND(struct name *, struct type *); \
+attr struct type *name##_PSCNV_RB_NFIND(struct name *, struct type *); \
+attr struct type *name##_PSCNV_RB_NEXT(struct type *); \
+attr struct type *name##_PSCNV_RB_PREV(struct type *); \
+attr struct type *name##_PSCNV_RB_MINMAX(struct name *, int); \
+ \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define PSCNV_RB_GENERATE(name, type, field, cmp) \
+ PSCNV_RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define PSCNV_RB_GENERATE_STATIC(name, type, field, cmp) \
+ PSCNV_RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
+#define PSCNV_RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+attr void \
+name##_PSCNV_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = PSCNV_RB_PARENT(elm, field)) != NULL && \
+ PSCNV_RB_COLOR(parent, field) == PSCNV_RB_RED) { \
+ gparent = PSCNV_RB_PARENT(parent, field); \
+ if (parent == PSCNV_RB_LEFT(gparent, field)) { \
+ tmp = PSCNV_RB_RIGHT(gparent, field); \
+ if (tmp && PSCNV_RB_COLOR(tmp, field) == PSCNV_RB_RED) { \
+ PSCNV_RB_COLOR(tmp, field) = PSCNV_RB_BLACK; \
+ PSCNV_RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (PSCNV_RB_RIGHT(parent, field) == elm) { \
+ PSCNV_RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ PSCNV_RB_SET_BLACKRED(parent, gparent, field); \
+ PSCNV_RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = PSCNV_RB_LEFT(gparent, field); \
+ if (tmp && PSCNV_RB_COLOR(tmp, field) == PSCNV_RB_RED) { \
+ PSCNV_RB_COLOR(tmp, field) = PSCNV_RB_BLACK; \
+ PSCNV_RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (PSCNV_RB_LEFT(parent, field) == elm) { \
+ PSCNV_RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ PSCNV_RB_SET_BLACKRED(parent, gparent, field); \
+ PSCNV_RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ PSCNV_RB_COLOR(head->rbh_root, field) = PSCNV_RB_BLACK; \
+} \
+ \
+attr void \
+name##_PSCNV_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || PSCNV_RB_COLOR(elm, field) == PSCNV_RB_BLACK) && \
+ elm != PSCNV_RB_ROOT(head)) { \
+ if (PSCNV_RB_LEFT(parent, field) == elm) { \
+ tmp = PSCNV_RB_RIGHT(parent, field); \
+ if (PSCNV_RB_COLOR(tmp, field) == PSCNV_RB_RED) { \
+ PSCNV_RB_SET_BLACKRED(tmp, parent, field); \
+ PSCNV_RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = PSCNV_RB_RIGHT(parent, field); \
+ } \
+ if ((PSCNV_RB_LEFT(tmp, field) == NULL || \
+ PSCNV_RB_COLOR(PSCNV_RB_LEFT(tmp, field), field) == PSCNV_RB_BLACK) &&\
+ (PSCNV_RB_RIGHT(tmp, field) == NULL || \
+ PSCNV_RB_COLOR(PSCNV_RB_RIGHT(tmp, field), field) == PSCNV_RB_BLACK)) {\
+ PSCNV_RB_COLOR(tmp, field) = PSCNV_RB_RED; \
+ elm = parent; \
+ parent = PSCNV_RB_PARENT(elm, field); \
+ } else { \
+ if (PSCNV_RB_RIGHT(tmp, field) == NULL || \
+ PSCNV_RB_COLOR(PSCNV_RB_RIGHT(tmp, field), field) == PSCNV_RB_BLACK) {\
+ struct type *oleft; \
+ if ((oleft = PSCNV_RB_LEFT(tmp, field)) \
+ != NULL) \
+ PSCNV_RB_COLOR(oleft, field) = PSCNV_RB_BLACK;\
+ PSCNV_RB_COLOR(tmp, field) = PSCNV_RB_RED; \
+ PSCNV_RB_ROTATE_RIGHT(head, tmp, oleft, field);\
+ tmp = PSCNV_RB_RIGHT(parent, field); \
+ } \
+ PSCNV_RB_COLOR(tmp, field) = PSCNV_RB_COLOR(parent, field);\
+ PSCNV_RB_COLOR(parent, field) = PSCNV_RB_BLACK; \
+ if (PSCNV_RB_RIGHT(tmp, field)) \
+ PSCNV_RB_COLOR(PSCNV_RB_RIGHT(tmp, field), field) = PSCNV_RB_BLACK;\
+ PSCNV_RB_ROTATE_LEFT(head, parent, tmp, field);\
+ elm = PSCNV_RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = PSCNV_RB_LEFT(parent, field); \
+ if (PSCNV_RB_COLOR(tmp, field) == PSCNV_RB_RED) { \
+ PSCNV_RB_SET_BLACKRED(tmp, parent, field); \
+ PSCNV_RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = PSCNV_RB_LEFT(parent, field); \
+ } \
+ if ((PSCNV_RB_LEFT(tmp, field) == NULL || \
+ PSCNV_RB_COLOR(PSCNV_RB_LEFT(tmp, field), field) == PSCNV_RB_BLACK) &&\
+ (PSCNV_RB_RIGHT(tmp, field) == NULL || \
+ PSCNV_RB_COLOR(PSCNV_RB_RIGHT(tmp, field), field) == PSCNV_RB_BLACK)) {\
+ PSCNV_RB_COLOR(tmp, field) = PSCNV_RB_RED; \
+ elm = parent; \
+ parent = PSCNV_RB_PARENT(elm, field); \
+ } else { \
+ if (PSCNV_RB_LEFT(tmp, field) == NULL || \
+ PSCNV_RB_COLOR(PSCNV_RB_LEFT(tmp, field), field) == PSCNV_RB_BLACK) {\
+ struct type *oright; \
+ if ((oright = PSCNV_RB_RIGHT(tmp, field)) \
+ != NULL) \
+ PSCNV_RB_COLOR(oright, field) = PSCNV_RB_BLACK;\
+ PSCNV_RB_COLOR(tmp, field) = PSCNV_RB_RED; \
+ PSCNV_RB_ROTATE_LEFT(head, tmp, oright, field);\
+ tmp = PSCNV_RB_LEFT(parent, field); \
+ } \
+ PSCNV_RB_COLOR(tmp, field) = PSCNV_RB_COLOR(parent, field);\
+ PSCNV_RB_COLOR(parent, field) = PSCNV_RB_BLACK; \
+ if (PSCNV_RB_LEFT(tmp, field)) \
+ PSCNV_RB_COLOR(PSCNV_RB_LEFT(tmp, field), field) = PSCNV_RB_BLACK;\
+ PSCNV_RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ elm = PSCNV_RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ PSCNV_RB_COLOR(elm, field) = PSCNV_RB_BLACK; \
+} \
+ \
+attr struct type * \
+name##_PSCNV_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (PSCNV_RB_LEFT(elm, field) == NULL) \
+ child = PSCNV_RB_RIGHT(elm, field); \
+ else if (PSCNV_RB_RIGHT(elm, field) == NULL) \
+ child = PSCNV_RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = PSCNV_RB_RIGHT(elm, field); \
+ while ((left = PSCNV_RB_LEFT(elm, field)) != NULL) \
+ elm = left; \
+ child = PSCNV_RB_RIGHT(elm, field); \
+ parent = PSCNV_RB_PARENT(elm, field); \
+ color = PSCNV_RB_COLOR(elm, field); \
+ if (child) \
+ PSCNV_RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (PSCNV_RB_LEFT(parent, field) == elm) \
+ PSCNV_RB_LEFT(parent, field) = child; \
+ else \
+ PSCNV_RB_RIGHT(parent, field) = child; \
+ PSCNV_RB_AUGMENT(parent); \
+ } else \
+ PSCNV_RB_ROOT(head) = child; \
+ if (PSCNV_RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (PSCNV_RB_PARENT(old, field)) { \
+ if (PSCNV_RB_LEFT(PSCNV_RB_PARENT(old, field), field) == old)\
+ PSCNV_RB_LEFT(PSCNV_RB_PARENT(old, field), field) = elm;\
+ else \
+ PSCNV_RB_RIGHT(PSCNV_RB_PARENT(old, field), field) = elm;\
+ PSCNV_RB_AUGMENT(PSCNV_RB_PARENT(old, field)); \
+ } else \
+ PSCNV_RB_ROOT(head) = elm; \
+ PSCNV_RB_PARENT(PSCNV_RB_LEFT(old, field), field) = elm; \
+ if (PSCNV_RB_RIGHT(old, field)) \
+ PSCNV_RB_PARENT(PSCNV_RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ PSCNV_RB_AUGMENT(left); \
+ } while ((left = PSCNV_RB_PARENT(left, field)) != NULL); \
+ } \
+ goto color; \
+ } \
+ parent = PSCNV_RB_PARENT(elm, field); \
+ color = PSCNV_RB_COLOR(elm, field); \
+ if (child) \
+ PSCNV_RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (PSCNV_RB_LEFT(parent, field) == elm) \
+ PSCNV_RB_LEFT(parent, field) = child; \
+ else \
+ PSCNV_RB_RIGHT(parent, field) = child; \
+ PSCNV_RB_AUGMENT(parent); \
+ } else \
+ PSCNV_RB_ROOT(head) = child; \
+color: \
+ if (color == PSCNV_RB_BLACK) \
+ name##_PSCNV_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+ \
+/* Inserts a node into the RB tree */ \
+attr struct type * \
+name##_PSCNV_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = PSCNV_RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = PSCNV_RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = PSCNV_RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ PSCNV_RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ PSCNV_RB_LEFT(parent, field) = elm; \
+ else \
+ PSCNV_RB_RIGHT(parent, field) = elm; \
+ PSCNV_RB_AUGMENT(parent); \
+ } else \
+ PSCNV_RB_ROOT(head) = elm; \
+ name##_PSCNV_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+} \
+ \
+/* Finds the node with the same key as elm */ \
+attr struct type * \
+name##_PSCNV_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = PSCNV_RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = PSCNV_RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = PSCNV_RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+} \
+ \
+/* Finds the first node greater than or equal to the search key */ \
+attr struct type * \
+name##_PSCNV_RB_NFIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = PSCNV_RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = PSCNV_RB_LEFT(tmp, field); \
+ } \
+ else if (comp > 0) \
+ tmp = PSCNV_RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_PSCNV_RB_NEXT(struct type *elm) \
+{ \
+ if (PSCNV_RB_RIGHT(elm, field)) { \
+ elm = PSCNV_RB_RIGHT(elm, field); \
+ while (PSCNV_RB_LEFT(elm, field)) \
+ elm = PSCNV_RB_LEFT(elm, field); \
+ } else { \
+ if (PSCNV_RB_PARENT(elm, field) && \
+ (elm == PSCNV_RB_LEFT(PSCNV_RB_PARENT(elm, field), field))) \
+ elm = PSCNV_RB_PARENT(elm, field); \
+ else { \
+ while (PSCNV_RB_PARENT(elm, field) && \
+ (elm == PSCNV_RB_RIGHT(PSCNV_RB_PARENT(elm, field), field)))\
+ elm = PSCNV_RB_PARENT(elm, field); \
+ elm = PSCNV_RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_PSCNV_RB_PREV(struct type *elm) \
+{ \
+ if (PSCNV_RB_LEFT(elm, field)) { \
+ elm = PSCNV_RB_LEFT(elm, field); \
+ while (PSCNV_RB_RIGHT(elm, field)) \
+ elm = PSCNV_RB_RIGHT(elm, field); \
+ } else { \
+ if (PSCNV_RB_PARENT(elm, field) && \
+ (elm == PSCNV_RB_RIGHT(PSCNV_RB_PARENT(elm, field), field))) \
+ elm = PSCNV_RB_PARENT(elm, field); \
+ else { \
+ while (PSCNV_RB_PARENT(elm, field) && \
+ (elm == PSCNV_RB_LEFT(PSCNV_RB_PARENT(elm, field), field)))\
+ elm = PSCNV_RB_PARENT(elm, field); \
+ elm = PSCNV_RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+attr struct type * \
+name##_PSCNV_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = PSCNV_RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = PSCNV_RB_LEFT(tmp, field); \
+ else \
+ tmp = PSCNV_RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define PSCNV_RB_NEGINF -1
+#define PSCNV_RB_INF 1
+
+#define PSCNV_RB_INSERT(name, x, y) name##_PSCNV_RB_INSERT(x, y)
+#define PSCNV_RB_REMOVE(name, x, y) name##_PSCNV_RB_REMOVE(x, y)
+#define PSCNV_RB_FIND(name, x, y) name##_PSCNV_RB_FIND(x, y)
+#define PSCNV_RB_NFIND(name, x, y) name##_PSCNV_RB_NFIND(x, y)
+#define PSCNV_RB_NEXT(name, x, y) name##_PSCNV_RB_NEXT(y)
+#define PSCNV_RB_PREV(name, x, y) name##_PSCNV_RB_PREV(y)
+#define PSCNV_RB_MIN(name, x) name##_PSCNV_RB_MINMAX(x, PSCNV_RB_NEGINF)
+#define PSCNV_RB_MAX(name, x) name##_PSCNV_RB_MINMAX(x, PSCNV_RB_INF)
+
+#define PSCNV_RB_FOREACH(x, name, head) \
+ for ((x) = PSCNV_RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_PSCNV_RB_NEXT(x))
+
+#define PSCNV_RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = PSCNV_RB_MAX(name, head); \
+ (x) != NULL; \
+ (x) = name##_PSCNV_RB_PREV(x))
+
+#endif /* __PSCNV_TREE_H__ */
View
164 pscnv/pscnv_vm.c
@@ -30,6 +30,31 @@
#include "pscnv_vram.h"
#include "pscnv_vm.h"
+#undef PSCNV_RB_AUGMENT
+
+static void PSCNV_RB_AUGMENT(struct pscnv_vm_mapnode *node) {
+ uint64_t maxgap = 0;
+ struct pscnv_vm_mapnode *left = PSCNV_RB_LEFT(node, entry);
+ struct pscnv_vm_mapnode *right = PSCNV_RB_RIGHT(node, entry);
+ if (!node->vo)
+ maxgap = node->size;
+ if (left && left->maxgap > maxgap)
+ maxgap = left->maxgap;
+ if (right && right->maxgap > maxgap)
+ maxgap = right->maxgap;
+ node->maxgap = maxgap;
+}
+
+static int mapcmp(struct pscnv_vm_mapnode *a, struct pscnv_vm_mapnode *b) {
+ if (a->start < b->start)
+ return -1;
+ else if (a->start > b->start)
+ return 1;
+ return 0;
+}
+
+PSCNV_RB_GENERATE_STATIC(pscnv_vm_maptree, pscnv_vm_mapnode, entry, mapcmp)
+
static int
pscnv_vspace_flush(struct pscnv_vspace *vs, int unit) {
nv_wr32(vs->dev, 0x100c80, unit << 16 | 1);
@@ -114,11 +139,23 @@ pscnv_vspace_do_map (struct pscnv_vspace *vs, struct pscnv_vo *vo, uint64_t offs
struct pscnv_vspace *
pscnv_vspace_new (struct drm_device *dev) {
struct pscnv_vspace *res = kzalloc(sizeof *res, GFP_KERNEL);
- if (res) {
- res->dev = dev;
- mutex_init(&res->lock);
- INIT_LIST_HEAD(&res->chan_list);
+ struct pscnv_vm_mapnode *fmap;
+ if (!res)
+ return 0;
+ res->dev = dev;
+ mutex_init(&res->lock);
+ INIT_LIST_HEAD(&res->chan_list);
+ PSCNV_RB_INIT(&res->maps);
+ fmap = kzalloc(sizeof *fmap, GFP_KERNEL);
+ if (!fmap) {
+ kfree(res);
+ return 0;
}
+ fmap->vspace = res;
+ fmap->start = 0;
+ fmap->size = 1ULL << 40;
+ fmap->maxgap = fmap->size;
+ PSCNV_RB_INSERT(pscnv_vm_maptree, &res->maps, fmap);
return res;
}
@@ -222,6 +259,7 @@ pscnv_vm_init(struct drm_device *dev) {
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct pscnv_vspace *barvm = pscnv_vspace_new (dev);
struct pscnv_chan *barch;
+ struct pscnv_vm_mapnode *foo;
int bar1dma, bar3dma;
if (!barvm)
return -ENOMEM;
@@ -234,9 +272,14 @@ pscnv_vm_init(struct drm_device *dev) {
bar3dma = pscnv_chan_dmaobj_new(barch, 0x7fc00000, dev_priv->fb_size, dev_priv->ramin_size);
nv_wr32(dev, 0x1708, 0x80000000 | bar1dma >> 4);
nv_wr32(dev, 0x170c, 0x80000000 | bar3dma >> 4);
-
dev_priv->barvm = barvm;
dev_priv->barch = barch;
+ pscnv_vspace_map3(barch->vo);
+ pscnv_vspace_map3(barvm->pt[0]);
+
+ pscnv_vspace_map(barvm, barch->vo, dev_priv->fb_size, dev_priv->fb_size + dev_priv->ramin_size, 0, &foo);
+ pscnv_vspace_map(barvm, barvm->pt[0], dev_priv->fb_size, dev_priv->fb_size + dev_priv->ramin_size, 0, &foo);
+
return 0;
}
@@ -249,3 +292,114 @@ pscnv_vm_takedown(struct drm_device *dev) {
/* XXX: write me. */
return 0;
}
+
+static struct pscnv_vm_mapnode *
+pscnv_vspace_map_int(struct pscnv_vspace *vs, struct pscnv_vo *vo,
+ uint64_t start, uint64_t end, int back,
+ struct pscnv_vm_mapnode *node)
+{
+ struct pscnv_vm_mapnode *left, *right, *res;
+ int lok, rok;
+ uint64_t mstart, mend;
+ left = PSCNV_RB_LEFT(node, entry);
+ right = PSCNV_RB_RIGHT(node, entry);
+ lok = left && left->maxgap >= vo->size && node->start > start;
+ rok = right && right->maxgap >= vo->size && node->start + node->size < end;
+ NV_INFO (vs->dev, "%llx %llx %llx %llx %llx %llx %llx %llx %llx %d %d\n", node->start, node->size, node->maxgap,
+ left?left->start:0, left?left->size:0, left?left->maxgap:0,
+ right?right->start:0, right?right->size:0, right?right->maxgap:0, lok, rok);
+ if (!back && lok) {
+ res = pscnv_vspace_map_int(vs, vo, start, end, back, left);
+ if (res)
+ return res;
+ }
+ if (back && rok) {
+ res = pscnv_vspace_map_int(vs, vo, start, end, back, right);
+ if (res)
+ return res;
+ }
+ mstart = node->start;
+ if (mstart < start)
+ mstart = start;
+ mend = node->start + node->size;
+ if (mend > end)
+ mend = end;
+ if (mstart + vo->size <= mend && !node->vo) {
+ if (back)
+ mstart = mend - vo->size;
+ mend = mstart + vo->size;
+ if (node->start + node->size != mend) {
+ struct pscnv_vm_mapnode *split = kzalloc(sizeof *split, GFP_KERNEL);
+ if (!split)
+ return 0;
+ split->start = mend;
+ split->size = node->start + node->size - mend;
+ node->size = mend - node->start;
+ split->maxgap = split->size;
+ PSCNV_RB_INSERT(pscnv_vm_maptree, &vs->maps, split);
+ }
+ if (node->start != mstart) {
+ struct pscnv_vm_mapnode *split = kzalloc(sizeof *split, GFP_KERNEL);
+ if (!split)
+ return 0;
+ split->start = node->start;
+ split->size = mstart - node->start;
+ node->start = mstart;
+ node->size = mend - node->start;
+ split->maxgap = split->size;
+ PSCNV_RB_INSERT(pscnv_vm_maptree, &vs->maps, split);
+ }
+ node->vo = vo;
+ PSCNV_RB_AUGMENT(node);
+ return node;
+ }
+ if (back && lok) {
+ res = pscnv_vspace_map_int(vs, vo, start, end, back, left);
+ if (res)
+ return res;
+ }
+ if (!back && rok) {
+ res = pscnv_vspace_map_int(vs, vo, start, end, back, right);
+ if (res)
+ return res;
+ }
+ return 0;
+}
+
+int
+pscnv_vspace_map(struct pscnv_vspace *vs, struct pscnv_vo *vo,
+ uint64_t start, uint64_t end, int back,
+ struct pscnv_vm_mapnode **res)
+{
+ struct pscnv_vm_mapnode *node;
+ mutex_lock(&vs->lock);
+ node = pscnv_vspace_map_int(vs, vo, start, end, back, PSCNV_RB_ROOT(&vs->maps));
+ if (!node) {
+ mutex_unlock(&vs->lock);
+ return -ENOMEM;
+ }
+ NV_INFO(vs->dev, "Mapping VO %x/%d at %llx-%llx.\n", vo->cookie, vo->serial, node->start,
+ node->start + node->size);
+ pscnv_vspace_do_map(vs, vo, node->start);
+ *res = node;
+ mutex_unlock(&vs->lock);
+ return 0;
+}
+
+int pscnv_vspace_map1(struct pscnv_vo *vo) {
+ struct drm_nouveau_private *dev_priv = vo->dev->dev_private;
+ if (vo->map1)
+ return 0;
+ if (!dev_priv->barvm)
+ return -ENODEV;
+ return pscnv_vspace_map(dev_priv->barvm, vo, 0, dev_priv->fb_size, 0, &vo->map1);
+}
+
+int pscnv_vspace_map3(struct pscnv_vo *vo) {
+ struct drm_nouveau_private *dev_priv = vo->dev->dev_private;
+ if (vo->map3)
+ return 0;
+ if (!dev_priv->barvm)
+ return -ENODEV;
+ return pscnv_vspace_map(dev_priv->barvm, vo, dev_priv->fb_size, dev_priv->fb_size + dev_priv->ramin_size, 0, &vo->map3);
+}
View
18 pscnv/pscnv_vm.h
@@ -27,6 +27,7 @@
#ifndef __PSCNV_VM_H__
#define __PSCNV_VM_H__
#include "pscnv_vram.h"
+#include "pscnv_tree.h"
#define NV50_VM_SIZE 0x10000000000ULL
#define NV50_VM_PDE_COUNT 0x800
@@ -36,21 +37,26 @@
#define NV50_CHAN_PD 0x1400
#define NV84_CHAN_PD 0x0200
+PSCNV_RB_HEAD(pscnv_vm_maptree, pscnv_vm_mapnode);
+
struct pscnv_vspace {
struct drm_device *dev;
struct mutex lock;
int isbar;
struct pscnv_vo *pt[NV50_VM_PDE_COUNT];
struct list_head chan_list;
+ struct pscnv_vm_maptree maps;
};
-#if 0
-struct pscnv_vspace_map {
+struct pscnv_vm_mapnode {
+ PSCNV_RB_ENTRY(pscnv_vm_mapnode) entry;
struct pscnv_vspace *vspace;
+ /* NULL means free */
struct pscnv_vo *vo;
uint64_t start;
+ uint64_t size;
+ uint64_t maxgap;
};
-#endif
struct pscnv_chan {
struct pscnv_vspace *vspace;
@@ -69,9 +75,9 @@ extern struct pscnv_chan *pscnv_chan_new(struct pscnv_vspace *);
extern void pscnv_chan_del(struct pscnv_chan *);
extern int pscnv_chan_iobj_new(struct pscnv_chan *, uint32_t size);
extern int pscnv_chan_dmaobj_new(struct pscnv_chan *, uint32_t type, uint64_t start, uint64_t size);
-#if 0
-extern int pscnv_vspace_map(struct pscnv_vspace *, struct pscnv_vo *, uint64_t start, uint64_t end, int back);
+extern int pscnv_vspace_map(struct pscnv_vspace *, struct pscnv_vo *, uint64_t start, uint64_t end, int back, struct pscnv_vm_mapnode **res);
extern int pscnv_vspace_unmap(struct pscnv_vspace *, uint64_t start);
-#endif
+extern int pscnv_vspace_map1(struct pscnv_vo *);
+extern int pscnv_vspace_map3(struct pscnv_vo *);
#endif
View
2  pscnv/pscnv_vram.c
@@ -369,7 +369,7 @@ pscnv_vram_alloc(struct drm_device *dev,
if (size >= (1ULL << 40))
return 0;
- res = kmalloc (sizeof *res, GFP_KERNEL);
+ res = kzalloc (sizeof *res, GFP_KERNEL);
if (!res)
return 0;
size = ALIGN(size, PSCNV_VRAM_PAGE_SIZE);
View
2  pscnv/pscnv_vram.h
@@ -50,6 +50,8 @@ struct pscnv_vo {
uint64_t map_handle;
uint32_t user[8];
struct drm_gem_object *gem;
+ struct pscnv_vm_mapnode *map1;
+ struct pscnv_vm_mapnode *map3;
};
/* the VO flags */
Please sign in to comment.
Something went wrong with that request. Please try again.