1/* $NetBSD: nouveau_subdev_instmem_base.c,v 1.1.1.1 2014/08/06 12:36:30 riastradh Exp $ */
2
3/*
4 * Copyright 2012 Red Hat Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: Ben Skeggs
25 */
26
27#include <sys/cdefs.h>
28__KERNEL_RCSID(0, "$NetBSD: nouveau_subdev_instmem_base.c,v 1.1.1.1 2014/08/06 12:36:30 riastradh Exp $");
29
30#include "priv.h"
31
32/******************************************************************************
33 * instmem object base implementation
34 *****************************************************************************/
35
36void
37_nouveau_instobj_dtor(struct nouveau_object *object)
38{
39 struct nouveau_instmem *imem = (void *)object->engine;
40 struct nouveau_instobj *iobj = (void *)object;
41
42 mutex_lock(&nv_subdev(imem)->mutex);
43 list_del(&iobj->head);
44 mutex_unlock(&nv_subdev(imem)->mutex);
45
46 return nouveau_object_destroy(&iobj->base);
47}
48
49int
50nouveau_instobj_create_(struct nouveau_object *parent,
51 struct nouveau_object *engine,
52 struct nouveau_oclass *oclass,
53 int length, void **pobject)
54{
55 struct nouveau_instmem *imem = (void *)engine;
56 struct nouveau_instobj *iobj;
57 int ret;
58
59 ret = nouveau_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS,
60 length, pobject);
61 iobj = *pobject;
62 if (ret)
63 return ret;
64
65 mutex_lock(&imem->base.mutex);
66 list_add(&iobj->head, &imem->list);
67 mutex_unlock(&imem->base.mutex);
68 return 0;
69}
70
71/******************************************************************************
72 * instmem subdev base implementation
73 *****************************************************************************/
74
75static int
76nouveau_instmem_alloc(struct nouveau_instmem *imem,
77 struct nouveau_object *parent, u32 size, u32 align,
78 struct nouveau_object **pobject)
79{
80 struct nouveau_object *engine = nv_object(imem);
81 struct nouveau_instmem_impl *impl = (void *)engine->oclass;
82 struct nouveau_instobj_args args = { .size = size, .align = align };
83 return nouveau_object_ctor(parent, engine, impl->instobj, &args,
84 sizeof(args), pobject);
85}
86
87int
88_nouveau_instmem_fini(struct nouveau_object *object, bool suspend)
89{
90 struct nouveau_instmem *imem = (void *)object;
91 struct nouveau_instobj *iobj;
92 int i, ret = 0;
93
94 if (suspend) {
95 mutex_lock(&imem->base.mutex);
96
97 list_for_each_entry(iobj, &imem->list, head) {
98 iobj->suspend = vmalloc(iobj->size);
99 if (!iobj->suspend) {
100 ret = -ENOMEM;
101 break;
102 }
103
104 for (i = 0; i < iobj->size; i += 4)
105 iobj->suspend[i / 4] = nv_ro32(iobj, i);
106 }
107
108 mutex_unlock(&imem->base.mutex);
109
110 if (ret)
111 return ret;
112 }
113
114 return nouveau_subdev_fini(&imem->base, suspend);
115}
116
117int
118_nouveau_instmem_init(struct nouveau_object *object)
119{
120 struct nouveau_instmem *imem = (void *)object;
121 struct nouveau_instobj *iobj;
122 int ret, i;
123
124 ret = nouveau_subdev_init(&imem->base);
125 if (ret)
126 return ret;
127
128 mutex_lock(&imem->base.mutex);
129
130 list_for_each_entry(iobj, &imem->list, head) {
131 if (iobj->suspend) {
132 for (i = 0; i < iobj->size; i += 4)
133 nv_wo32(iobj, i, iobj->suspend[i / 4]);
134 vfree(iobj->suspend);
135 iobj->suspend = NULL;
136 }
137 }
138
139 mutex_unlock(&imem->base.mutex);
140
141 return 0;
142}
143
144int
145nouveau_instmem_create_(struct nouveau_object *parent,
146 struct nouveau_object *engine,
147 struct nouveau_oclass *oclass,
148 int length, void **pobject)
149{
150 struct nouveau_instmem *imem;
151 int ret;
152
153 ret = nouveau_subdev_create_(parent, engine, oclass, 0,
154 "INSTMEM", "instmem", length, pobject);
155 imem = *pobject;
156 if (ret)
157 return ret;
158
159 INIT_LIST_HEAD(&imem->list);
160 imem->alloc = nouveau_instmem_alloc;
161 return 0;
162}
163