Commit 3b330f08 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/sec2: unload RTOS before tearing down WPR

Reset regs won't be available on Ampere while SEC2 RTOS is running, and
we're apparently supposed to be doing this on earlier GPUs too.

v2:
- fixed some excessive indentation
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
parent a9d90860
......@@ -10,6 +10,7 @@ struct nv_sec2_args {
};
#define NV_SEC2_UNIT_INIT 0x01
#define NV_SEC2_UNIT_UNLOAD 0x06
#define NV_SEC2_UNIT_ACR 0x08
struct nv_sec2_init_msg {
......@@ -57,4 +58,8 @@ struct nv_sec2_acr_bootstrap_falcon_msg {
u32 error_code;
u32 falcon_id;
};
#define NV_SEC2_UNIT_V2_INIT 0x01
#define NV_SEC2_UNIT_V2_UNLOAD 0x05
#define NV_SEC2_UNIT_V2_ACR 0x07
#endif
......@@ -72,6 +72,7 @@ int nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *, const char *name,
void nvkm_falcon_msgq_del(struct nvkm_falcon_msgq **);
void nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *,
u32 index, u32 offset, u32 size);
bool nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *);
int nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *, void *, u32 size);
void nvkm_falcon_msgq_recv(struct nvkm_falcon_msgq *);
#endif
......@@ -10,12 +10,14 @@ struct nvkm_sec2 {
struct nvkm_engine engine;
struct nvkm_falcon falcon;
atomic_t running;
atomic_t initmsg;
struct nvkm_falcon_qmgr *qmgr;
struct nvkm_falcon_cmdq *cmdq;
struct nvkm_falcon_msgq *msgq;
struct work_struct work;
bool initmsg_received;
};
int gp102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
......
......@@ -109,7 +109,6 @@ struct nvkm_acr_lsf_func {
u32 bld_size;
void (*bld_write)(struct nvkm_acr *, u32 bld, struct nvkm_acr_lsfw *);
void (*bld_patch)(struct nvkm_acr *, u32 bld, s64 adjust);
int (*boot)(struct nvkm_falcon *);
u64 bootstrap_falcons;
int (*bootstrap_falcon)(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
int (*bootstrap_multiple_falcons)(struct nvkm_falcon *, u32 mask);
......
......@@ -22,25 +22,17 @@
#include "priv.h"
#include <core/firmware.h>
#include <subdev/top.h>
#include <subdev/timer.h>
static void
nvkm_sec2_recv(struct work_struct *work)
{
struct nvkm_sec2 *sec2 = container_of(work, typeof(*sec2), work);
if (!sec2->initmsg_received) {
int ret = sec2->func->initmsg(sec2);
if (ret) {
nvkm_error(&sec2->engine.subdev,
"error parsing init message: %d\n", ret);
return;
}
#include <nvfw/sec2.h>
sec2->initmsg_received = true;
}
static int
nvkm_sec2_finimsg(void *priv, struct nvfw_falcon_msg *hdr)
{
struct nvkm_sec2 *sec2 = priv;
nvkm_falcon_msgq_recv(sec2->msgq);
atomic_set(&sec2->running, 0);
return 0;
}
static void
......@@ -54,14 +46,52 @@ static int
nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend)
{
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
struct nvkm_subdev *subdev = &sec2->engine.subdev;
struct nvkm_falcon *falcon = &sec2->falcon;
struct nvkm_falcon_cmdq *cmdq = sec2->cmdq;
struct nvfw_falcon_cmd cmd = {
.unit_id = sec2->func->unit_unload,
.size = sizeof(cmd),
};
int ret;
if (!subdev->use.enabled)
return 0;
flush_work(&sec2->work);
if (atomic_read(&sec2->initmsg) == 1) {
ret = nvkm_falcon_cmdq_send(cmdq, &cmd, nvkm_sec2_finimsg, sec2,
msecs_to_jiffies(1000));
WARN_ON(ret);
if (suspend) {
nvkm_falcon_cmdq_fini(sec2->cmdq);
sec2->initmsg_received = false;
nvkm_msec(subdev->device, 2000,
if (nvkm_falcon_rd32(falcon, 0x100) & 0x00000010)
break;
);
}
nvkm_falcon_cmdq_fini(cmdq);
falcon->func->disable(falcon);
nvkm_falcon_put(falcon, subdev);
return 0;
}
static int
nvkm_sec2_init(struct nvkm_engine *engine)
{
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
struct nvkm_subdev *subdev = &sec2->engine.subdev;
struct nvkm_falcon *falcon = &sec2->falcon;
int ret;
ret = nvkm_falcon_get(falcon, subdev);
if (ret)
return ret;
nvkm_falcon_wr32(falcon, 0x014, 0xffffffff);
atomic_set(&sec2->initmsg, 0);
atomic_set(&sec2->running, 1);
nvkm_falcon_start(falcon);
return 0;
}
......@@ -69,6 +99,7 @@ static void *
nvkm_sec2_dtor(struct nvkm_engine *engine)
{
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
nvkm_falcon_msgq_del(&sec2->msgq);
nvkm_falcon_cmdq_del(&sec2->cmdq);
nvkm_falcon_qmgr_del(&sec2->qmgr);
......@@ -79,6 +110,7 @@ nvkm_sec2_dtor(struct nvkm_engine *engine)
static const struct nvkm_engine_func
nvkm_sec2 = {
.dtor = nvkm_sec2_dtor,
.init = nvkm_sec2_init,
.fini = nvkm_sec2_fini,
.intr = nvkm_sec2_intr,
};
......@@ -113,6 +145,5 @@ nvkm_sec2_new_(const struct nvkm_sec2_fwif *fwif, struct nvkm_device *device,
(ret = nvkm_falcon_msgq_new(sec2->qmgr, "msgq", &sec2->msgq)))
return ret;
INIT_WORK(&sec2->work, nvkm_sec2_recv);
return 0;
};
......@@ -74,16 +74,6 @@ gp102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon,
msecs_to_jiffies(1000));
}
static int
gp102_sec2_acr_boot(struct nvkm_falcon *falcon)
{
struct nv_sec2_args args = {};
nvkm_falcon_load_dmem(falcon, &args,
falcon->func->emem_addr, sizeof(args), 0);
nvkm_falcon_start(falcon);
return 0;
}
static void
gp102_sec2_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust)
{
......@@ -122,7 +112,6 @@ gp102_sec2_acr_0 = {
.bld_size = sizeof(struct loader_config_v1),
.bld_write = gp102_sec2_acr_bld_write,
.bld_patch = gp102_sec2_acr_bld_patch,
.boot = gp102_sec2_acr_boot,
.bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) |
BIT_ULL(NVKM_ACR_LSF_GPCCS) |
BIT_ULL(NVKM_ACR_LSF_SEC2),
......@@ -169,11 +158,29 @@ gp102_sec2_intr(struct nvkm_sec2 *sec2)
u32 intr = nvkm_falcon_rd32(falcon, 0x008) & disp & ~(disp >> 16);
if (intr & 0x00000040) {
schedule_work(&sec2->work);
if (unlikely(atomic_read(&sec2->initmsg) == 0)) {
int ret = sec2->func->initmsg(sec2);
if (ret)
nvkm_error(subdev, "error parsing init message: %d\n", ret);
atomic_set(&sec2->initmsg, ret ?: 1);
}
if (atomic_read(&sec2->initmsg) > 0) {
if (!nvkm_falcon_msgq_empty(sec2->msgq))
nvkm_falcon_msgq_recv(sec2->msgq);
}
nvkm_falcon_wr32(falcon, 0x004, 0x00000040);
intr &= ~0x00000040;
}
if (intr & 0x00000010) {
nvkm_falcon_wr32(falcon, 0x004, 0x00000010);
intr &= ~0x00000010;
}
if (intr) {
nvkm_error(subdev, "unhandled intr %08x\n", intr);
nvkm_falcon_wr32(falcon, 0x004, intr);
......@@ -250,6 +257,7 @@ gp102_sec2_flcn = {
const struct nvkm_sec2_func
gp102_sec2 = {
.flcn = &gp102_sec2_flcn,
.unit_unload = NV_SEC2_UNIT_UNLOAD,
.unit_acr = NV_SEC2_UNIT_ACR,
.intr = gp102_sec2_intr,
.initmsg = gp102_sec2_initmsg,
......@@ -304,7 +312,6 @@ gp102_sec2_acr_1 = {
.bld_size = sizeof(struct flcn_bl_dmem_desc_v2),
.bld_write = gp102_sec2_acr_bld_write_1,
.bld_patch = gp102_sec2_acr_bld_patch_1,
.boot = gp102_sec2_acr_boot,
.bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) |
BIT_ULL(NVKM_ACR_LSF_GPCCS) |
BIT_ULL(NVKM_ACR_LSF_SEC2),
......
......@@ -5,6 +5,7 @@
struct nvkm_sec2_func {
const struct nvkm_falcon_func *flcn;
u8 unit_unload;
u8 unit_acr;
void (*intr)(struct nvkm_sec2 *);
int (*initmsg)(struct nvkm_sec2 *);
......
......@@ -22,6 +22,8 @@
#include "priv.h"
#include <subdev/acr.h>
#include <nvfw/sec2.h>
static const struct nvkm_falcon_func
tu102_sec2_flcn = {
.debug = 0x408,
......@@ -44,7 +46,8 @@ tu102_sec2_flcn = {
static const struct nvkm_sec2_func
tu102_sec2 = {
.flcn = &tu102_sec2_flcn,
.unit_acr = 0x07,
.unit_unload = NV_SEC2_UNIT_V2_UNLOAD,
.unit_acr = NV_SEC2_UNIT_V2_ACR,
.intr = gp102_sec2_intr,
.initmsg = gp102_sec2_initmsg,
};
......
......@@ -25,7 +25,7 @@
static void
nvkm_falcon_msgq_open(struct nvkm_falcon_msgq *msgq)
{
mutex_lock(&msgq->mutex);
spin_lock(&msgq->lock);
msgq->position = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->tail_reg);
}
......@@ -37,10 +37,10 @@ nvkm_falcon_msgq_close(struct nvkm_falcon_msgq *msgq, bool commit)
if (commit)
nvkm_falcon_wr32(falcon, msgq->tail_reg, msgq->position);
mutex_unlock(&msgq->mutex);
spin_unlock(&msgq->lock);
}
static bool
bool
nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *msgq)
{
u32 head = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->head_reg);
......@@ -208,6 +208,6 @@ nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *qmgr, const char *name,
msgq->qmgr = qmgr;
msgq->name = name;
mutex_init(&msgq->mutex);
spin_lock_init(&msgq->lock);
return 0;
}
......@@ -73,7 +73,7 @@ struct nvkm_falcon_cmdq {
struct nvkm_falcon_msgq {
struct nvkm_falcon_qmgr *qmgr;
const char *name;
struct mutex mutex;
spinlock_t lock;
u32 head_reg;
u32 tail_reg;
......
......@@ -97,7 +97,6 @@ nvkm_acr_load(struct nvkm_acr *acr)
{
struct nvkm_subdev *subdev = &acr->subdev;
struct nvkm_acr_lsf *rtos = nvkm_acr_rtos(acr);
struct nvkm_acr_lsf *lsf;
u64 start, limit;
int ret;
......@@ -129,14 +128,6 @@ nvkm_acr_load(struct nvkm_acr *acr)
acr->rtos = rtos;
}
list_for_each_entry(lsf, &acr->lsf, head) {
if (lsf->func->boot) {
ret = lsf->func->boot(lsf->falcon);
if (ret)
break;
}
}
return ret;
}
......
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