Home | History | Annotate | Line # | Download | only in instmem
      1 /*	$NetBSD: nouveau_nvkm_subdev_instmem_base.c,v 1.9 2022/04/09 19:59:08 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 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_instmem_base.c,v 1.9 2022/04/09 19:59:08 riastradh Exp $");
     28 
     29 #include "priv.h"
     30 
     31 #include <subdev/bar.h>
     32 
     33 #ifdef __NetBSD__
     34 #  define	__iomem	__nvkm_memory_iomem
     35 #endif
     36 
     37 /******************************************************************************
     38  * instmem object base implementation
     39  *****************************************************************************/
     40 static void
     41 nvkm_instobj_load(struct nvkm_instobj *iobj)
     42 {
     43 	struct nvkm_memory *memory = &iobj->memory;
     44 	const u64 size = nvkm_memory_size(memory);
     45 	void __iomem *map;
     46 	int i;
     47 
     48 	if (!(map = nvkm_kmap(memory))) {
     49 		for (i = 0; i < size; i += 4)
     50 			nvkm_wo32(memory, i, iobj->suspend[i / 4]);
     51 	} else {
     52 		memcpy_toio(map, iobj->suspend, size);
     53 	}
     54 	nvkm_done(memory);
     55 
     56 	kvfree(iobj->suspend);
     57 	iobj->suspend = NULL;
     58 }
     59 
     60 static int
     61 nvkm_instobj_save(struct nvkm_instobj *iobj)
     62 {
     63 	struct nvkm_memory *memory = &iobj->memory;
     64 	const u64 size = nvkm_memory_size(memory);
     65 	void __iomem *map;
     66 	int i;
     67 
     68 	iobj->suspend = kvmalloc(size, GFP_KERNEL);
     69 	if (!iobj->suspend)
     70 		return -ENOMEM;
     71 
     72 	if (!(map = nvkm_kmap(memory))) {
     73 		for (i = 0; i < size; i += 4)
     74 			iobj->suspend[i / 4] = nvkm_ro32(memory, i);
     75 	} else {
     76 		memcpy_fromio(iobj->suspend, map, size);
     77 	}
     78 	nvkm_done(memory);
     79 	return 0;
     80 }
     81 
     82 void
     83 nvkm_instobj_dtor(struct nvkm_instmem *imem, struct nvkm_instobj *iobj)
     84 {
     85 	spin_lock(&imem->lock);
     86 	list_del(&iobj->head);
     87 	spin_unlock(&imem->lock);
     88 }
     89 
     90 void
     91 nvkm_instobj_ctor(const struct nvkm_memory_func *func,
     92 		  struct nvkm_instmem *imem, struct nvkm_instobj *iobj)
     93 {
     94 	nvkm_memory_ctor(func, &iobj->memory);
     95 	iobj->suspend = NULL;
     96 	spin_lock(&imem->lock);
     97 	list_add_tail(&iobj->head, &imem->list);
     98 	spin_unlock(&imem->lock);
     99 }
    100 
    101 int
    102 nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero,
    103 		 struct nvkm_memory **pmemory)
    104 {
    105 	struct nvkm_subdev *subdev = &imem->subdev;
    106 	struct nvkm_memory *memory = NULL;
    107 	u32 offset;
    108 	int ret;
    109 
    110 	ret = imem->func->memory_new(imem, size, align, zero, &memory);
    111 	if (ret) {
    112 		nvkm_error(subdev, "OOM: %08x %08x %d\n", size, align, ret);
    113 		goto done;
    114 	}
    115 
    116 	nvkm_trace(subdev, "new %08x %08x %d: %010"PRIx64" %010"PRIx64"\n", size, align,
    117 		   zero, nvkm_memory_addr(memory), nvkm_memory_size(memory));
    118 
    119 	if (!imem->func->zero && zero) {
    120 		void __iomem *map = nvkm_kmap(memory);
    121 		if (unlikely(!map)) {
    122 			for (offset = 0; offset < size; offset += 4)
    123 				nvkm_wo32(memory, offset, 0x00000000);
    124 		} else {
    125 			memset_io(map, 0x00, size);
    126 		}
    127 		nvkm_done(memory);
    128 	}
    129 
    130 done:
    131 	if (ret)
    132 		nvkm_memory_unref(&memory);
    133 	*pmemory = memory;
    134 	return ret;
    135 }
    136 
    137 /******************************************************************************
    138  * instmem subdev base implementation
    139  *****************************************************************************/
    140 
    141 u32
    142 nvkm_instmem_rd32(struct nvkm_instmem *imem, u32 addr)
    143 {
    144 	return imem->func->rd32(imem, addr);
    145 }
    146 
    147 void
    148 nvkm_instmem_wr32(struct nvkm_instmem *imem, u32 addr, u32 data)
    149 {
    150 	return imem->func->wr32(imem, addr, data);
    151 }
    152 
    153 void
    154 nvkm_instmem_boot(struct nvkm_instmem *imem)
    155 {
    156 	/* Separate bootstrapped objects from normal list, as we need
    157 	 * to make sure they're accessed with the slowpath on suspend
    158 	 * and resume.
    159 	 */
    160 	struct nvkm_instobj *iobj, *itmp;
    161 	spin_lock(&imem->lock);
    162 	list_for_each_entry_safe(iobj, itmp, &imem->list, head) {
    163 		list_move_tail(&iobj->head, &imem->boot);
    164 	}
    165 	spin_unlock(&imem->lock);
    166 }
    167 
    168 static int
    169 nvkm_instmem_fini(struct nvkm_subdev *subdev, bool suspend)
    170 {
    171 	struct nvkm_instmem *imem = nvkm_instmem(subdev);
    172 	struct nvkm_instobj *iobj;
    173 
    174 	if (suspend) {
    175 		list_for_each_entry(iobj, &imem->list, head) {
    176 			int ret = nvkm_instobj_save(iobj);
    177 			if (ret)
    178 				return ret;
    179 		}
    180 
    181 		nvkm_bar_bar2_fini(subdev->device);
    182 
    183 		list_for_each_entry(iobj, &imem->boot, head) {
    184 			int ret = nvkm_instobj_save(iobj);
    185 			if (ret)
    186 				return ret;
    187 		}
    188 	}
    189 
    190 	if (imem->func->fini)
    191 		imem->func->fini(imem);
    192 
    193 	return 0;
    194 }
    195 
    196 static int
    197 nvkm_instmem_init(struct nvkm_subdev *subdev)
    198 {
    199 	struct nvkm_instmem *imem = nvkm_instmem(subdev);
    200 	struct nvkm_instobj *iobj;
    201 
    202 	list_for_each_entry(iobj, &imem->boot, head) {
    203 		if (iobj->suspend)
    204 			nvkm_instobj_load(iobj);
    205 	}
    206 
    207 	nvkm_bar_bar2_init(subdev->device);
    208 
    209 	list_for_each_entry(iobj, &imem->list, head) {
    210 		if (iobj->suspend)
    211 			nvkm_instobj_load(iobj);
    212 	}
    213 
    214 	return 0;
    215 }
    216 
    217 static int
    218 nvkm_instmem_oneinit(struct nvkm_subdev *subdev)
    219 {
    220 	struct nvkm_instmem *imem = nvkm_instmem(subdev);
    221 	if (imem->func->oneinit)
    222 		return imem->func->oneinit(imem);
    223 	return 0;
    224 }
    225 
    226 static void *
    227 nvkm_instmem_dtor(struct nvkm_subdev *subdev)
    228 {
    229 	struct nvkm_instmem *imem = nvkm_instmem(subdev);
    230 	spin_lock_destroy(&imem->lock);
    231 	if (imem->func->dtor)
    232 		return imem->func->dtor(imem);
    233 	return imem;
    234 }
    235 
    236 static const struct nvkm_subdev_func
    237 nvkm_instmem = {
    238 	.dtor = nvkm_instmem_dtor,
    239 	.oneinit = nvkm_instmem_oneinit,
    240 	.init = nvkm_instmem_init,
    241 	.fini = nvkm_instmem_fini,
    242 };
    243 
    244 void
    245 nvkm_instmem_ctor(const struct nvkm_instmem_func *func,
    246 		  struct nvkm_device *device, int index,
    247 		  struct nvkm_instmem *imem)
    248 {
    249 	nvkm_subdev_ctor(&nvkm_instmem, device, index, &imem->subdev);
    250 	imem->func = func;
    251 	spin_lock_init(&imem->lock);
    252 	INIT_LIST_HEAD(&imem->list);
    253 	INIT_LIST_HEAD(&imem->boot);
    254 }
    255