1/* 2 * Copyright 2012 Red Hat Inc. 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 */ 24 25#include "priv.h" 26 27/****************************************************************************** 28 * instmem object base implementation 29 *****************************************************************************/ 30 31void 32_nouveau_instobj_dtor(struct nouveau_object *object) 33{ 34 struct nouveau_instmem *imem = (void *)object->engine; 35 struct nouveau_instobj *iobj = (void *)object; 36 37 mutex_lock(&nv_subdev(imem)->mutex); 38 list_del(&iobj->head); 39 mutex_unlock(&nv_subdev(imem)->mutex); 40 41 return nouveau_object_destroy(&iobj->base); 42} 43 44int 45nouveau_instobj_create_(struct nouveau_object *parent, 46 struct nouveau_object *engine, 47 struct nouveau_oclass *oclass, 48 int length, void **pobject) 49{ 50 struct nouveau_instmem *imem = (void *)engine; 51 struct nouveau_instobj *iobj; 52 int ret; 53 54 ret = nouveau_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS, 55 length, pobject); 56 iobj = *pobject; 57 if (ret) 58 return ret; 59 60 mutex_lock(&imem->base.mutex); 61 list_add(&iobj->head, &imem->list); 62 mutex_unlock(&imem->base.mutex); 63 return 0; 64} 65 66/****************************************************************************** 67 * instmem subdev base implementation 68 *****************************************************************************/ 69 70static int 71nouveau_instmem_alloc(struct nouveau_instmem *imem, 72 struct nouveau_object *parent, u32 size, u32 align, 73 struct nouveau_object **pobject) 74{ 75 struct nouveau_object *engine = nv_object(imem); 76 struct nouveau_instmem_impl *impl = (void *)engine->oclass; 77 struct nouveau_instobj_args args = { .size = size, .align = align }; 78 return nouveau_object_ctor(parent, engine, impl->instobj, &args, 79 sizeof(args), pobject); 80} 81 82int 83_nouveau_instmem_fini(struct nouveau_object *object, bool suspend) 84{ 85 struct nouveau_instmem *imem = (void *)object; 86 struct nouveau_instobj *iobj; 87 int i, ret = 0; 88 89 if (suspend) { 90 mutex_lock(&imem->base.mutex); 91 92 list_for_each_entry(iobj, &imem->list, head) { 93 iobj->suspend = vmalloc(iobj->size); 94 if (!iobj->suspend) { 95 ret = -ENOMEM; 96 break; 97 } 98 99 for (i = 0; i < iobj->size; i += 4) 100 iobj->suspend[i / 4] = nv_ro32(iobj, i); 101 } 102 103 mutex_unlock(&imem->base.mutex); 104 105 if (ret) 106 return ret; 107 } 108 109 return nouveau_subdev_fini(&imem->base, suspend); 110} 111 112int 113_nouveau_instmem_init(struct nouveau_object *object) 114{ 115 struct nouveau_instmem *imem = (void *)object; 116 struct nouveau_instobj *iobj; 117 int ret, i; 118 119 ret = nouveau_subdev_init(&imem->base); 120 if (ret) 121 return ret; 122 123 mutex_lock(&imem->base.mutex); 124 125 list_for_each_entry(iobj, &imem->list, head) { 126 if (iobj->suspend) { 127 for (i = 0; i < iobj->size; i += 4) 128 nv_wo32(iobj, i, iobj->suspend[i / 4]); 129 vfree(iobj->suspend); 130 iobj->suspend = NULL; 131 } 132 } 133 134 mutex_unlock(&imem->base.mutex); 135 136 return 0; 137} 138 139int 140nouveau_instmem_create_(struct nouveau_object *parent, 141 struct nouveau_object *engine, 142 struct nouveau_oclass *oclass, 143 int length, void **pobject) 144{ 145 struct nouveau_instmem *imem; 146 int ret; 147 148 ret = nouveau_subdev_create_(parent, engine, oclass, 0, 149 "INSTMEM", "instmem", length, pobject); 150 imem = *pobject; 151 if (ret) 152 return ret; 153 154 INIT_LIST_HEAD(&imem->list); 155 imem->alloc = nouveau_instmem_alloc; 156 return 0; 157} 158