Home | History | Annotate | Line # | Download | only in core
      1 /*	$NetBSD: nouveau_nvkm_core_ramht.c,v 1.3 2021/12/18 23:45:34 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 #include <sys/cdefs.h>
     25 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_core_ramht.c,v 1.3 2021/12/18 23:45:34 riastradh Exp $");
     26 
     27 #include <core/ramht.h>
     28 #include <core/engine.h>
     29 #include <core/object.h>
     30 
     31 static u32
     32 nvkm_ramht_hash(struct nvkm_ramht *ramht, int chid, u32 handle)
     33 {
     34 	u32 hash = 0;
     35 
     36 	while (handle) {
     37 		hash ^= (handle & ((1 << ramht->bits) - 1));
     38 		handle >>= ramht->bits;
     39 	}
     40 
     41 	hash ^= chid << (ramht->bits - 4);
     42 	return hash;
     43 }
     44 
     45 struct nvkm_gpuobj *
     46 nvkm_ramht_search(struct nvkm_ramht *ramht, int chid, u32 handle)
     47 {
     48 	u32 co, ho;
     49 
     50 	co = ho = nvkm_ramht_hash(ramht, chid, handle);
     51 	do {
     52 		if (ramht->data[co].chid == chid) {
     53 			if (ramht->data[co].handle == handle)
     54 				return ramht->data[co].inst;
     55 		}
     56 
     57 		if (++co >= ramht->size)
     58 			co = 0;
     59 	} while (co != ho);
     60 
     61 	return NULL;
     62 }
     63 
     64 static int
     65 nvkm_ramht_update(struct nvkm_ramht *ramht, int co, struct nvkm_object *object,
     66 		  int chid, int addr, u32 handle, u32 context)
     67 {
     68 	struct nvkm_ramht_data *data = &ramht->data[co];
     69 	u64 inst = 0x00000040; /* just non-zero for <=g8x fifo ramht */
     70 	int ret;
     71 
     72 	nvkm_gpuobj_del(&data->inst);
     73 	data->chid = chid;
     74 	data->handle = handle;
     75 
     76 	if (object) {
     77 		ret = nvkm_object_bind(object, ramht->parent, 16, &data->inst);
     78 		if (ret) {
     79 			if (ret != -ENODEV) {
     80 				data->chid = -1;
     81 				return ret;
     82 			}
     83 			data->inst = NULL;
     84 		}
     85 
     86 		if (data->inst) {
     87 			if (ramht->device->card_type >= NV_50)
     88 				inst = data->inst->node->offset;
     89 			else
     90 				inst = data->inst->addr;
     91 		}
     92 
     93 		if (addr < 0) context |= inst << -addr;
     94 		else          context |= inst >>  addr;
     95 	}
     96 
     97 	nvkm_kmap(ramht->gpuobj);
     98 	nvkm_wo32(ramht->gpuobj, (co << 3) + 0, handle);
     99 	nvkm_wo32(ramht->gpuobj, (co << 3) + 4, context);
    100 	nvkm_done(ramht->gpuobj);
    101 	return co + 1;
    102 }
    103 
    104 void
    105 nvkm_ramht_remove(struct nvkm_ramht *ramht, int cookie)
    106 {
    107 	if (--cookie >= 0)
    108 		nvkm_ramht_update(ramht, cookie, NULL, -1, 0, 0, 0);
    109 }
    110 
    111 int
    112 nvkm_ramht_insert(struct nvkm_ramht *ramht, struct nvkm_object *object,
    113 		  int chid, int addr, u32 handle, u32 context)
    114 {
    115 	u32 co, ho;
    116 
    117 	if (nvkm_ramht_search(ramht, chid, handle))
    118 		return -EEXIST;
    119 
    120 	co = ho = nvkm_ramht_hash(ramht, chid, handle);
    121 	do {
    122 		if (ramht->data[co].chid < 0) {
    123 			return nvkm_ramht_update(ramht, co, object, chid,
    124 						 addr, handle, context);
    125 		}
    126 
    127 		if (++co >= ramht->size)
    128 			co = 0;
    129 	} while (co != ho);
    130 
    131 	return -ENOSPC;
    132 }
    133 
    134 void
    135 nvkm_ramht_del(struct nvkm_ramht **pramht)
    136 {
    137 	struct nvkm_ramht *ramht = *pramht;
    138 	if (ramht) {
    139 		nvkm_gpuobj_del(&ramht->gpuobj);
    140 		vfree(*pramht);
    141 		*pramht = NULL;
    142 	}
    143 }
    144 
    145 int
    146 nvkm_ramht_new(struct nvkm_device *device, u32 size, u32 align,
    147 	       struct nvkm_gpuobj *parent, struct nvkm_ramht **pramht)
    148 {
    149 	struct nvkm_ramht *ramht;
    150 	int ret, i;
    151 
    152 	if (!(ramht = *pramht = vzalloc(struct_size(ramht, data, (size >> 3)))))
    153 		return -ENOMEM;
    154 
    155 	ramht->device = device;
    156 	ramht->parent = parent;
    157 	ramht->size = size >> 3;
    158 	ramht->bits = order_base_2(ramht->size);
    159 	for (i = 0; i < ramht->size; i++)
    160 		ramht->data[i].chid = -1;
    161 
    162 	ret = nvkm_gpuobj_new(ramht->device, size, align, true,
    163 			      ramht->parent, &ramht->gpuobj);
    164 	if (ret)
    165 		nvkm_ramht_del(pramht);
    166 	return ret;
    167 }
    168