xref: /openbmc/linux/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1c39f472eSBen Skeggs /*
2c39f472eSBen Skeggs  * Copyright 2012 Red Hat Inc.
3c39f472eSBen Skeggs  *
4c39f472eSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
5c39f472eSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
6c39f472eSBen Skeggs  * to deal in the Software without restriction, including without limitation
7c39f472eSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c39f472eSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
9c39f472eSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
10c39f472eSBen Skeggs  *
11c39f472eSBen Skeggs  * The above copyright notice and this permission notice shall be included in
12c39f472eSBen Skeggs  * all copies or substantial portions of the Software.
13c39f472eSBen Skeggs  *
14c39f472eSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c39f472eSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c39f472eSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17c39f472eSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c39f472eSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c39f472eSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c39f472eSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
21c39f472eSBen Skeggs  *
22c39f472eSBen Skeggs  * Authors: Ben Skeggs
23c39f472eSBen Skeggs  */
24c39f472eSBen Skeggs #include "priv.h"
25c39f472eSBen Skeggs 
26d8e83994SBen Skeggs #include <subdev/bar.h>
2778b2b4e7SBen Skeggs 
28c39f472eSBen Skeggs /******************************************************************************
29c39f472eSBen Skeggs  * instmem object base implementation
30c39f472eSBen Skeggs  *****************************************************************************/
31d52ddc95SBen Skeggs static void
nvkm_instobj_load(struct nvkm_instobj * iobj)32d52ddc95SBen Skeggs nvkm_instobj_load(struct nvkm_instobj *iobj)
33d52ddc95SBen Skeggs {
34d52ddc95SBen Skeggs 	struct nvkm_memory *memory = &iobj->memory;
35d52ddc95SBen Skeggs 	const u64 size = nvkm_memory_size(memory);
36ffd937bbSBen Skeggs 	void __iomem *map;
37d52ddc95SBen Skeggs 	int i;
38d52ddc95SBen Skeggs 
39ffd937bbSBen Skeggs 	if (!(map = nvkm_kmap(memory))) {
40d52ddc95SBen Skeggs 		for (i = 0; i < size; i += 4)
41d52ddc95SBen Skeggs 			nvkm_wo32(memory, i, iobj->suspend[i / 4]);
42ffd937bbSBen Skeggs 	} else {
43ffd937bbSBen Skeggs 		memcpy_toio(map, iobj->suspend, size);
44ffd937bbSBen Skeggs 	}
45ffd937bbSBen Skeggs 	nvkm_done(memory);
46ffd937bbSBen Skeggs 
4754c70e3aSBen Skeggs 	kvfree(iobj->suspend);
48d52ddc95SBen Skeggs 	iobj->suspend = NULL;
49d52ddc95SBen Skeggs }
50d52ddc95SBen Skeggs 
51d52ddc95SBen Skeggs static int
nvkm_instobj_save(struct nvkm_instobj * iobj)52d52ddc95SBen Skeggs nvkm_instobj_save(struct nvkm_instobj *iobj)
53d52ddc95SBen Skeggs {
54d52ddc95SBen Skeggs 	struct nvkm_memory *memory = &iobj->memory;
55d52ddc95SBen Skeggs 	const u64 size = nvkm_memory_size(memory);
56e9be3c7dSBen Skeggs 	void __iomem *map;
57d52ddc95SBen Skeggs 	int i;
58d52ddc95SBen Skeggs 
5954c70e3aSBen Skeggs 	iobj->suspend = kvmalloc(size, GFP_KERNEL);
60d52ddc95SBen Skeggs 	if (!iobj->suspend)
61d52ddc95SBen Skeggs 		return -ENOMEM;
62d52ddc95SBen Skeggs 
63e9be3c7dSBen Skeggs 	if (!(map = nvkm_kmap(memory))) {
64d52ddc95SBen Skeggs 		for (i = 0; i < size; i += 4)
65d52ddc95SBen Skeggs 			iobj->suspend[i / 4] = nvkm_ro32(memory, i);
66e9be3c7dSBen Skeggs 	} else {
67e9be3c7dSBen Skeggs 		memcpy_fromio(iobj->suspend, map, size);
68e9be3c7dSBen Skeggs 	}
69e9be3c7dSBen Skeggs 	nvkm_done(memory);
70d52ddc95SBen Skeggs 	return 0;
71d52ddc95SBen Skeggs }
72d52ddc95SBen Skeggs 
7349814f62SBen Skeggs void
nvkm_instobj_dtor(struct nvkm_instmem * imem,struct nvkm_instobj * iobj)7449814f62SBen Skeggs nvkm_instobj_dtor(struct nvkm_instmem *imem, struct nvkm_instobj *iobj)
7549814f62SBen Skeggs {
7649814f62SBen Skeggs 	spin_lock(&imem->lock);
7749814f62SBen Skeggs 	list_del(&iobj->head);
7849814f62SBen Skeggs 	spin_unlock(&imem->lock);
7949814f62SBen Skeggs }
8049814f62SBen Skeggs 
8149814f62SBen Skeggs void
nvkm_instobj_ctor(const struct nvkm_memory_func * func,struct nvkm_instmem * imem,struct nvkm_instobj * iobj)8249814f62SBen Skeggs nvkm_instobj_ctor(const struct nvkm_memory_func *func,
8349814f62SBen Skeggs 		  struct nvkm_instmem *imem, struct nvkm_instobj *iobj)
8449814f62SBen Skeggs {
8549814f62SBen Skeggs 	nvkm_memory_ctor(func, &iobj->memory);
8649814f62SBen Skeggs 	iobj->suspend = NULL;
8749814f62SBen Skeggs 	spin_lock(&imem->lock);
8849814f62SBen Skeggs 	list_add_tail(&iobj->head, &imem->list);
8949814f62SBen Skeggs 	spin_unlock(&imem->lock);
9049814f62SBen Skeggs }
9149814f62SBen Skeggs 
92b7a2bc18SBen Skeggs int
nvkm_instobj_wrap(struct nvkm_device * device,struct nvkm_memory * memory,struct nvkm_memory ** pmemory)93*973b3244SBen Skeggs nvkm_instobj_wrap(struct nvkm_device *device,
94*973b3244SBen Skeggs 		  struct nvkm_memory *memory, struct nvkm_memory **pmemory)
95*973b3244SBen Skeggs {
96*973b3244SBen Skeggs 	struct nvkm_instmem *imem = device->imem;
97*973b3244SBen Skeggs 
98*973b3244SBen Skeggs 	if (!imem->func->memory_wrap)
99*973b3244SBen Skeggs 		return -ENOSYS;
100*973b3244SBen Skeggs 
101*973b3244SBen Skeggs 	return imem->func->memory_wrap(imem, memory, pmemory);
102*973b3244SBen Skeggs }
103*973b3244SBen Skeggs 
104*973b3244SBen Skeggs int
nvkm_instobj_new(struct nvkm_instmem * imem,u32 size,u32 align,bool zero,struct nvkm_memory ** pmemory)105d8e83994SBen Skeggs nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero,
106d8e83994SBen Skeggs 		 struct nvkm_memory **pmemory)
107d8e83994SBen Skeggs {
108dde59b9cSBen Skeggs 	struct nvkm_subdev *subdev = &imem->subdev;
109b7a2bc18SBen Skeggs 	struct nvkm_memory *memory = NULL;
110d8e83994SBen Skeggs 	u32 offset;
111c39f472eSBen Skeggs 	int ret;
112c39f472eSBen Skeggs 
113b7a2bc18SBen Skeggs 	ret = imem->func->memory_new(imem, size, align, zero, &memory);
114dde59b9cSBen Skeggs 	if (ret) {
115dde59b9cSBen Skeggs 		nvkm_error(subdev, "OOM: %08x %08x %d\n", size, align, ret);
116d8e83994SBen Skeggs 		goto done;
117dde59b9cSBen Skeggs 	}
118dde59b9cSBen Skeggs 
119dde59b9cSBen Skeggs 	nvkm_trace(subdev, "new %08x %08x %d: %010llx %010llx\n", size, align,
120dde59b9cSBen Skeggs 		   zero, nvkm_memory_addr(memory), nvkm_memory_size(memory));
121c39f472eSBen Skeggs 
122b7a2bc18SBen Skeggs 	if (!imem->func->zero && zero) {
123d8e83994SBen Skeggs 		void __iomem *map = nvkm_kmap(memory);
124d8e83994SBen Skeggs 		if (unlikely(!map)) {
125d8e83994SBen Skeggs 			for (offset = 0; offset < size; offset += 4)
126d8e83994SBen Skeggs 				nvkm_wo32(memory, offset, 0x00000000);
127d8e83994SBen Skeggs 		} else {
128d8e83994SBen Skeggs 			memset_io(map, 0x00, size);
129d8e83994SBen Skeggs 		}
130d8e83994SBen Skeggs 		nvkm_done(memory);
131d8e83994SBen Skeggs 	}
132d8e83994SBen Skeggs 
133d8e83994SBen Skeggs done:
134d8e83994SBen Skeggs 	if (ret)
135997a8900SBen Skeggs 		nvkm_memory_unref(&memory);
136d8e83994SBen Skeggs 	*pmemory = memory;
137d8e83994SBen Skeggs 	return ret;
138c39f472eSBen Skeggs }
139c39f472eSBen Skeggs 
140c39f472eSBen Skeggs /******************************************************************************
141c39f472eSBen Skeggs  * instmem subdev base implementation
142c39f472eSBen Skeggs  *****************************************************************************/
143c39f472eSBen Skeggs 
144b7a2bc18SBen Skeggs u32
nvkm_instmem_rd32(struct nvkm_instmem * imem,u32 addr)145b7a2bc18SBen Skeggs nvkm_instmem_rd32(struct nvkm_instmem *imem, u32 addr)
146c39f472eSBen Skeggs {
147b7a2bc18SBen Skeggs 	return imem->func->rd32(imem, addr);
148b7a2bc18SBen Skeggs }
149b7a2bc18SBen Skeggs 
150b7a2bc18SBen Skeggs void
nvkm_instmem_wr32(struct nvkm_instmem * imem,u32 addr,u32 data)151b7a2bc18SBen Skeggs nvkm_instmem_wr32(struct nvkm_instmem *imem, u32 addr, u32 data)
152b7a2bc18SBen Skeggs {
153b7a2bc18SBen Skeggs 	return imem->func->wr32(imem, addr, data);
154b7a2bc18SBen Skeggs }
155b7a2bc18SBen Skeggs 
156b00b8430SBen Skeggs void
nvkm_instmem_boot(struct nvkm_instmem * imem)157b00b8430SBen Skeggs nvkm_instmem_boot(struct nvkm_instmem *imem)
158b00b8430SBen Skeggs {
159b00b8430SBen Skeggs 	/* Separate bootstrapped objects from normal list, as we need
160b00b8430SBen Skeggs 	 * to make sure they're accessed with the slowpath on suspend
161b00b8430SBen Skeggs 	 * and resume.
162b00b8430SBen Skeggs 	 */
163b00b8430SBen Skeggs 	struct nvkm_instobj *iobj, *itmp;
164b00b8430SBen Skeggs 	spin_lock(&imem->lock);
165b00b8430SBen Skeggs 	list_for_each_entry_safe(iobj, itmp, &imem->list, head) {
166b00b8430SBen Skeggs 		list_move_tail(&iobj->head, &imem->boot);
167b00b8430SBen Skeggs 	}
168b00b8430SBen Skeggs 	spin_unlock(&imem->lock);
169b00b8430SBen Skeggs }
170b00b8430SBen Skeggs 
171b7a2bc18SBen Skeggs static int
nvkm_instmem_fini(struct nvkm_subdev * subdev,bool suspend)172b7a2bc18SBen Skeggs nvkm_instmem_fini(struct nvkm_subdev *subdev, bool suspend)
173b7a2bc18SBen Skeggs {
174b7a2bc18SBen Skeggs 	struct nvkm_instmem *imem = nvkm_instmem(subdev);
17578b2b4e7SBen Skeggs 	struct nvkm_instobj *iobj;
176d52ddc95SBen Skeggs 
177d52ddc95SBen Skeggs 	if (suspend) {
178d52ddc95SBen Skeggs 		list_for_each_entry(iobj, &imem->list, head) {
179d52ddc95SBen Skeggs 			int ret = nvkm_instobj_save(iobj);
180d52ddc95SBen Skeggs 			if (ret)
181d52ddc95SBen Skeggs 				return ret;
182d52ddc95SBen Skeggs 		}
183b00b8430SBen Skeggs 
184e9be3c7dSBen Skeggs 		nvkm_bar_bar2_fini(subdev->device);
185e9be3c7dSBen Skeggs 
186b00b8430SBen Skeggs 		list_for_each_entry(iobj, &imem->boot, head) {
187b00b8430SBen Skeggs 			int ret = nvkm_instobj_save(iobj);
188b00b8430SBen Skeggs 			if (ret)
189b00b8430SBen Skeggs 				return ret;
190b00b8430SBen Skeggs 		}
191d52ddc95SBen Skeggs 	}
192c39f472eSBen Skeggs 
193b7a2bc18SBen Skeggs 	if (imem->func->fini)
194b7a2bc18SBen Skeggs 		imem->func->fini(imem);
195b7a2bc18SBen Skeggs 
196d52ddc95SBen Skeggs 	return 0;
19795cf469cSBen Skeggs }
198d52ddc95SBen Skeggs 
199d52ddc95SBen Skeggs static int
nvkm_instmem_init(struct nvkm_subdev * subdev)200d52ddc95SBen Skeggs nvkm_instmem_init(struct nvkm_subdev *subdev)
201d52ddc95SBen Skeggs {
202d52ddc95SBen Skeggs 	struct nvkm_instmem *imem = nvkm_instmem(subdev);
203d52ddc95SBen Skeggs 	struct nvkm_instobj *iobj;
204d52ddc95SBen Skeggs 
205b00b8430SBen Skeggs 	list_for_each_entry(iobj, &imem->boot, head) {
206b00b8430SBen Skeggs 		if (iobj->suspend)
207b00b8430SBen Skeggs 			nvkm_instobj_load(iobj);
208b00b8430SBen Skeggs 	}
209b00b8430SBen Skeggs 
210ffd937bbSBen Skeggs 	nvkm_bar_bar2_init(subdev->device);
211ffd937bbSBen Skeggs 
212d52ddc95SBen Skeggs 	list_for_each_entry(iobj, &imem->list, head) {
213d52ddc95SBen Skeggs 		if (iobj->suspend)
214d52ddc95SBen Skeggs 			nvkm_instobj_load(iobj);
215c39f472eSBen Skeggs 	}
216c39f472eSBen Skeggs 
217b7a2bc18SBen Skeggs 	return 0;
218c39f472eSBen Skeggs }
219c39f472eSBen Skeggs 
220b7a2bc18SBen Skeggs static int
nvkm_instmem_oneinit(struct nvkm_subdev * subdev)221b7a2bc18SBen Skeggs nvkm_instmem_oneinit(struct nvkm_subdev *subdev)
222c39f472eSBen Skeggs {
223b7a2bc18SBen Skeggs 	struct nvkm_instmem *imem = nvkm_instmem(subdev);
224b7a2bc18SBen Skeggs 	if (imem->func->oneinit)
225b7a2bc18SBen Skeggs 		return imem->func->oneinit(imem);
226b7a2bc18SBen Skeggs 	return 0;
227b7a2bc18SBen Skeggs }
228c39f472eSBen Skeggs 
229b7a2bc18SBen Skeggs static void *
nvkm_instmem_dtor(struct nvkm_subdev * subdev)230b7a2bc18SBen Skeggs nvkm_instmem_dtor(struct nvkm_subdev *subdev)
231c39f472eSBen Skeggs {
232b7a2bc18SBen Skeggs 	struct nvkm_instmem *imem = nvkm_instmem(subdev);
233e5bf9a5cSBen Skeggs 	void *data = imem;
234b7a2bc18SBen Skeggs 	if (imem->func->dtor)
235e5bf9a5cSBen Skeggs 		data = imem->func->dtor(imem);
236e5bf9a5cSBen Skeggs 	mutex_destroy(&imem->mutex);
237e5bf9a5cSBen Skeggs 	return data;
238b7a2bc18SBen Skeggs }
239c39f472eSBen Skeggs 
240b7a2bc18SBen Skeggs static const struct nvkm_subdev_func
241b7a2bc18SBen Skeggs nvkm_instmem = {
242b7a2bc18SBen Skeggs 	.dtor = nvkm_instmem_dtor,
243b7a2bc18SBen Skeggs 	.oneinit = nvkm_instmem_oneinit,
244b7a2bc18SBen Skeggs 	.init = nvkm_instmem_init,
245b7a2bc18SBen Skeggs 	.fini = nvkm_instmem_fini,
246b7a2bc18SBen Skeggs };
247c39f472eSBen Skeggs 
248b7a2bc18SBen Skeggs void
nvkm_instmem_ctor(const struct nvkm_instmem_func * func,struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_instmem * imem)249d9691a22SBen Skeggs nvkm_instmem_ctor(const struct nvkm_instmem_func *func, struct nvkm_device *device,
250d9691a22SBen Skeggs 		  enum nvkm_subdev_type type, int inst, struct nvkm_instmem *imem)
251b7a2bc18SBen Skeggs {
252d9691a22SBen Skeggs 	nvkm_subdev_ctor(&nvkm_instmem, device, type, inst, &imem->subdev);
253b7a2bc18SBen Skeggs 	imem->func = func;
25495095032SBen Skeggs 	spin_lock_init(&imem->lock);
255c39f472eSBen Skeggs 	INIT_LIST_HEAD(&imem->list);
256b00b8430SBen Skeggs 	INIT_LIST_HEAD(&imem->boot);
257e5bf9a5cSBen Skeggs 	mutex_init(&imem->mutex);
258c39f472eSBen Skeggs }
259