};
#define NV_SEC2_UNIT_INIT 0x01
+#define NV_SEC2_UNIT_UNLOAD 0x06
#define NV_SEC2_UNIT_ACR 0x08
struct nv_sec2_init_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
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
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 **);
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);
#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
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;
}
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);
static const struct nvkm_engine_func
nvkm_sec2 = {
.dtor = nvkm_sec2_dtor,
+ .init = nvkm_sec2_init,
.fini = nvkm_sec2_fini,
.intr = nvkm_sec2_intr,
};
(ret = nvkm_falcon_msgq_new(sec2->qmgr, "msgq", &sec2->msgq)))
return ret;
- INIT_WORK(&sec2->work, nvkm_sec2_recv);
return 0;
};
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)
{
.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),
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);
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,
.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),
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 *);
#include "priv.h"
#include <subdev/acr.h>
+#include <nvfw/sec2.h>
+
static const struct nvkm_falcon_func
tu102_sec2_flcn = {
.debug = 0x408,
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,
};
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);
}
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);
msgq->qmgr = qmgr;
msgq->name = name;
- mutex_init(&msgq->mutex);
+ spin_lock_init(&msgq->lock);
return 0;
}
struct nvkm_falcon_msgq {
struct nvkm_falcon_qmgr *qmgr;
const char *name;
- struct mutex mutex;
+ spinlock_t lock;
u32 head_reg;
u32 tail_reg;
{
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;
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;
}