Commit 0fa9061a authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/mc: handle irq-related setup ourselves

We need to be able to process interrupts before the DRM code is able to
actually enable them, set it up ourselves.  Also, it's less convoluted
to *not* use the DRM wrappers it appears...
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 1a646342
......@@ -213,7 +213,7 @@ nouveau-y += core/engine/vp/nve0.o
# drm/core
nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
nouveau-y += nouveau_irq.o nouveau_vga.o nouveau_agp.o
nouveau-y += nouveau_vga.o nouveau_agp.o
nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
nouveau-y += nouveau_prime.o nouveau_abi16.o
nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o
......
......@@ -21,18 +21,22 @@ nouveau_mc(void *obj)
}
#define nouveau_mc_create(p,e,o,d) \
nouveau_subdev_create_((p), (e), (o), 0, "PMC", "master", \
sizeof(**d), (void **)d)
#define nouveau_mc_destroy(p) \
nouveau_subdev_destroy(&(p)->base)
#define nouveau_mc_init(p) \
nouveau_subdev_init(&(p)->base)
#define nouveau_mc_fini(p,s) \
nouveau_subdev_fini(&(p)->base, (s))
#define _nouveau_mc_dtor _nouveau_subdev_dtor
#define _nouveau_mc_init _nouveau_subdev_init
#define _nouveau_mc_fini _nouveau_subdev_fini
nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d)
#define nouveau_mc_destroy(p) ({ \
struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc)); \
})
#define nouveau_mc_init(p) ({ \
struct nouveau_mc *pmc = (p); _nouveau_mc_init(nv_object(pmc)); \
})
#define nouveau_mc_fini(p,s) ({ \
struct nouveau_mc *pmc = (p); _nouveau_mc_fini(nv_object(pmc), (s)); \
})
int nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int, void **);
void _nouveau_mc_dtor(struct nouveau_object *);
int _nouveau_mc_init(struct nouveau_object *);
int _nouveau_mc_fini(struct nouveau_object *, bool);
extern struct nouveau_oclass nv04_mc_oclass;
extern struct nouveau_oclass nv44_mc_oclass;
......@@ -40,8 +44,6 @@ extern struct nouveau_oclass nv50_mc_oclass;
extern struct nouveau_oclass nv98_mc_oclass;
extern struct nouveau_oclass nvc0_mc_oclass;
void nouveau_mc_intr(struct nouveau_subdev *);
extern const struct nouveau_mc_intr nv04_mc_intr[];
int nv04_mc_init(struct nouveau_object *);
int nv50_mc_init(struct nouveau_object *);
......
......@@ -17,6 +17,7 @@
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/reboot.h>
#include <linux/interrupt.h>
#include <asm/unaligned.h>
......
......@@ -24,10 +24,10 @@
#include <subdev/mc.h>
void
nouveau_mc_intr(struct nouveau_subdev *subdev)
static irqreturn_t
nouveau_mc_intr(int irq, void *arg)
{
struct nouveau_mc *pmc = nouveau_mc(subdev);
struct nouveau_mc *pmc = arg;
const struct nouveau_mc_intr *map = pmc->intr_map;
struct nouveau_subdev *unit;
u32 stat, intr;
......@@ -35,7 +35,7 @@ nouveau_mc_intr(struct nouveau_subdev *subdev)
intr = stat = nv_rd32(pmc, 0x000100);
while (stat && map->stat) {
if (stat & map->stat) {
unit = nouveau_subdev(subdev, map->unit);
unit = nouveau_subdev(pmc, map->unit);
if (unit && unit->intr)
unit->intr(unit);
intr &= ~map->stat;
......@@ -46,4 +46,56 @@ nouveau_mc_intr(struct nouveau_subdev *subdev)
if (intr) {
nv_error(pmc, "unknown intr 0x%08x\n", stat);
}
return stat ? IRQ_HANDLED : IRQ_NONE;
}
int
_nouveau_mc_fini(struct nouveau_object *object, bool suspend)
{
struct nouveau_mc *pmc = (void *)object;
nv_wr32(pmc, 0x000140, 0x00000000);
return nouveau_subdev_fini(&pmc->base, suspend);
}
int
_nouveau_mc_init(struct nouveau_object *object)
{
struct nouveau_mc *pmc = (void *)object;
int ret = nouveau_subdev_init(&pmc->base);
if (ret)
return ret;
nv_wr32(pmc, 0x000140, 0x00000001);
return 0;
}
void
_nouveau_mc_dtor(struct nouveau_object *object)
{
struct nouveau_device *device = nv_device(object);
struct nouveau_mc *pmc = (void *)object;
free_irq(device->pdev->irq, pmc);
nouveau_subdev_destroy(&pmc->base);
}
int
nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, int length, void **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nouveau_mc *pmc;
int ret;
ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PMC",
"master", length, pobject);
pmc = *pobject;
if (ret)
return ret;
ret = request_irq(device->pdev->irq, nouveau_mc_intr,
IRQF_SHARED, "nouveau", pmc);
if (ret < 0)
return ret;
return 0;
}
......@@ -55,7 +55,6 @@ nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
nv_subdev(priv)->intr = nouveau_mc_intr;
priv->base.intr_map = nv04_mc_intr;
return 0;
}
......
......@@ -41,7 +41,6 @@ nv44_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
nv_subdev(priv)->intr = nouveau_mc_intr;
priv->base.intr_map = nv04_mc_intr;
return 0;
}
......
......@@ -57,7 +57,6 @@ nv50_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
nv_subdev(priv)->intr = nouveau_mc_intr;
priv->base.intr_map = nv50_mc_intr;
return 0;
}
......
......@@ -59,7 +59,6 @@ nv98_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
nv_subdev(priv)->intr = nouveau_mc_intr;
priv->base.intr_map = nv98_mc_intr;
return 0;
}
......
......@@ -61,7 +61,6 @@ nvc0_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
nv_subdev(priv)->intr = nouveau_mc_intr;
priv->base.intr_map = nvc0_mc_intr;
return 0;
}
......
......@@ -37,7 +37,6 @@
#include <engine/disp.h>
#include "nouveau_drm.h"
#include "nouveau_irq.h"
#include "nouveau_dma.h"
#include "nouveau_ttm.h"
#include "nouveau_gem.h"
......@@ -365,10 +364,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
if (ret)
goto fail_bios;
ret = nouveau_irq_init(dev);
if (ret)
goto fail_irq;
ret = nouveau_display_create(dev);
if (ret)
goto fail_dispctor;
......@@ -388,8 +383,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
fail_dispinit:
nouveau_display_destroy(dev);
fail_dispctor:
nouveau_irq_fini(dev);
fail_irq:
nouveau_bios_takedown(dev);
fail_bios:
nouveau_ttm_fini(drm);
......@@ -415,7 +408,6 @@ nouveau_drm_unload(struct drm_device *dev)
nouveau_display_fini(dev);
nouveau_display_destroy(dev);
nouveau_irq_fini(dev);
nouveau_bios_takedown(dev);
nouveau_ttm_fini(drm);
......@@ -533,7 +525,6 @@ nouveau_do_resume(struct drm_device *dev)
nouveau_fence(drm)->resume(drm);
nouveau_run_vbios_init(dev);
nouveau_irq_postinstall(dev);
nouveau_pm_resume(dev);
if (dev->mode_config.num_crtc) {
......@@ -669,8 +660,7 @@ static struct drm_driver
driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
DRIVER_MODESET | DRIVER_PRIME,
DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME,
.load = nouveau_drm_load,
.unload = nouveau_drm_unload,
......@@ -684,11 +674,6 @@ driver = {
.debugfs_cleanup = nouveau_debugfs_takedown,
#endif
.irq_preinstall = nouveau_irq_preinstall,
.irq_postinstall = nouveau_irq_postinstall,
.irq_uninstall = nouveau_irq_uninstall,
.irq_handler = nouveau_irq_handler,
.get_vblank_counter = drm_vblank_count,
.enable_vblank = nouveau_drm_vblank_enable,
.disable_vblank = nouveau_drm_vblank_disable,
......
/*
* 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 <subdev/mc.h>
#include "nouveau_drm.h"
#include "nouveau_irq.h"
#include "nv50_display.h"
void
nouveau_irq_preinstall(struct drm_device *dev)
{
nv_wr32(nouveau_dev(dev), 0x000140, 0x00000000);
}
int
nouveau_irq_postinstall(struct drm_device *dev)
{
nv_wr32(nouveau_dev(dev), 0x000140, 0x00000001);
return 0;
}
void
nouveau_irq_uninstall(struct drm_device *dev)
{
nv_wr32(nouveau_dev(dev), 0x000140, 0x00000000);
}
irqreturn_t
nouveau_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = arg;
struct nouveau_device *device = nouveau_dev(dev);
struct nouveau_mc *pmc = nouveau_mc(device);
u32 stat;
stat = nv_rd32(device, 0x000100);
if (stat == 0 || stat == ~0)
return IRQ_NONE;
nv_subdev(pmc)->intr(nv_subdev(pmc));
return IRQ_HANDLED;
}
int
nouveau_irq_init(struct drm_device *dev)
{
return drm_irq_install(dev);
}
void
nouveau_irq_fini(struct drm_device *dev)
{
drm_irq_uninstall(dev);
}
#ifndef __NOUVEAU_IRQ_H__
#define __NOUVEAU_IRQ_H__
extern int nouveau_irq_init(struct drm_device *);
extern void nouveau_irq_fini(struct drm_device *);
extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS);
extern void nouveau_irq_preinstall(struct drm_device *);
extern int nouveau_irq_postinstall(struct drm_device *);
extern void nouveau_irq_uninstall(struct drm_device *);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment