brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · 6c20e82 Raw
276 lines · c
1/*2 * Copyright 2012 Red Hat Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: Ben Skeggs23 */24#include <core/subdev.h>25#include <core/device.h>26#include <core/option.h>27#include <subdev/mc.h>28 29const char *30nvkm_subdev_type[NVKM_SUBDEV_NR] = {31#define NVKM_LAYOUT_ONCE(type,data,ptr,...) [type] = #ptr,32#define NVKM_LAYOUT_INST(A...) NVKM_LAYOUT_ONCE(A)33#include <core/layout.h>34#undef NVKM_LAYOUT_ONCE35#undef NVKM_LAYOUT_INST36};37 38void39nvkm_subdev_intr(struct nvkm_subdev *subdev)40{41	if (subdev->func->intr)42		subdev->func->intr(subdev);43}44 45int46nvkm_subdev_info(struct nvkm_subdev *subdev, u64 mthd, u64 *data)47{48	if (subdev->func->info)49		return subdev->func->info(subdev, mthd, data);50	return -ENOSYS;51}52 53int54nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend)55{56	struct nvkm_device *device = subdev->device;57	const char *action = suspend ? "suspend" : subdev->use.enabled ? "fini" : "reset";58	s64 time;59 60	nvkm_trace(subdev, "%s running...\n", action);61	time = ktime_to_us(ktime_get());62 63	if (subdev->func->fini) {64		int ret = subdev->func->fini(subdev, suspend);65		if (ret) {66			nvkm_error(subdev, "%s failed, %d\n", action, ret);67			if (suspend)68				return ret;69		}70	}71	subdev->use.enabled = false;72 73	nvkm_mc_reset(device, subdev->type, subdev->inst);74 75	time = ktime_to_us(ktime_get()) - time;76	nvkm_trace(subdev, "%s completed in %lldus\n", action, time);77	return 0;78}79 80int81nvkm_subdev_preinit(struct nvkm_subdev *subdev)82{83	s64 time;84 85	nvkm_trace(subdev, "preinit running...\n");86	time = ktime_to_us(ktime_get());87 88	if (subdev->func->preinit) {89		int ret = subdev->func->preinit(subdev);90		if (ret) {91			nvkm_error(subdev, "preinit failed, %d\n", ret);92			return ret;93		}94	}95 96	time = ktime_to_us(ktime_get()) - time;97	nvkm_trace(subdev, "preinit completed in %lldus\n", time);98	return 0;99}100 101static int102nvkm_subdev_oneinit_(struct nvkm_subdev *subdev)103{104	s64 time;105	int ret;106 107	if (!subdev->func->oneinit || subdev->oneinit)108		return 0;109 110	nvkm_trace(subdev, "one-time init running...\n");111	time = ktime_to_us(ktime_get());112	ret = subdev->func->oneinit(subdev);113	if (ret) {114		nvkm_error(subdev, "one-time init failed, %d\n", ret);115		return ret;116	}117 118	subdev->oneinit = true;119	time = ktime_to_us(ktime_get()) - time;120	nvkm_trace(subdev, "one-time init completed in %lldus\n", time);121	return 0;122}123 124static int125nvkm_subdev_init_(struct nvkm_subdev *subdev)126{127	s64 time;128	int ret;129 130	if (subdev->use.enabled) {131		nvkm_trace(subdev, "init skipped, already running\n");132		return 0;133	}134 135	nvkm_trace(subdev, "init running...\n");136	time = ktime_to_us(ktime_get());137 138	ret = nvkm_subdev_oneinit_(subdev);139	if (ret)140		return ret;141 142	subdev->use.enabled = true;143 144	if (subdev->func->init) {145		ret = subdev->func->init(subdev);146		if (ret) {147			nvkm_error(subdev, "init failed, %d\n", ret);148			return ret;149		}150	}151 152	time = ktime_to_us(ktime_get()) - time;153	nvkm_trace(subdev, "init completed in %lldus\n", time);154	return 0;155}156 157int158nvkm_subdev_init(struct nvkm_subdev *subdev)159{160	int ret;161 162	mutex_lock(&subdev->use.mutex);163	if (refcount_read(&subdev->use.refcount) == 0) {164		nvkm_trace(subdev, "init skipped, no users\n");165		mutex_unlock(&subdev->use.mutex);166		return 0;167	}168 169	ret = nvkm_subdev_init_(subdev);170	mutex_unlock(&subdev->use.mutex);171	return ret;172}173 174int175nvkm_subdev_oneinit(struct nvkm_subdev *subdev)176{177	int ret;178 179	mutex_lock(&subdev->use.mutex);180	ret = nvkm_subdev_oneinit_(subdev);181	mutex_unlock(&subdev->use.mutex);182	return ret;183}184 185void186nvkm_subdev_unref(struct nvkm_subdev *subdev)187{188	if (refcount_dec_and_mutex_lock(&subdev->use.refcount, &subdev->use.mutex)) {189		nvkm_subdev_fini(subdev, false);190		mutex_unlock(&subdev->use.mutex);191	}192}193 194int195nvkm_subdev_ref(struct nvkm_subdev *subdev)196{197	int ret;198 199	if (subdev && !refcount_inc_not_zero(&subdev->use.refcount)) {200		mutex_lock(&subdev->use.mutex);201		if (!refcount_inc_not_zero(&subdev->use.refcount)) {202			if ((ret = nvkm_subdev_init_(subdev))) {203				mutex_unlock(&subdev->use.mutex);204				return ret;205			}206 207			refcount_set(&subdev->use.refcount, 1);208		}209		mutex_unlock(&subdev->use.mutex);210	}211 212	return 0;213}214 215void216nvkm_subdev_del(struct nvkm_subdev **psubdev)217{218	struct nvkm_subdev *subdev = *psubdev;219	s64 time;220 221	if (subdev && !WARN_ON(!subdev->func)) {222		nvkm_trace(subdev, "destroy running...\n");223		time = ktime_to_us(ktime_get());224		list_del(&subdev->head);225		if (subdev->func->dtor)226			*psubdev = subdev->func->dtor(subdev);227		mutex_destroy(&subdev->use.mutex);228		time = ktime_to_us(ktime_get()) - time;229		nvkm_trace(subdev, "destroy completed in %lldus\n", time);230		kfree(*psubdev);231		*psubdev = NULL;232	}233}234 235void236nvkm_subdev_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)237{238	struct nvkm_subdev *subdev;239	list_for_each_entry(subdev, &device->subdev, head) {240		if (subdev->type == type && subdev->inst == inst) {241			*subdev->pself = NULL;242			nvkm_subdev_del(&subdev);243			break;244		}245	}246}247 248void249__nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device,250		   enum nvkm_subdev_type type, int inst, struct nvkm_subdev *subdev)251{252	subdev->func = func;253	subdev->device = device;254	subdev->type = type;255	subdev->inst = inst < 0 ? 0 : inst;256 257	if (inst >= 0)258		snprintf(subdev->name, sizeof(subdev->name), "%s%d", nvkm_subdev_type[type], inst);259	else260		strscpy(subdev->name, nvkm_subdev_type[type], sizeof(subdev->name));261	subdev->debug = nvkm_dbgopt(device->dbgopt, subdev->name);262 263	refcount_set(&subdev->use.refcount, 1);264	list_add_tail(&subdev->head, &device->subdev);265}266 267int268nvkm_subdev_new_(const struct nvkm_subdev_func *func, struct nvkm_device *device,269		 enum nvkm_subdev_type type, int inst, struct nvkm_subdev **psubdev)270{271	if (!(*psubdev = kzalloc(sizeof(**psubdev), GFP_KERNEL)))272		return -ENOMEM;273	nvkm_subdev_ctor(func, device, type, inst, *psubdev);274	return 0;275}276