OSDN Git Service

android: set LOCAL_MODULE_TAGS to optional
[android-x86/external-libdrm.git] / nouveau / nouveau_grobj.c
1 /*
2  * Copyright 2007 Nouveau Project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22
23 #include <stdlib.h>
24 #include <errno.h>
25
26 #include "nouveau_private.h"
27
28 int
29 nouveau_grobj_alloc(struct nouveau_channel *chan, uint32_t handle,
30                     int class, struct nouveau_grobj **grobj)
31 {
32         struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
33         struct nouveau_grobj_priv *nvgrobj;
34         struct drm_nouveau_grobj_alloc g;
35         int ret;
36
37         if (!nvdev || !grobj || *grobj)
38                 return -EINVAL;
39
40         nvgrobj = calloc(1, sizeof(*nvgrobj));
41         if (!nvgrobj)
42                 return -ENOMEM;
43         nvgrobj->base.channel = chan;
44         nvgrobj->base.handle  = handle;
45         nvgrobj->base.grclass = class;
46         nvgrobj->base.bound   = NOUVEAU_GROBJ_UNBOUND;
47         nvgrobj->base.subc    = -1;
48
49         g.channel = chan->id;
50         g.handle  = handle;
51         g.class   = class;
52         ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GROBJ_ALLOC,
53                               &g, sizeof(g));
54         if (ret) {
55                 nouveau_grobj_free((void *)&nvgrobj);
56                 return ret;
57         }
58
59         *grobj = &nvgrobj->base;
60         return 0;
61 }
62
63 int
64 nouveau_grobj_ref(struct nouveau_channel *chan, uint32_t handle,
65                   struct nouveau_grobj **grobj)
66 {
67         struct nouveau_grobj_priv *nvgrobj;
68
69         if (!chan || !grobj || *grobj)
70                 return -EINVAL;
71
72         nvgrobj = calloc(1, sizeof(struct nouveau_grobj_priv));
73         if (!nvgrobj)
74                 return -ENOMEM;
75         nvgrobj->base.channel = chan;
76         nvgrobj->base.handle = handle;
77         nvgrobj->base.grclass = 0;
78
79         *grobj = &nvgrobj->base;
80         return 0;
81 }
82
83 void
84 nouveau_grobj_free(struct nouveau_grobj **grobj)
85 {
86         struct nouveau_device_priv *nvdev;
87         struct nouveau_channel_priv *chan;
88         struct nouveau_grobj_priv *nvgrobj;
89
90         if (!grobj || !*grobj)
91                 return;
92         nvgrobj = nouveau_grobj(*grobj);
93         *grobj = NULL;
94
95
96         chan = nouveau_channel(nvgrobj->base.channel);
97         nvdev = nouveau_device(chan->base.device);
98
99         if (nvgrobj->base.grclass) {
100                 struct drm_nouveau_gpuobj_free f;
101
102                 FIRE_RING(&chan->base);
103
104                 f.channel = chan->drm.channel;
105                 f.handle  = nvgrobj->base.handle;
106                 drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
107                                 &f, sizeof(f)); 
108         }
109         free(nvgrobj);
110 }
111
112 void
113 nouveau_grobj_autobind(struct nouveau_grobj *grobj)
114 {
115         struct nouveau_channel *chan = grobj->channel;
116         struct nouveau_subchannel *subc = NULL;
117         int i;
118
119         for (i = 0; i < 8; i++) {
120                 struct nouveau_subchannel *scc = &grobj->channel->subc[i];
121
122                 if (scc->gr && scc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
123                         continue;
124
125                 if (!subc || scc->sequence < subc->sequence)
126                         subc = scc;
127         }
128
129         if (subc->gr) {
130                 subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
131                 subc->gr->subc  = -1;
132         }
133
134         subc->gr = grobj;
135         subc->gr->bound = NOUVEAU_GROBJ_BOUND;
136         subc->gr->subc  = subc - &grobj->channel->subc[0];
137
138         WAIT_RING(chan, 2);
139         if (chan->device->chipset < 0xc0) {
140                 OUT_RING (chan, (1 << 18) | (grobj->subc << 13));
141                 OUT_RING (chan, grobj->handle);
142         } else {
143                 OUT_RING (chan, (2 << 28) | (1 << 16) | (grobj->subc << 13));
144                 OUT_RING (chan, grobj->grclass);
145         }
146 }
147