struct nvkm_device_tegra *(*tegra)(struct nvkm_device *);
void *(*dtor)(struct nvkm_device *);
int (*preinit)(struct nvkm_device *);
+ int (*init)(struct nvkm_device *);
void (*fini)(struct nvkm_device *, bool suspend);
};
resource_size_t
nv_device_resource_len(struct nvkm_device *device, unsigned int bar);
-int
-nv_device_get_irq(struct nvkm_device *device, bool stall);
-
struct platform_device;
enum nv_bus_type {
struct nvkm_device_tegra {
struct nvkm_device device;
struct platform_device *pdev;
+ int irq;
};
int nvkm_device_tegra_new(struct platform_device *,
struct nvkm_mc {
const struct nvkm_mc_func *func;
struct nvkm_subdev subdev;
-
- unsigned int irq;
- bool use_msi;
};
+void nvkm_mc_intr(struct nvkm_mc *, bool *handled);
void nvkm_mc_intr_unarm(struct nvkm_mc *);
void nvkm_mc_intr_rearm(struct nvkm_mc *);
-u32 nvkm_mc_intr_mask(struct nvkm_mc *);
void nvkm_mc_unk260(struct nvkm_mc *, u32 data);
int nv04_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
-int nv40_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
int nv44_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
-int nv4c_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
int nv50_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
-int g94_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
int g98_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
int gf100_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
-int gf106_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
int gk20a_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
#endif
struct nvkm_pci {
const struct nvkm_pci_func *func;
struct nvkm_subdev subdev;
+ struct pci_dev *pdev;
+ int irq;
+ bool msi;
};
u32 nvkm_pci_rd32(struct nvkm_pci *, u16 addr);
void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data);
void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data);
void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow);
-void nvkm_pci_msi_rearm(struct nvkm_pci *);
int nv04_pci_new(struct nvkm_device *, int, struct nvkm_pci **);
int nv40_pci_new(struct nvkm_device *, int, struct nvkm_pci **);
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv40_mc_new,
+ .mc = nv04_mc_new,
.mmu = nv04_mmu_new,
.pci = nv40_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv40_mc_new,
+ .mc = nv04_mc_new,
.mmu = nv41_mmu_new,
.pci = nv40_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv40_mc_new,
+ .mc = nv04_mc_new,
.mmu = nv41_mmu_new,
.pci = nv40_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv40_mc_new,
+ .mc = nv04_mc_new,
.mmu = nv41_mmu_new,
.pci = nv40_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv40_mc_new,
+ .mc = nv04_mc_new,
.mmu = nv04_mmu_new,
.pci = nv40_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv40_mc_new,
+ .mc = nv04_mc_new,
.mmu = nv41_mmu_new,
.pci = nv40_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv40_mc_new,
+ .mc = nv04_mc_new,
.mmu = nv41_mmu_new,
.pci = nv40_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv40_mc_new,
+ .mc = nv04_mc_new,
.mmu = nv41_mmu_new,
.pci = nv40_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv4c_mc_new,
+ .mc = nv44_mc_new,
.mmu = nv44_mmu_new,
.pci = nv4c_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv4e_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv4c_mc_new,
+ .mc = nv44_mc_new,
.mmu = nv44_mmu_new,
.pci = nv4c_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv4c_mc_new,
+ .mc = nv44_mc_new,
.mmu = nv44_mmu_new,
.pci = nv4c_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv4c_mc_new,
+ .mc = nv44_mc_new,
.mmu = nv44_mmu_new,
.pci = nv4c_pci_new,
.therm = nv40_therm_new,
.gpio = nv10_gpio_new,
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
- .mc = nv4c_mc_new,
+ .mc = nv44_mc_new,
.mmu = nv44_mmu_new,
.pci = nv4c_pci_new,
.therm = nv40_therm_new,
.gpio = g94_gpio_new,
.i2c = g94_i2c_new,
.imem = nv50_instmem_new,
- .mc = g94_mc_new,
+ .mc = nv50_mc_new,
.mmu = nv50_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.gpio = g94_gpio_new,
.i2c = g94_i2c_new,
.imem = nv50_instmem_new,
- .mc = g94_mc_new,
+ .mc = nv50_mc_new,
.mmu = nv50_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gf100_ibus_new,
.imem = nv50_instmem_new,
.ltc = gf100_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gf100_ibus_new,
.imem = nv50_instmem_new,
.ltc = gf100_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gf100_ibus_new,
.imem = nv50_instmem_new,
.ltc = gf100_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gf100_ibus_new,
.imem = nv50_instmem_new,
.ltc = gf100_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gf100_ibus_new,
.imem = nv50_instmem_new,
.ltc = gf100_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gk104_ibus_new,
.imem = nv50_instmem_new,
.ltc = gk104_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gk104_ibus_new,
.imem = nv50_instmem_new,
.ltc = gk104_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gk104_ibus_new,
.imem = nv50_instmem_new,
.ltc = gk104_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gk104_ibus_new,
.imem = nv50_instmem_new,
.ltc = gk104_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
.ibus = gk104_ibus_new,
.imem = nv50_instmem_new,
.ltc = gk104_ltc_new,
- .mc = gf106_mc_new,
+ .mc = gf100_mc_new,
.mmu = gf100_mmu_new,
.mxm = nv50_mxm_new,
.pci = nv40_pci_new,
nvdev_trace(device, "init running...\n");
time = ktime_to_us(ktime_get());
+ if (device->func->init) {
+ ret = device->func->init(device);
+ if (ret)
+ goto fail;
+ }
+
for (i = 0; i < NVKM_SUBDEV_NR; i++) {
if ((subdev = nvkm_device_subdev(device, i))) {
ret = nvkm_subdev_init(subdev);
if (ret)
- goto fail;
+ goto fail_subdev;
}
}
nvdev_trace(device, "init completed in %lldus\n", time);
return 0;
-fail:
+fail_subdev:
do {
if ((subdev = nvkm_device_subdev(device, i)))
nvkm_subdev_fini(subdev, false);
} while (--i >= 0);
+fail:
nvdev_error(device, "init failed with %d\n", ret);
return ret;
}
}
}
-int
-nv_device_get_irq(struct nvkm_device *device, bool stall)
-{
- if (nv_device_is_pci(device)) {
- return device->pdev->irq;
- } else {
- return platform_get_irq_byname(device->platformdev,
- stall ? "stall" : "nonstall");
- }
-}
-
void
nvkm_device_del(struct nvkm_device **pdevice)
{
return container_of(obj, struct nvkm_device_tegra, device);
}
+static irqreturn_t
+nvkm_device_tegra_intr(int irq, void *arg)
+{
+ struct nvkm_device_tegra *tdev = arg;
+ struct nvkm_mc *mc = tdev->device.mc;
+ bool handled = false;
+ if (likely(mc)) {
+ nvkm_mc_intr_unarm(mc);
+ nvkm_mc_intr(mc, &handled);
+ nvkm_mc_intr_rearm(mc);
+ }
+ return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void
+nvkm_device_tegra_fini(struct nvkm_device *device, bool suspend)
+{
+ struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);
+ if (tdev->irq) {
+ free_irq(tdev->irq, tdev);
+ tdev->irq = 0;
+ };
+}
+
+static int
+nvkm_device_tegra_init(struct nvkm_device *device)
+{
+ struct nvkm_device_tegra *tdev = nvkm_device_tegra(device);
+ int irq, ret;
+
+ irq = platform_get_irq_byname(tdev->pdev, "stall");
+ if (irq < 0)
+ return irq;
+
+ ret = request_irq(irq, nvkm_device_tegra_intr,
+ IRQF_SHARED, "nvkm", tdev);
+ if (ret)
+ return ret;
+
+ tdev->irq = irq;
+ return 0;
+}
+
static const struct nvkm_device_func
nvkm_device_tegra_func = {
.tegra = nvkm_device_tegra,
+ .init = nvkm_device_tegra_init,
+ .fini = nvkm_device_tegra_fini,
};
int
return -ENOMEM;
*pdevice = &tdev->device;
tdev->pdev = pdev;
+ tdev->irq = -1;
return nvkm_device_ctor(&nvkm_device_tegra_func, NULL, pdev,
NVKM_BUS_PLATFORM, pdev->id, NULL,
nvkm-y += nvkm/subdev/mc/base.o
nvkm-y += nvkm/subdev/mc/nv04.o
-nvkm-y += nvkm/subdev/mc/nv40.o
nvkm-y += nvkm/subdev/mc/nv44.o
-nvkm-y += nvkm/subdev/mc/nv4c.o
nvkm-y += nvkm/subdev/mc/nv50.o
-nvkm-y += nvkm/subdev/mc/g94.o
nvkm-y += nvkm/subdev/mc/g98.o
nvkm-y += nvkm/subdev/mc/gf100.o
-nvkm-y += nvkm/subdev/mc/gf106.o
nvkm-y += nvkm/subdev/mc/gk20a.o
return mc->func->intr_rearm(mc);
}
-u32
+static u32
nvkm_mc_intr_mask(struct nvkm_mc *mc)
{
u32 intr = mc->func->intr_mask(mc);
return intr;
}
-static irqreturn_t
-nvkm_mc_intr(int irq, void *arg)
+void
+nvkm_mc_intr(struct nvkm_mc *mc, bool *handled)
{
- struct nvkm_mc *mc = arg;
- struct nvkm_subdev *subdev = &mc->subdev;
- struct nvkm_device *device = subdev->device;
+ struct nvkm_device *device = mc->subdev.device;
+ struct nvkm_subdev *subdev;
const struct nvkm_mc_intr *map = mc->func->intr;
- struct nvkm_subdev *unit;
- u32 intr;
-
- nvkm_mc_intr_unarm(mc);
- intr = nvkm_mc_intr_mask(mc);
- if (mc->use_msi)
- mc->func->msi_rearm(mc);
-
- if (intr) {
- u32 stat = intr = nvkm_mc_intr_mask(mc);
- while (map->stat) {
- if (intr & map->stat) {
- unit = nvkm_device_subdev(device, map->unit);
- if (unit)
- nvkm_subdev_intr(unit);
- stat &= ~map->stat;
- }
- map++;
+ u32 stat, intr;
+
+ stat = intr = nvkm_mc_intr_mask(mc);
+ while (map->stat) {
+ if (intr & map->stat) {
+ subdev = nvkm_device_subdev(device, map->unit);
+ if (subdev)
+ nvkm_subdev_intr(subdev);
+ stat &= ~map->stat;
}
-
- if (stat)
- nvkm_error(subdev, "unknown intr %08x\n", stat);
+ map++;
}
- nvkm_mc_intr_rearm(mc);
- return intr ? IRQ_HANDLED : IRQ_NONE;
+ if (stat)
+ nvkm_error(&mc->subdev, "intr %08x\n", stat);
+ *handled = intr != 0;
}
static int
return 0;
}
-static int
-nvkm_mc_oneinit(struct nvkm_subdev *subdev)
-{
- struct nvkm_mc *mc = nvkm_mc(subdev);
- return request_irq(mc->irq, nvkm_mc_intr, IRQF_SHARED, "nvkm", mc);
-}
-
static int
nvkm_mc_init(struct nvkm_subdev *subdev)
{
static void *
nvkm_mc_dtor(struct nvkm_subdev *subdev)
{
- struct nvkm_mc *mc = nvkm_mc(subdev);
- struct nvkm_device *device = mc->subdev.device;
- free_irq(mc->irq, mc);
- if (mc->use_msi)
- pci_disable_msi(device->pdev);
- return mc;
+ return nvkm_mc(subdev);
}
static const struct nvkm_subdev_func
nvkm_mc = {
.dtor = nvkm_mc_dtor,
- .oneinit = nvkm_mc_oneinit,
.init = nvkm_mc_init,
.fini = nvkm_mc_fini,
};
int index, struct nvkm_mc **pmc)
{
struct nvkm_mc *mc;
- int ret;
if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL)))
return -ENOMEM;
nvkm_subdev_ctor(&nvkm_mc, device, index, 0, &mc->subdev);
mc->func = func;
-
- if (nv_device_is_pci(device)) {
- switch (device->pdev->device & 0x0ff0) {
- case 0x00f0:
- case 0x02e0:
- /* BR02? NFI how these would be handled yet exactly */
- break;
- default:
- switch (device->chipset) {
- case 0xaa:
- /* reported broken, nv also disable it */
- break;
- default:
- mc->use_msi = true;
- break;
- }
- }
-
- mc->use_msi = nvkm_boolopt(device->cfgopt, "NvMSI",
- mc->use_msi);
-
- if (mc->use_msi && mc->func->msi_rearm) {
- mc->use_msi = pci_enable_msi(device->pdev) == 0;
- if (mc->use_msi) {
- nvkm_debug(&mc->subdev, "MSI enabled\n");
- mc->func->msi_rearm(mc);
- }
- } else {
- mc->use_msi = false;
- }
- }
-
- ret = nv_device_get_irq(device, true);
- if (ret < 0)
- return ret;
- mc->irq = ret;
return 0;
}
+++ /dev/null
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-#include "priv.h"
-
-static const struct nvkm_mc_func
-g94_mc = {
- .init = nv50_mc_init,
- .intr = nv50_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_mask = nv04_mc_intr_mask,
- .msi_rearm = nv40_mc_msi_rearm,
-};
-
-int
-g94_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc)
-{
- return nvkm_mc_new_(&g94_mc, device, index, pmc);
-}
.intr_unarm = nv04_mc_intr_unarm,
.intr_rearm = nv04_mc_intr_rearm,
.intr_mask = nv04_mc_intr_mask,
- .msi_rearm = nv40_mc_msi_rearm,
};
int
return intr0 | intr1;
}
-static void
-gf100_mc_msi_rearm(struct nvkm_mc *mc)
-{
- nvkm_wr32(mc->subdev.device, 0x088704, 0x00000000);
-}
-
void
gf100_mc_unk260(struct nvkm_mc *mc, u32 data)
{
.intr_unarm = gf100_mc_intr_unarm,
.intr_rearm = gf100_mc_intr_rearm,
.intr_mask = gf100_mc_intr_mask,
- .msi_rearm = gf100_mc_msi_rearm,
.unk260 = gf100_mc_unk260,
};
+++ /dev/null
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-#include "priv.h"
-
-static const struct nvkm_mc_func
-gf106_mc = {
- .init = nv50_mc_init,
- .intr = gf100_mc_intr,
- .intr_unarm = gf100_mc_intr_unarm,
- .intr_rearm = gf100_mc_intr_rearm,
- .intr_mask = gf100_mc_intr_mask,
- .msi_rearm = nv40_mc_msi_rearm,
- .unk260 = gf100_mc_unk260,
-};
-
-int
-gf106_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc)
-{
- return nvkm_mc_new_(&gf106_mc, device, index, pmc);
-}
.intr_unarm = gf100_mc_intr_unarm,
.intr_rearm = gf100_mc_intr_rearm,
.intr_mask = gf100_mc_intr_mask,
- .msi_rearm = nv40_mc_msi_rearm,
};
int
+++ /dev/null
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-#include "priv.h"
-
-void
-nv40_mc_msi_rearm(struct nvkm_mc *mc)
-{
- nvkm_wr08(mc->subdev.device, 0x088068, 0xff);
-}
-
-static const struct nvkm_mc_func
-nv40_mc = {
- .init = nv04_mc_init,
- .intr = nv04_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_mask = nv04_mc_intr_mask,
- .msi_rearm = nv40_mc_msi_rearm,
-};
-
-int
-nv40_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc)
-{
- return nvkm_mc_new_(&nv40_mc, device, index, pmc);
-}
.intr_unarm = nv04_mc_intr_unarm,
.intr_rearm = nv04_mc_intr_rearm,
.intr_mask = nv04_mc_intr_mask,
- .msi_rearm = nv40_mc_msi_rearm,
};
int
+++ /dev/null
-/*
- * Copyright 2014 Ilia Mirkin
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ilia Mirkin
- */
-#include "priv.h"
-
-static const struct nvkm_mc_func
-nv4c_mc = {
- .init = nv44_mc_init,
- .intr = nv04_mc_intr,
- .intr_unarm = nv04_mc_intr_unarm,
- .intr_rearm = nv04_mc_intr_rearm,
- .intr_mask = nv04_mc_intr_mask,
-};
-
-int
-nv4c_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc)
-{
- return nvkm_mc_new_(&nv4c_mc, device, index, pmc);
-}
{},
};
-static void
-nv50_mc_msi_rearm(struct nvkm_mc *mc)
-{
- struct nvkm_device *device = mc->subdev.device;
- pci_write_config_byte(device->pdev, 0x68, 0xff);
-}
-
void
nv50_mc_init(struct nvkm_mc *mc)
{
.intr_unarm = nv04_mc_intr_unarm,
.intr_rearm = nv04_mc_intr_rearm,
.intr_mask = nv04_mc_intr_mask,
- .msi_rearm = nv50_mc_msi_rearm,
};
int
void (*intr_rearm)(struct nvkm_mc *);
/* retrieve pending interrupt mask (NV_PMC_INTR) */
u32 (*intr_mask)(struct nvkm_mc *);
- void (*msi_rearm)(struct nvkm_mc *);
void (*unk260)(struct nvkm_mc *, u32);
};
void nv04_mc_intr_rearm(struct nvkm_mc *);
u32 nv04_mc_intr_mask(struct nvkm_mc *);
-void nv40_mc_msi_rearm(struct nvkm_mc *);
-
void nv44_mc_init(struct nvkm_mc *);
void nv50_mc_init(struct nvkm_mc *);
*/
#include "priv.h"
+#include <core/option.h>
+#include <core/pci.h>
+#include <subdev/mc.h>
+
u32
nvkm_pci_rd32(struct nvkm_pci *pci, u16 addr)
{
nvkm_pci_wr32(pci, 0x0050, data);
}
-void
-nvkm_pci_msi_rearm(struct nvkm_pci *pci)
+static irqreturn_t
+nvkm_pci_intr(int irq, void *arg)
+{
+ struct nvkm_pci *pci = arg;
+ struct nvkm_mc *mc = pci->subdev.device->mc;
+ bool handled = false;
+ if (likely(mc)) {
+ nvkm_mc_intr_unarm(mc);
+ if (pci->msi)
+ pci->func->msi_rearm(pci);
+ nvkm_mc_intr(mc, &handled);
+ nvkm_mc_intr_rearm(mc);
+ }
+ return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int
+nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend)
{
- pci->func->msi_rearm(pci);
+ struct nvkm_pci *pci = nvkm_pci(subdev);
+ if (pci->irq >= 0) {
+ free_irq(pci->irq, pci);
+ pci->irq = -1;
+ };
+ return 0;
+}
+
+static int
+nvkm_pci_init(struct nvkm_subdev *subdev)
+{
+ struct nvkm_pci *pci = nvkm_pci(subdev);
+ struct pci_dev *pdev = pci->pdev;
+ int ret;
+
+ ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci);
+ if (ret)
+ return ret;
+
+ pci->irq = pdev->irq;
+ return ret;
}
static void *
nvkm_pci_dtor(struct nvkm_subdev *subdev)
{
+ struct nvkm_pci *pci = nvkm_pci(subdev);
+ if (pci->msi)
+ pci_disable_msi(pci->pdev);
return nvkm_pci(subdev);
}
static const struct nvkm_subdev_func
nvkm_pci_func = {
.dtor = nvkm_pci_dtor,
+ .init = nvkm_pci_init,
+ .fini = nvkm_pci_fini,
};
int
int index, struct nvkm_pci **ppci)
{
struct nvkm_pci *pci;
+
if (!(pci = *ppci = kzalloc(sizeof(**ppci), GFP_KERNEL)))
return -ENOMEM;
nvkm_subdev_ctor(&nvkm_pci_func, device, index, 0, &pci->subdev);
pci->func = func;
+ pci->pdev = device->func->pci(device)->pdev;
+ pci->irq = -1;
+
+ switch (pci->pdev->device & 0x0ff0) {
+ case 0x00f0:
+ case 0x02e0:
+ /* BR02? NFI how these would be handled yet exactly */
+ break;
+ default:
+ switch (device->chipset) {
+ case 0xaa:
+ /* reported broken, nv also disable it */
+ break;
+ default:
+ pci->msi = true;
+ break;
+ }
+ }
+
+ pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi);
+ if (pci->msi && func->msi_rearm) {
+ pci->msi = pci_enable_msi(pci->pdev) == 0;
+ if (pci->msi)
+ nvkm_debug(&pci->subdev, "MSI enabled\n");
+ } else {
+ pci->msi = false;
+ }
+
return 0;
}