Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs
0023  */
0024 #include "priv.h"
0025 
0026 #include <core/option.h>
0027 #include <subdev/top.h>
0028 
0029 void
0030 nvkm_mc_unk260(struct nvkm_device *device, u32 data)
0031 {
0032     struct nvkm_mc *mc = device->mc;
0033     if (likely(mc) && mc->func->unk260)
0034         mc->func->unk260(mc, data);
0035 }
0036 
0037 void
0038 nvkm_mc_intr_mask(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, bool en)
0039 {
0040     struct nvkm_mc *mc = device->mc;
0041     const struct nvkm_mc_map *map;
0042     if (likely(mc) && mc->func->intr_mask) {
0043         u32 mask = nvkm_top_intr_mask(device, type, inst);
0044         for (map = mc->func->intr; !mask && map->stat; map++) {
0045             if (map->type == type && map->inst == inst)
0046                 mask = map->stat;
0047         }
0048         mc->func->intr_mask(mc, mask, en ? mask : 0);
0049     }
0050 }
0051 
0052 void
0053 nvkm_mc_intr_unarm(struct nvkm_device *device)
0054 {
0055     struct nvkm_mc *mc = device->mc;
0056     if (likely(mc))
0057         mc->func->intr_unarm(mc);
0058 }
0059 
0060 void
0061 nvkm_mc_intr_rearm(struct nvkm_device *device)
0062 {
0063     struct nvkm_mc *mc = device->mc;
0064     if (likely(mc))
0065         mc->func->intr_rearm(mc);
0066 }
0067 
0068 static u32
0069 nvkm_mc_intr_stat(struct nvkm_mc *mc)
0070 {
0071     u32 intr = mc->func->intr_stat(mc);
0072     if (WARN_ON_ONCE(intr == 0xffffffff))
0073         intr = 0; /* likely fallen off the bus */
0074     return intr;
0075 }
0076 
0077 void
0078 nvkm_mc_intr(struct nvkm_device *device, bool *handled)
0079 {
0080     struct nvkm_mc *mc = device->mc;
0081     struct nvkm_top *top = device->top;
0082     struct nvkm_top_device *tdev;
0083     struct nvkm_subdev *subdev;
0084     const struct nvkm_mc_map *map;
0085     u32 stat, intr;
0086 
0087     if (unlikely(!mc))
0088         return;
0089 
0090     stat = intr = nvkm_mc_intr_stat(mc);
0091 
0092     if (top) {
0093         list_for_each_entry(tdev, &top->device, head) {
0094             if (tdev->intr >= 0 && (stat & BIT(tdev->intr))) {
0095                 subdev = nvkm_device_subdev(device, tdev->type, tdev->inst);
0096                 if (subdev) {
0097                     nvkm_subdev_intr(subdev);
0098                     stat &= ~BIT(tdev->intr);
0099                     if (!stat)
0100                         break;
0101                 }
0102             }
0103         }
0104     }
0105 
0106     for (map = mc->func->intr; map->stat; map++) {
0107         if (intr & map->stat) {
0108             subdev = nvkm_device_subdev(device, map->type, map->inst);
0109             if (subdev)
0110                 nvkm_subdev_intr(subdev);
0111             stat &= ~map->stat;
0112         }
0113     }
0114 
0115     if (stat)
0116         nvkm_error(&mc->subdev, "intr %08x\n", stat);
0117     *handled = intr != 0;
0118 }
0119 
0120 static u32
0121 nvkm_mc_reset_mask(struct nvkm_device *device, bool isauto, enum nvkm_subdev_type type, int inst)
0122 {
0123     struct nvkm_mc *mc = device->mc;
0124     const struct nvkm_mc_map *map;
0125     u64 pmc_enable = 0;
0126     if (likely(mc)) {
0127         if (!(pmc_enable = nvkm_top_reset(device, type, inst))) {
0128             for (map = mc->func->reset; map && map->stat; map++) {
0129                 if (!isauto || !map->noauto) {
0130                     if (map->type == type && map->inst == inst) {
0131                         pmc_enable = map->stat;
0132                         break;
0133                     }
0134                 }
0135             }
0136         }
0137     }
0138     return pmc_enable;
0139 }
0140 
0141 void
0142 nvkm_mc_reset(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
0143 {
0144     u64 pmc_enable = nvkm_mc_reset_mask(device, true, type, inst);
0145     if (pmc_enable) {
0146         nvkm_mask(device, 0x000200, pmc_enable, 0x00000000);
0147         nvkm_mask(device, 0x000200, pmc_enable, pmc_enable);
0148         nvkm_rd32(device, 0x000200);
0149     }
0150 }
0151 
0152 void
0153 nvkm_mc_disable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
0154 {
0155     u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst);
0156     if (pmc_enable)
0157         nvkm_mask(device, 0x000200, pmc_enable, 0x00000000);
0158 }
0159 
0160 void
0161 nvkm_mc_enable(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
0162 {
0163     u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst);
0164     if (pmc_enable) {
0165         nvkm_mask(device, 0x000200, pmc_enable, pmc_enable);
0166         nvkm_rd32(device, 0x000200);
0167     }
0168 }
0169 
0170 bool
0171 nvkm_mc_enabled(struct nvkm_device *device, enum nvkm_subdev_type type, int inst)
0172 {
0173     u64 pmc_enable = nvkm_mc_reset_mask(device, false, type, inst);
0174 
0175     return (pmc_enable != 0) &&
0176            ((nvkm_rd32(device, 0x000200) & pmc_enable) == pmc_enable);
0177 }
0178 
0179 
0180 static int
0181 nvkm_mc_fini(struct nvkm_subdev *subdev, bool suspend)
0182 {
0183     nvkm_mc_intr_unarm(subdev->device);
0184     return 0;
0185 }
0186 
0187 static int
0188 nvkm_mc_init(struct nvkm_subdev *subdev)
0189 {
0190     struct nvkm_mc *mc = nvkm_mc(subdev);
0191     if (mc->func->init)
0192         mc->func->init(mc);
0193     nvkm_mc_intr_rearm(subdev->device);
0194     return 0;
0195 }
0196 
0197 static void *
0198 nvkm_mc_dtor(struct nvkm_subdev *subdev)
0199 {
0200     return nvkm_mc(subdev);
0201 }
0202 
0203 static const struct nvkm_subdev_func
0204 nvkm_mc = {
0205     .dtor = nvkm_mc_dtor,
0206     .init = nvkm_mc_init,
0207     .fini = nvkm_mc_fini,
0208 };
0209 
0210 void
0211 nvkm_mc_ctor(const struct nvkm_mc_func *func, struct nvkm_device *device,
0212          enum nvkm_subdev_type type, int inst, struct nvkm_mc *mc)
0213 {
0214     nvkm_subdev_ctor(&nvkm_mc, device, type, inst, &mc->subdev);
0215     mc->func = func;
0216 }
0217 
0218 int
0219 nvkm_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device,
0220          enum nvkm_subdev_type type, int inst, struct nvkm_mc **pmc)
0221 {
0222     struct nvkm_mc *mc;
0223     if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL)))
0224         return -ENOMEM;
0225     nvkm_mc_ctor(func, device, type, inst, *pmc);
0226     return 0;
0227 }