linux/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
<<
>>
Prefs
   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#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_ONCE
  35#undef NVKM_LAYOUT_INST
  36};
  37
  38void
  39nvkm_subdev_intr(struct nvkm_subdev *subdev)
  40{
  41        if (subdev->func->intr)
  42                subdev->func->intr(subdev);
  43}
  44
  45int
  46nvkm_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
  53int
  54nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend)
  55{
  56        struct nvkm_device *device = subdev->device;
  57        const char *action = suspend ? "suspend" : "fini";
  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
  72        nvkm_mc_reset(device, subdev->type, subdev->inst);
  73
  74        time = ktime_to_us(ktime_get()) - time;
  75        nvkm_trace(subdev, "%s completed in %lldus\n", action, time);
  76        return 0;
  77}
  78
  79int
  80nvkm_subdev_preinit(struct nvkm_subdev *subdev)
  81{
  82        s64 time;
  83
  84        nvkm_trace(subdev, "preinit running...\n");
  85        time = ktime_to_us(ktime_get());
  86
  87        if (subdev->func->preinit) {
  88                int ret = subdev->func->preinit(subdev);
  89                if (ret) {
  90                        nvkm_error(subdev, "preinit failed, %d\n", ret);
  91                        return ret;
  92                }
  93        }
  94
  95        time = ktime_to_us(ktime_get()) - time;
  96        nvkm_trace(subdev, "preinit completed in %lldus\n", time);
  97        return 0;
  98}
  99
 100int
 101nvkm_subdev_init(struct nvkm_subdev *subdev)
 102{
 103        s64 time;
 104        int ret;
 105
 106        nvkm_trace(subdev, "init running...\n");
 107        time = ktime_to_us(ktime_get());
 108
 109        if (subdev->func->oneinit && !subdev->oneinit) {
 110                s64 time;
 111                nvkm_trace(subdev, "one-time init running...\n");
 112                time = ktime_to_us(ktime_get());
 113                ret = subdev->func->oneinit(subdev);
 114                if (ret) {
 115                        nvkm_error(subdev, "one-time init failed, %d\n", ret);
 116                        return ret;
 117                }
 118
 119                subdev->oneinit = true;
 120                time = ktime_to_us(ktime_get()) - time;
 121                nvkm_trace(subdev, "one-time init completed in %lldus\n", time);
 122        }
 123
 124        if (subdev->func->init) {
 125                ret = subdev->func->init(subdev);
 126                if (ret) {
 127                        nvkm_error(subdev, "init failed, %d\n", ret);
 128                        return ret;
 129                }
 130        }
 131
 132        time = ktime_to_us(ktime_get()) - time;
 133        nvkm_trace(subdev, "init completed in %lldus\n", time);
 134        return 0;
 135}
 136
 137void
 138nvkm_subdev_del(struct nvkm_subdev **psubdev)
 139{
 140        struct nvkm_subdev *subdev = *psubdev;
 141        s64 time;
 142
 143        if (subdev && !WARN_ON(!subdev->func)) {
 144                nvkm_trace(subdev, "destroy running...\n");
 145                time = ktime_to_us(ktime_get());
 146                list_del(&subdev->head);
 147                if (subdev->func->dtor)
 148                        *psubdev = subdev->func->dtor(subdev);
 149                time = ktime_to_us(ktime_get()) - time;
 150                nvkm_trace(subdev, "destroy completed in %lldus\n", time);
 151                kfree(*psubdev);
 152                *psubdev = NULL;
 153        }
 154}
 155
 156void
 157nvkm_subdev_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
 158{
 159        struct nvkm_subdev *subdev;
 160        list_for_each_entry(subdev, &device->subdev, head) {
 161                if (subdev->type == type && subdev->inst == inst) {
 162                        *subdev->pself = NULL;
 163                        nvkm_subdev_del(&subdev);
 164                        break;
 165                }
 166        }
 167}
 168
 169void
 170nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device,
 171                 enum nvkm_subdev_type type, int inst, struct nvkm_subdev *subdev)
 172{
 173        subdev->func = func;
 174        subdev->device = device;
 175        subdev->type = type;
 176        subdev->inst = inst < 0 ? 0 : inst;
 177
 178        if (inst >= 0)
 179                snprintf(subdev->name, sizeof(subdev->name), "%s%d", nvkm_subdev_type[type], inst);
 180        else
 181                strscpy(subdev->name, nvkm_subdev_type[type], sizeof(subdev->name));
 182        subdev->debug = nvkm_dbgopt(device->dbgopt, subdev->name);
 183        list_add_tail(&subdev->head, &device->subdev);
 184}
 185
 186int
 187nvkm_subdev_new_(const struct nvkm_subdev_func *func, struct nvkm_device *device,
 188                 enum nvkm_subdev_type type, int inst, struct nvkm_subdev **psubdev)
 189{
 190        if (!(*psubdev = kzalloc(sizeof(**psubdev), GFP_KERNEL)))
 191                return -ENOMEM;
 192        nvkm_subdev_ctor(func, device, type, inst, *psubdev);
 193        return 0;
 194}
 195