forked from Minki/linux
drm/nouveau/flcn/msgq: move handling of init message to subdevs
When the PMU/SEC2 LS FWs have booted, they'll send a message to the host with various information, including the configuration of message/command queues that are available. Move the handling for this to the relevant subdevs. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
2d063981d7
commit
d114a1393f
@ -1,8 +1,28 @@
|
|||||||
#ifndef __NVFW_PMU_H__
|
#ifndef __NVFW_PMU_H__
|
||||||
#define __NVFW_PMU_H__
|
#define __NVFW_PMU_H__
|
||||||
|
|
||||||
|
#define NV_PMU_UNIT_INIT 0x07
|
||||||
#define NV_PMU_UNIT_ACR 0x0a
|
#define NV_PMU_UNIT_ACR 0x0a
|
||||||
|
|
||||||
|
struct nv_pmu_init_msg {
|
||||||
|
struct nv_falcon_msg hdr;
|
||||||
|
#define NV_PMU_INIT_MSG_INIT 0x00
|
||||||
|
u8 msg_type;
|
||||||
|
|
||||||
|
u8 pad;
|
||||||
|
u16 os_debug_entry_point;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u16 size;
|
||||||
|
u16 offset;
|
||||||
|
u8 index;
|
||||||
|
u8 pad;
|
||||||
|
} queue_info[5];
|
||||||
|
|
||||||
|
u16 sw_managed_area_offset;
|
||||||
|
u16 sw_managed_area_size;
|
||||||
|
};
|
||||||
|
|
||||||
struct nv_pmu_acr_cmd {
|
struct nv_pmu_acr_cmd {
|
||||||
struct nv_falcon_cmd hdr;
|
struct nv_falcon_cmd hdr;
|
||||||
#define NV_PMU_ACR_CMD_INIT_WPR_REGION 0x00
|
#define NV_PMU_ACR_CMD_INIT_WPR_REGION 0x00
|
||||||
@ -16,6 +36,17 @@ struct nv_pmu_acr_msg {
|
|||||||
u8 msg_type;
|
u8 msg_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nv_pmu_acr_init_wpr_region_cmd {
|
||||||
|
struct nv_pmu_acr_cmd cmd;
|
||||||
|
u32 region_id;
|
||||||
|
u32 wpr_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nv_pmu_acr_init_wpr_region_msg {
|
||||||
|
struct nv_pmu_acr_msg msg;
|
||||||
|
u32 error_code;
|
||||||
|
};
|
||||||
|
|
||||||
struct nv_pmu_acr_bootstrap_falcon_cmd {
|
struct nv_pmu_acr_bootstrap_falcon_cmd {
|
||||||
struct nv_pmu_acr_cmd cmd;
|
struct nv_pmu_acr_cmd cmd;
|
||||||
#define NV_PMU_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0x00000000
|
#define NV_PMU_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0x00000000
|
||||||
|
@ -1,8 +1,30 @@
|
|||||||
#ifndef __NVFW_SEC2_H__
|
#ifndef __NVFW_SEC2_H__
|
||||||
#define __NVFW_SEC2_H__
|
#define __NVFW_SEC2_H__
|
||||||
|
|
||||||
|
#define NV_SEC2_UNIT_INIT 0x01
|
||||||
#define NV_SEC2_UNIT_ACR 0x08
|
#define NV_SEC2_UNIT_ACR 0x08
|
||||||
|
|
||||||
|
struct nv_sec2_init_msg {
|
||||||
|
struct nv_falcon_msg hdr;
|
||||||
|
#define NV_SEC2_INIT_MSG_INIT 0x00
|
||||||
|
u8 msg_type;
|
||||||
|
|
||||||
|
u8 num_queues;
|
||||||
|
u16 os_debug_entry_point;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u32 offset;
|
||||||
|
u16 size;
|
||||||
|
u8 index;
|
||||||
|
#define NV_SEC2_INIT_MSG_QUEUE_ID_CMDQ 0x00
|
||||||
|
#define NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ 0x01
|
||||||
|
u8 id;
|
||||||
|
} queue_info[2];
|
||||||
|
|
||||||
|
u32 sw_managed_area_offset;
|
||||||
|
u16 sw_managed_area_size;
|
||||||
|
};
|
||||||
|
|
||||||
struct nv_sec2_acr_cmd {
|
struct nv_sec2_acr_cmd {
|
||||||
struct nv_falcon_cmd hdr;
|
struct nv_falcon_cmd hdr;
|
||||||
#define NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON 0x00
|
#define NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON 0x00
|
||||||
|
@ -72,4 +72,5 @@ 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_del(struct nvkm_falcon_msgq **);
|
||||||
void nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *,
|
void nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *,
|
||||||
u32 index, u32 offset, u32 size);
|
u32 index, u32 offset, u32 size);
|
||||||
|
int nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *, void *, u32 size);
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,7 +32,6 @@ int nvkm_msgqueue_new(u32, struct nvkm_falcon *, const struct nvkm_secboot *,
|
|||||||
struct nvkm_msgqueue **);
|
struct nvkm_msgqueue **);
|
||||||
void nvkm_msgqueue_del(struct nvkm_msgqueue **);
|
void nvkm_msgqueue_del(struct nvkm_msgqueue **);
|
||||||
void nvkm_msgqueue_recv(struct nvkm_msgqueue *);
|
void nvkm_msgqueue_recv(struct nvkm_msgqueue *);
|
||||||
int nvkm_msgqueue_reinit(struct nvkm_msgqueue *);
|
|
||||||
|
|
||||||
/* useful if we run a NVIDIA-signed firmware */
|
/* useful if we run a NVIDIA-signed firmware */
|
||||||
void nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *, void *);
|
void nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *, void *);
|
||||||
|
@ -14,7 +14,9 @@ struct nvkm_sec2 {
|
|||||||
struct nvkm_falcon_cmdq *cmdq;
|
struct nvkm_falcon_cmdq *cmdq;
|
||||||
struct nvkm_falcon_msgq *msgq;
|
struct nvkm_falcon_msgq *msgq;
|
||||||
struct nvkm_msgqueue *queue;
|
struct nvkm_msgqueue *queue;
|
||||||
|
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
|
bool initmsg_received;
|
||||||
};
|
};
|
||||||
|
|
||||||
int gp102_sec2_new(struct nvkm_device *, int, struct nvkm_sec2 **);
|
int gp102_sec2_new(struct nvkm_device *, int, struct nvkm_sec2 **);
|
||||||
|
@ -13,6 +13,7 @@ struct nvkm_pmu {
|
|||||||
struct nvkm_falcon_cmdq *hpq;
|
struct nvkm_falcon_cmdq *hpq;
|
||||||
struct nvkm_falcon_cmdq *lpq;
|
struct nvkm_falcon_cmdq *lpq;
|
||||||
struct nvkm_falcon_msgq *msgq;
|
struct nvkm_falcon_msgq *msgq;
|
||||||
|
bool initmsg_received;
|
||||||
struct nvkm_msgqueue *queue;
|
struct nvkm_msgqueue *queue;
|
||||||
|
|
||||||
struct completion wpr_ready;
|
struct completion wpr_ready;
|
||||||
|
@ -30,6 +30,17 @@ nvkm_sec2_recv(struct work_struct *work)
|
|||||||
{
|
{
|
||||||
struct nvkm_sec2 *sec2 = container_of(work, typeof(*sec2), 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec2->initmsg_received = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sec2->queue) {
|
if (!sec2->queue) {
|
||||||
nvkm_warn(&sec2->engine.subdev,
|
nvkm_warn(&sec2->engine.subdev,
|
||||||
"recv function called while no firmware set!\n");
|
"recv function called while no firmware set!\n");
|
||||||
@ -50,8 +61,14 @@ static int
|
|||||||
nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend)
|
nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend)
|
||||||
{
|
{
|
||||||
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
|
struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
|
||||||
|
|
||||||
flush_work(&sec2->work);
|
flush_work(&sec2->work);
|
||||||
nvkm_falcon_cmdq_fini(sec2->cmdq);
|
|
||||||
|
if (suspend) {
|
||||||
|
nvkm_falcon_cmdq_fini(sec2->cmdq);
|
||||||
|
sec2->initmsg_received = false;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,37 @@ gp102_sec2_acr_0 = {
|
|||||||
.bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon,
|
.bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
gp102_sec2_initmsg(struct nvkm_sec2 *sec2)
|
||||||
|
{
|
||||||
|
struct nv_sec2_init_msg msg;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
ret = nvkm_falcon_msgq_recv_initmsg(sec2->msgq, &msg, sizeof(msg));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (msg.hdr.unit_id != NV_SEC2_UNIT_INIT ||
|
||||||
|
msg.msg_type != NV_SEC2_INIT_MSG_INIT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(msg.queue_info); i++) {
|
||||||
|
if (msg.queue_info[i].id == NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ) {
|
||||||
|
nvkm_falcon_msgq_init(sec2->msgq,
|
||||||
|
msg.queue_info[i].index,
|
||||||
|
msg.queue_info[i].offset,
|
||||||
|
msg.queue_info[i].size);
|
||||||
|
} else {
|
||||||
|
nvkm_falcon_cmdq_init(sec2->cmdq,
|
||||||
|
msg.queue_info[i].index,
|
||||||
|
msg.queue_info[i].offset,
|
||||||
|
msg.queue_info[i].size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gp102_sec2_intr(struct nvkm_sec2 *sec2)
|
gp102_sec2_intr(struct nvkm_sec2 *sec2)
|
||||||
{
|
{
|
||||||
@ -161,6 +192,7 @@ gp102_sec2 = {
|
|||||||
.flcn = &gp102_sec2_flcn,
|
.flcn = &gp102_sec2_flcn,
|
||||||
.unit_acr = NV_SEC2_UNIT_ACR,
|
.unit_acr = NV_SEC2_UNIT_ACR,
|
||||||
.intr = gp102_sec2_intr,
|
.intr = gp102_sec2_intr,
|
||||||
|
.initmsg = gp102_sec2_initmsg,
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_FIRMWARE("nvidia/gp102/sec2/desc.bin");
|
MODULE_FIRMWARE("nvidia/gp102/sec2/desc.bin");
|
||||||
|
@ -7,6 +7,7 @@ struct nvkm_sec2_func {
|
|||||||
const struct nvkm_falcon_func *flcn;
|
const struct nvkm_falcon_func *flcn;
|
||||||
u8 unit_acr;
|
u8 unit_acr;
|
||||||
void (*intr)(struct nvkm_sec2 *);
|
void (*intr)(struct nvkm_sec2 *);
|
||||||
|
int (*initmsg)(struct nvkm_sec2 *);
|
||||||
};
|
};
|
||||||
|
|
||||||
void gp102_sec2_intr(struct nvkm_sec2 *);
|
void gp102_sec2_intr(struct nvkm_sec2 *);
|
||||||
|
@ -136,40 +136,27 @@ msgqueue_msg_handle(struct nvkm_falcon_msgq *msgq, struct nv_falcon_msg *hdr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
msgqueue_handle_init_msg(struct nvkm_msgqueue *priv)
|
nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *msgq,
|
||||||
|
void *data, u32 size)
|
||||||
{
|
{
|
||||||
struct nvkm_falcon *falcon = priv->falcon;
|
struct nvkm_falcon *falcon = msgq->qmgr->falcon;
|
||||||
const struct nvkm_subdev *subdev = falcon->owner;
|
struct nv_falcon_msg *hdr = data;
|
||||||
const u32 tail_reg = falcon->func->msgq.tail;
|
|
||||||
u8 msg_buffer[MSG_BUF_SIZE];
|
|
||||||
struct nvkm_msgqueue_hdr *hdr = (void *)msg_buffer;
|
|
||||||
u32 tail;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
msgq->head_reg = falcon->func->msgq.head;
|
||||||
* Read the message - queues are not initialized yet so we cannot rely
|
msgq->tail_reg = falcon->func->msgq.tail;
|
||||||
* on msg_queue_read()
|
msgq->offset = nvkm_falcon_rd32(falcon, falcon->func->msgq.tail);
|
||||||
*/
|
|
||||||
tail = nvkm_falcon_rd32(falcon, tail_reg);
|
|
||||||
nvkm_falcon_read_dmem(falcon, tail, HDR_SIZE, 0, hdr);
|
|
||||||
|
|
||||||
if (hdr->size > MSG_BUF_SIZE) {
|
msg_queue_open(msgq);
|
||||||
nvkm_error(subdev, "message too big (%d bytes)\n", hdr->size);
|
ret = msg_queue_pop(msgq, data, size);
|
||||||
return -ENOSPC;
|
if (ret == 0 && hdr->size != size) {
|
||||||
|
FLCN_ERR(falcon, "unexpected init message size %d vs %d",
|
||||||
|
hdr->size, size);
|
||||||
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
msg_queue_close(msgq, ret == 0);
|
||||||
nvkm_falcon_read_dmem(falcon, tail + HDR_SIZE, hdr->size - HDR_SIZE, 0,
|
return ret;
|
||||||
(hdr + 1));
|
|
||||||
|
|
||||||
tail += ALIGN(hdr->size, QUEUE_ALIGNMENT);
|
|
||||||
nvkm_falcon_wr32(falcon, tail_reg, tail);
|
|
||||||
|
|
||||||
ret = priv->func->init_func->init_callback(priv, hdr);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -182,17 +169,9 @@ nvkm_msgqueue_process_msgs(struct nvkm_msgqueue *priv,
|
|||||||
*/
|
*/
|
||||||
u8 msg_buffer[MSG_BUF_SIZE];
|
u8 msg_buffer[MSG_BUF_SIZE];
|
||||||
struct nv_falcon_msg *hdr = (void *)msg_buffer;
|
struct nv_falcon_msg *hdr = (void *)msg_buffer;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* the first message we receive must be the init message */
|
while (msg_queue_read(queue, hdr) > 0)
|
||||||
if ((!priv->init_msg_received)) {
|
msgqueue_msg_handle(queue, hdr);
|
||||||
ret = msgqueue_handle_init_msg(priv);
|
|
||||||
if (!ret)
|
|
||||||
priv->init_msg_received = true;
|
|
||||||
} else {
|
|
||||||
while (msg_queue_read(queue, hdr) > 0)
|
|
||||||
msgqueue_msg_handle(queue, hdr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -90,17 +90,6 @@ nvkm_msgqueue_recv(struct nvkm_msgqueue *queue)
|
|||||||
queue->func->recv(queue);
|
queue->func->recv(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
nvkm_msgqueue_reinit(struct nvkm_msgqueue *queue)
|
|
||||||
{
|
|
||||||
/* firmware not set yet... */
|
|
||||||
if (!queue)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
queue->init_msg_received = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nvkm_msgqueue_ctor(const struct nvkm_msgqueue_func *func,
|
nvkm_msgqueue_ctor(const struct nvkm_msgqueue_func *func,
|
||||||
struct nvkm_falcon *falcon,
|
struct nvkm_falcon *falcon,
|
||||||
|
@ -52,31 +52,6 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* struct nvkm_msgqueue_hdr - header for all commands/messages
|
|
||||||
* @unit_id: id of firmware using receiving the command/sending the message
|
|
||||||
* @size: total size of command/message
|
|
||||||
* @ctrl_flags: type of command/message
|
|
||||||
* @seq_id: used to match a message from its corresponding command
|
|
||||||
*/
|
|
||||||
struct nvkm_msgqueue_hdr {
|
|
||||||
u8 unit_id;
|
|
||||||
u8 size;
|
|
||||||
u8 ctrl_flags;
|
|
||||||
u8 seq_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct nvkm_msgqueue_msg - base message.
|
|
||||||
*
|
|
||||||
* This is just a header and a message (or command) type. Useful when
|
|
||||||
* building command-specific structures.
|
|
||||||
*/
|
|
||||||
struct nvkm_msgqueue_msg {
|
|
||||||
struct nvkm_msgqueue_hdr hdr;
|
|
||||||
u8 msg_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nvkm_msgqueue;
|
struct nvkm_msgqueue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,7 +62,6 @@ struct nvkm_msgqueue;
|
|||||||
*/
|
*/
|
||||||
struct nvkm_msgqueue_init_func {
|
struct nvkm_msgqueue_init_func {
|
||||||
void (*gen_cmdline)(struct nvkm_msgqueue *, void *);
|
void (*gen_cmdline)(struct nvkm_msgqueue *, void *);
|
||||||
int (*init_callback)(struct nvkm_msgqueue *, struct nvkm_msgqueue_hdr *);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nvkm_msgqueue_func {
|
struct nvkm_msgqueue_func {
|
||||||
@ -136,7 +110,6 @@ struct nvkm_msgqueue {
|
|||||||
struct nvkm_falcon *falcon;
|
struct nvkm_falcon *falcon;
|
||||||
const struct nvkm_msgqueue_func *func;
|
const struct nvkm_msgqueue_func *func;
|
||||||
u32 fw_version;
|
u32 fw_version;
|
||||||
bool init_msg_received;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void nvkm_msgqueue_ctor(const struct nvkm_msgqueue_func *, struct nvkm_falcon *,
|
void nvkm_msgqueue_ctor(const struct nvkm_msgqueue_func *, struct nvkm_falcon *,
|
||||||
|
@ -25,11 +25,6 @@
|
|||||||
#include <subdev/pmu.h>
|
#include <subdev/pmu.h>
|
||||||
#include <subdev/secboot.h>
|
#include <subdev/secboot.h>
|
||||||
|
|
||||||
/* Queues identifiers */
|
|
||||||
enum {
|
|
||||||
MSGQUEUE_0137C63D_NUM_QUEUES = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct msgqueue_0137c63d {
|
struct msgqueue_0137c63d {
|
||||||
struct nvkm_msgqueue base;
|
struct nvkm_msgqueue base;
|
||||||
};
|
};
|
||||||
@ -52,12 +47,6 @@ msgqueue_0137c63d_process_msgs(struct nvkm_msgqueue *queue)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Init unit */
|
/* Init unit */
|
||||||
#define MSGQUEUE_0137C63D_UNIT_INIT 0x07
|
|
||||||
|
|
||||||
enum {
|
|
||||||
INIT_MSG_INIT = 0x0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf)
|
init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf)
|
||||||
{
|
{
|
||||||
@ -84,118 +73,11 @@ init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf)
|
|||||||
args->secure_mode = 1;
|
args->secure_mode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* forward declaration */
|
|
||||||
static int acr_init_wpr(struct nvkm_msgqueue *queue);
|
|
||||||
|
|
||||||
static int
|
|
||||||
init_callback(struct nvkm_msgqueue *_queue, struct nvkm_msgqueue_hdr *hdr)
|
|
||||||
{
|
|
||||||
struct msgqueue_0137c63d *priv = msgqueue_0137c63d(_queue);
|
|
||||||
struct {
|
|
||||||
struct nvkm_msgqueue_msg base;
|
|
||||||
|
|
||||||
u8 pad;
|
|
||||||
u16 os_debug_entry_point;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u16 size;
|
|
||||||
u16 offset;
|
|
||||||
u8 index;
|
|
||||||
u8 pad;
|
|
||||||
} queue_info[MSGQUEUE_0137C63D_NUM_QUEUES];
|
|
||||||
|
|
||||||
u16 sw_managed_area_offset;
|
|
||||||
u16 sw_managed_area_size;
|
|
||||||
} *init = (void *)hdr;
|
|
||||||
const struct nvkm_subdev *subdev = _queue->falcon->owner;
|
|
||||||
struct nvkm_pmu *pmu = subdev->device->pmu;
|
|
||||||
|
|
||||||
if (init->base.hdr.unit_id != MSGQUEUE_0137C63D_UNIT_INIT) {
|
|
||||||
nvkm_error(subdev, "expected message from init unit\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (init->base.msg_type != INIT_MSG_INIT) {
|
|
||||||
nvkm_error(subdev, "expected PMU init msg\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvkm_falcon_cmdq_init(pmu->hpq, init->queue_info[0].index,
|
|
||||||
init->queue_info[0].offset,
|
|
||||||
init->queue_info[0].size);
|
|
||||||
nvkm_falcon_cmdq_init(pmu->lpq, init->queue_info[1].index,
|
|
||||||
init->queue_info[1].offset,
|
|
||||||
init->queue_info[1].size);
|
|
||||||
nvkm_falcon_msgq_init(pmu->msgq, init->queue_info[4].index,
|
|
||||||
init->queue_info[4].offset,
|
|
||||||
init->queue_info[4].size);
|
|
||||||
|
|
||||||
/* Complete initialization by initializing WPR region */
|
|
||||||
return acr_init_wpr(&priv->base);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct nvkm_msgqueue_init_func
|
static const struct nvkm_msgqueue_init_func
|
||||||
msgqueue_0137c63d_init_func = {
|
msgqueue_0137c63d_init_func = {
|
||||||
.gen_cmdline = init_gen_cmdline,
|
.gen_cmdline = init_gen_cmdline,
|
||||||
.init_callback = init_callback,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ACR unit */
|
|
||||||
#define MSGQUEUE_0137C63D_UNIT_ACR 0x0a
|
|
||||||
|
|
||||||
enum {
|
|
||||||
ACR_CMD_INIT_WPR_REGION = 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
acr_init_wpr_callback(void *priv, struct nv_falcon_msg *hdr)
|
|
||||||
{
|
|
||||||
struct nvkm_pmu *pmu = priv;
|
|
||||||
struct nvkm_subdev *subdev = &pmu->subdev;
|
|
||||||
struct {
|
|
||||||
struct nv_falcon_msg base;
|
|
||||||
u8 msg_type;
|
|
||||||
u32 error_code;
|
|
||||||
} *msg = (void *)hdr;
|
|
||||||
|
|
||||||
if (msg->error_code) {
|
|
||||||
nvkm_error(subdev, "ACR WPR init failure: %d\n",
|
|
||||||
msg->error_code);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvkm_debug(subdev, "ACR WPR init complete\n");
|
|
||||||
complete_all(&pmu->wpr_ready);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
acr_init_wpr(struct nvkm_msgqueue *queue)
|
|
||||||
{
|
|
||||||
struct nvkm_pmu *pmu = queue->falcon->owner->device->pmu;
|
|
||||||
/*
|
|
||||||
* region_id: region ID in WPR region
|
|
||||||
* wpr_offset: offset in WPR region
|
|
||||||
*/
|
|
||||||
struct {
|
|
||||||
struct nv_falcon_cmd hdr;
|
|
||||||
u8 cmd_type;
|
|
||||||
u32 region_id;
|
|
||||||
u32 wpr_offset;
|
|
||||||
} cmd;
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
|
||||||
|
|
||||||
cmd.hdr.unit_id = MSGQUEUE_0137C63D_UNIT_ACR;
|
|
||||||
cmd.hdr.size = sizeof(cmd);
|
|
||||||
cmd.cmd_type = ACR_CMD_INIT_WPR_REGION;
|
|
||||||
cmd.region_id = 0x01;
|
|
||||||
cmd.wpr_offset = 0x00;
|
|
||||||
return nvkm_falcon_cmdq_send(pmu->hpq, &cmd.hdr, acr_init_wpr_callback,
|
|
||||||
pmu, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue)
|
msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue)
|
||||||
{
|
{
|
||||||
|
@ -31,12 +31,6 @@
|
|||||||
* message queue, and uses a different command line and init message.
|
* message queue, and uses a different command line and init message.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum {
|
|
||||||
MSGQUEUE_0148CDEC_COMMAND_QUEUE = 0,
|
|
||||||
MSGQUEUE_0148CDEC_MESSAGE_QUEUE = 1,
|
|
||||||
MSGQUEUE_0148CDEC_NUM_QUEUES,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct msgqueue_0148cdec {
|
struct msgqueue_0148cdec {
|
||||||
struct nvkm_msgqueue base;
|
struct nvkm_msgqueue base;
|
||||||
};
|
};
|
||||||
@ -50,13 +44,6 @@ msgqueue_0148cdec_process_msgs(struct nvkm_msgqueue *queue)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Init unit */
|
|
||||||
#define MSGQUEUE_0148CDEC_UNIT_INIT 0x01
|
|
||||||
|
|
||||||
enum {
|
|
||||||
INIT_MSG_INIT = 0x0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf)
|
init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf)
|
||||||
{
|
{
|
||||||
@ -71,62 +58,9 @@ init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf)
|
|||||||
args->secure_mode = false;
|
args->secure_mode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
init_callback(struct nvkm_msgqueue *_queue, struct nvkm_msgqueue_hdr *hdr)
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
struct nvkm_msgqueue_msg base;
|
|
||||||
|
|
||||||
u8 num_queues;
|
|
||||||
u16 os_debug_entry_point;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u32 offset;
|
|
||||||
u16 size;
|
|
||||||
u8 index;
|
|
||||||
u8 id;
|
|
||||||
} queue_info[MSGQUEUE_0148CDEC_NUM_QUEUES];
|
|
||||||
|
|
||||||
u16 sw_managed_area_offset;
|
|
||||||
u16 sw_managed_area_size;
|
|
||||||
} *init = (void *)hdr;
|
|
||||||
const struct nvkm_subdev *subdev = _queue->falcon->owner;
|
|
||||||
struct nvkm_sec2 *sec2 = subdev->device->sec2;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (init->base.hdr.unit_id != MSGQUEUE_0148CDEC_UNIT_INIT) {
|
|
||||||
nvkm_error(subdev, "expected message from init unit\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (init->base.msg_type != INIT_MSG_INIT) {
|
|
||||||
nvkm_error(subdev, "expected SEC init msg\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < MSGQUEUE_0148CDEC_NUM_QUEUES; i++) {
|
|
||||||
u8 id = init->queue_info[i].id;
|
|
||||||
|
|
||||||
if (id == MSGQUEUE_0148CDEC_MESSAGE_QUEUE) {
|
|
||||||
nvkm_falcon_msgq_init(sec2->msgq,
|
|
||||||
init->queue_info[i].index,
|
|
||||||
init->queue_info[i].offset,
|
|
||||||
init->queue_info[i].size);
|
|
||||||
} else {
|
|
||||||
nvkm_falcon_cmdq_init(sec2->cmdq,
|
|
||||||
init->queue_info[i].index,
|
|
||||||
init->queue_info[i].offset,
|
|
||||||
init->queue_info[i].size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct nvkm_msgqueue_init_func
|
static const struct nvkm_msgqueue_init_func
|
||||||
msgqueue_0148cdec_init_func = {
|
msgqueue_0148cdec_init_func = {
|
||||||
.gen_cmdline = init_gen_cmdline,
|
.gen_cmdline = init_gen_cmdline,
|
||||||
.init_callback = init_callback,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ nvkm_pmu_fini(struct nvkm_subdev *subdev, bool suspend)
|
|||||||
|
|
||||||
nvkm_falcon_cmdq_fini(pmu->lpq);
|
nvkm_falcon_cmdq_fini(pmu->lpq);
|
||||||
nvkm_falcon_cmdq_fini(pmu->hpq);
|
nvkm_falcon_cmdq_fini(pmu->hpq);
|
||||||
|
pmu->initmsg_received = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,9 +61,80 @@ gm20b_pmu_acr = {
|
|||||||
.bootstrap_falcon = gm20b_pmu_acr_bootstrap_falcon,
|
.bootstrap_falcon = gm20b_pmu_acr_bootstrap_falcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
gm20b_pmu_acr_init_wpr_callback(void *priv, struct nv_falcon_msg *hdr)
|
||||||
|
{
|
||||||
|
struct nv_pmu_acr_init_wpr_region_msg *msg =
|
||||||
|
container_of(hdr, typeof(*msg), msg.hdr);
|
||||||
|
struct nvkm_pmu *pmu = priv;
|
||||||
|
struct nvkm_subdev *subdev = &pmu->subdev;
|
||||||
|
|
||||||
|
if (msg->error_code) {
|
||||||
|
nvkm_error(subdev, "ACR WPR init failure: %d\n",
|
||||||
|
msg->error_code);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvkm_debug(subdev, "ACR WPR init complete\n");
|
||||||
|
complete_all(&pmu->wpr_ready);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gm20b_pmu_acr_init_wpr(struct nvkm_pmu *pmu)
|
||||||
|
{
|
||||||
|
struct nv_pmu_acr_init_wpr_region_cmd cmd = {
|
||||||
|
.cmd.hdr.unit_id = NV_PMU_UNIT_ACR,
|
||||||
|
.cmd.hdr.size = sizeof(cmd),
|
||||||
|
.cmd.cmd_type = NV_PMU_ACR_CMD_INIT_WPR_REGION,
|
||||||
|
.region_id = 1,
|
||||||
|
.wpr_offset = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return nvkm_falcon_cmdq_send(pmu->hpq, &cmd.cmd.hdr,
|
||||||
|
gm20b_pmu_acr_init_wpr_callback, pmu, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gm20b_pmu_initmsg(struct nvkm_pmu *pmu)
|
||||||
|
{
|
||||||
|
struct nv_pmu_init_msg msg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nvkm_falcon_msgq_recv_initmsg(pmu->msgq, &msg, sizeof(msg));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (msg.hdr.unit_id != NV_PMU_UNIT_INIT ||
|
||||||
|
msg.msg_type != NV_PMU_INIT_MSG_INIT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
nvkm_falcon_cmdq_init(pmu->hpq, msg.queue_info[0].index,
|
||||||
|
msg.queue_info[0].offset,
|
||||||
|
msg.queue_info[0].size);
|
||||||
|
nvkm_falcon_cmdq_init(pmu->lpq, msg.queue_info[1].index,
|
||||||
|
msg.queue_info[1].offset,
|
||||||
|
msg.queue_info[1].size);
|
||||||
|
nvkm_falcon_msgq_init(pmu->msgq, msg.queue_info[4].index,
|
||||||
|
msg.queue_info[4].offset,
|
||||||
|
msg.queue_info[4].size);
|
||||||
|
return gm20b_pmu_acr_init_wpr(pmu);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gm20b_pmu_recv(struct nvkm_pmu *pmu)
|
gm20b_pmu_recv(struct nvkm_pmu *pmu)
|
||||||
{
|
{
|
||||||
|
if (!pmu->initmsg_received) {
|
||||||
|
int ret = pmu->func->initmsg(pmu);
|
||||||
|
if (ret) {
|
||||||
|
nvkm_error(&pmu->subdev,
|
||||||
|
"error parsing init message: %d\n", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pmu->initmsg_received = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!pmu->queue) {
|
if (!pmu->queue) {
|
||||||
nvkm_warn(&pmu->subdev,
|
nvkm_warn(&pmu->subdev,
|
||||||
"recv function called while no firmware set!\n");
|
"recv function called while no firmware set!\n");
|
||||||
@ -79,6 +150,7 @@ gm20b_pmu = {
|
|||||||
.enabled = gf100_pmu_enabled,
|
.enabled = gf100_pmu_enabled,
|
||||||
.intr = gt215_pmu_intr,
|
.intr = gt215_pmu_intr,
|
||||||
.recv = gm20b_pmu_recv,
|
.recv = gm20b_pmu_recv,
|
||||||
|
.initmsg = gm20b_pmu_initmsg,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
|
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
|
||||||
|
@ -68,6 +68,7 @@ gp10b_pmu = {
|
|||||||
.enabled = gf100_pmu_enabled,
|
.enabled = gf100_pmu_enabled,
|
||||||
.intr = gt215_pmu_intr,
|
.intr = gt215_pmu_intr,
|
||||||
.recv = gm20b_pmu_recv,
|
.recv = gm20b_pmu_recv,
|
||||||
|
.initmsg = gm20b_pmu_initmsg,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
|
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
|
||||||
|
@ -27,6 +27,7 @@ struct nvkm_pmu_func {
|
|||||||
int (*send)(struct nvkm_pmu *, u32 reply[2], u32 process,
|
int (*send)(struct nvkm_pmu *, u32 reply[2], u32 process,
|
||||||
u32 message, u32 data0, u32 data1);
|
u32 message, u32 data0, u32 data1);
|
||||||
void (*recv)(struct nvkm_pmu *);
|
void (*recv)(struct nvkm_pmu *);
|
||||||
|
int (*initmsg)(struct nvkm_pmu *);
|
||||||
void (*pgob)(struct nvkm_pmu *, bool);
|
void (*pgob)(struct nvkm_pmu *, bool);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,6 +45,7 @@ void gk110_pmu_pgob(struct nvkm_pmu *, bool);
|
|||||||
|
|
||||||
int gm20b_pmu_acr_bootstrap_falcon(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
|
int gm20b_pmu_acr_bootstrap_falcon(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
|
||||||
void gm20b_pmu_recv(struct nvkm_pmu *);
|
void gm20b_pmu_recv(struct nvkm_pmu *);
|
||||||
|
int gm20b_pmu_initmsg(struct nvkm_pmu *);
|
||||||
|
|
||||||
struct nvkm_pmu_fwif {
|
struct nvkm_pmu_fwif {
|
||||||
int version;
|
int version;
|
||||||
|
@ -85,8 +85,6 @@ acr_ls_msgqueue_post_run(struct nvkm_msgqueue *queue,
|
|||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
nvkm_msgqueue_write_cmdline(queue, buf);
|
nvkm_msgqueue_write_cmdline(queue, buf);
|
||||||
nvkm_falcon_load_dmem(falcon, buf, addr_args, sizeof(buf), 0);
|
nvkm_falcon_load_dmem(falcon, buf, addr_args, sizeof(buf), 0);
|
||||||
/* rearm the queue so it will wait for the init message */
|
|
||||||
nvkm_msgqueue_reinit(queue);
|
|
||||||
|
|
||||||
/* Enable interrupts */
|
/* Enable interrupts */
|
||||||
nvkm_falcon_wr32(falcon, 0x10, 0xff);
|
nvkm_falcon_wr32(falcon, 0x10, 0xff);
|
||||||
|
Loading…
Reference in New Issue
Block a user