Commit 86ce2a71 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/flcn/cmdq: move command generation to subdevs

This moves the code to generate commands for the ACR unit of the PMU/SEC2 LS
firmwares to those subdevs.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 25fd061c
#ifndef __NVFW_PMU_H__
#define __NVFW_PMU_H__
#define NV_PMU_UNIT_ACR 0x0a
struct nv_pmu_acr_cmd {
struct nv_falcon_cmd hdr;
#define NV_PMU_ACR_CMD_INIT_WPR_REGION 0x00
#define NV_PMU_ACR_CMD_BOOTSTRAP_FALCON 0x01
#define NV_PMU_ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS 0x03
u8 cmd_type;
};
struct nv_pmu_acr_msg {
struct nv_falcon_cmd hdr;
u8 msg_type;
};
struct nv_pmu_acr_bootstrap_falcon_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_NO 0x00000001
u32 flags;
u32 falcon_id;
};
struct nv_pmu_acr_bootstrap_falcon_msg {
struct nv_pmu_acr_msg msg;
u32 falcon_id;
};
struct nv_pmu_acr_bootstrap_multiple_falcons_cmd {
struct nv_pmu_acr_cmd cmd;
#define NV_PMU_ACR_BOOTSTRAP_MULTIPLE_FALCONS_FLAGS_RESET_YES 0x00000000
#define NV_PMU_ACR_BOOTSTRAP_MULTIPLE_FALCONS_FLAGS_RESET_NO 0x00000001
u32 flags;
u32 falcon_mask;
u32 use_va_mask;
u32 wpr_lo;
u32 wpr_hi;
};
struct nv_pmu_acr_bootstrap_multiple_falcons_msg {
struct nv_pmu_acr_msg msg;
u32 falcon_mask;
};
#endif
#ifndef __NVFW_SEC2_H__
#define __NVFW_SEC2_H__
#define NV_SEC2_UNIT_ACR 0x08
struct nv_sec2_acr_cmd {
struct nv_falcon_cmd hdr;
#define NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON 0x00
u8 cmd_type;
};
struct nv_sec2_acr_msg {
struct nv_falcon_cmd hdr;
u8 msg_type;
};
struct nv_sec2_acr_bootstrap_falcon_cmd {
struct nv_sec2_acr_cmd cmd;
#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0x00000000
#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_NO 0x00000001
u32 flags;
u32 falcon_id;
};
struct nv_sec2_acr_bootstrap_falcon_msg {
struct nv_sec2_acr_msg msg;
u32 error_code;
u32 falcon_id;
};
#endif
...@@ -37,7 +37,4 @@ int nvkm_msgqueue_reinit(struct nvkm_msgqueue *); ...@@ -37,7 +37,4 @@ 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 *);
/* interface to ACR unit running on falcon (NVIDIA signed firmware) */
int nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *, unsigned long);
#endif #endif
...@@ -13,15 +13,34 @@ enum nvkm_acr_lsf_id { ...@@ -13,15 +13,34 @@ enum nvkm_acr_lsf_id {
NVKM_ACR_LSF_NVDEC = 4, NVKM_ACR_LSF_NVDEC = 4,
NVKM_ACR_LSF_SEC2 = 7, NVKM_ACR_LSF_SEC2 = 7,
NVKM_ACR_LSF_MINION = 10, NVKM_ACR_LSF_MINION = 10,
NVKM_ACR_LSF_NUM
}; };
static inline const char *
nvkm_acr_lsf_id(enum nvkm_acr_lsf_id id)
{
switch (id) {
case NVKM_ACR_LSF_PMU : return "pmu";
case NVKM_ACR_LSF_GSPLITE: return "gsplite";
case NVKM_ACR_LSF_FECS : return "fecs";
case NVKM_ACR_LSF_GPCCS : return "gpccs";
case NVKM_ACR_LSF_NVDEC : return "nvdec";
case NVKM_ACR_LSF_SEC2 : return "sec2";
case NVKM_ACR_LSF_MINION : return "minion";
default:
return "unknown";
}
}
struct nvkm_acr { struct nvkm_acr {
const struct nvkm_acr_func *func; const struct nvkm_acr_func *func;
struct nvkm_subdev subdev; struct nvkm_subdev subdev;
struct list_head lsfw; struct list_head lsfw, lsf;
}; };
int nvkm_acr_bootstrap_falcons(struct nvkm_device *, unsigned long mask);
int gm200_acr_new(struct nvkm_device *, int, struct nvkm_acr **); int gm200_acr_new(struct nvkm_device *, int, struct nvkm_acr **);
int gm20b_acr_new(struct nvkm_device *, int, struct nvkm_acr **); int gm20b_acr_new(struct nvkm_device *, int, struct nvkm_acr **);
int gp102_acr_new(struct nvkm_device *, int, struct nvkm_acr **); int gp102_acr_new(struct nvkm_device *, int, struct nvkm_acr **);
...@@ -55,6 +74,8 @@ struct nvkm_acr_lsfw { ...@@ -55,6 +74,8 @@ struct nvkm_acr_lsfw {
}; };
struct nvkm_acr_lsf_func { struct nvkm_acr_lsf_func {
int (*bootstrap_falcon)(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
int (*bootstrap_multiple_falcons)(struct nvkm_falcon *, u32 mask);
}; };
int int
......
...@@ -20,11 +20,53 @@ ...@@ -20,11 +20,53 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#include "priv.h" #include "priv.h"
#include <subdev/acr.h> #include <subdev/acr.h>
#include <subdev/timer.h> #include <subdev/timer.h>
#include <nvfw/sec2.h>
static int
gp102_sec2_acr_bootstrap_falcon_callback(void *priv, struct nv_falcon_msg *hdr)
{
struct nv_sec2_acr_bootstrap_falcon_msg *msg =
container_of(hdr, typeof(*msg), msg.hdr);
struct nvkm_subdev *subdev = priv;
const char *name = nvkm_acr_lsf_id(msg->falcon_id);
if (msg->error_code) {
nvkm_error(subdev, "ACR_BOOTSTRAP_FALCON failed for "
"falcon %d [%s]: %08x\n",
msg->falcon_id, name, msg->error_code);
return -EINVAL;
}
nvkm_debug(subdev, "%s booted\n", name);
return 0;
}
static int
gp102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon,
enum nvkm_acr_lsf_id id)
{
struct nvkm_sec2 *sec2 = container_of(falcon, typeof(*sec2), falcon);
struct nv_sec2_acr_bootstrap_falcon_cmd cmd = {
.cmd.hdr.unit_id = sec2->func->unit_acr,
.cmd.hdr.size = sizeof(cmd),
.cmd.cmd_type = NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON,
.flags = NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES,
.falcon_id = id,
};
return nvkm_falcon_cmdq_send(sec2->cmdq, &cmd.cmd.hdr,
gp102_sec2_acr_bootstrap_falcon_callback,
&sec2->engine.subdev,
msecs_to_jiffies(1000));
}
static const struct nvkm_acr_lsf_func static const struct nvkm_acr_lsf_func
gp102_sec2_acr_0 = { gp102_sec2_acr_0 = {
.bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon,
}; };
void void
...@@ -117,6 +159,7 @@ gp102_sec2_flcn = { ...@@ -117,6 +159,7 @@ gp102_sec2_flcn = {
const struct nvkm_sec2_func const struct nvkm_sec2_func
gp102_sec2 = { gp102_sec2 = {
.flcn = &gp102_sec2_flcn, .flcn = &gp102_sec2_flcn,
.unit_acr = NV_SEC2_UNIT_ACR,
.intr = gp102_sec2_intr, .intr = gp102_sec2_intr,
}; };
...@@ -135,6 +178,7 @@ MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin"); ...@@ -135,6 +178,7 @@ MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin");
const struct nvkm_acr_lsf_func const struct nvkm_acr_lsf_func
gp102_sec2_acr_1 = { gp102_sec2_acr_1 = {
.bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon,
}; };
int int
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
struct nvkm_sec2_func { struct nvkm_sec2_func {
const struct nvkm_falcon_func *flcn; const struct nvkm_falcon_func *flcn;
u8 unit_acr;
void (*intr)(struct nvkm_sec2 *); void (*intr)(struct nvkm_sec2 *);
}; };
......
...@@ -35,34 +35,6 @@ nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *queue, void *buf) ...@@ -35,34 +35,6 @@ nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *queue, void *buf)
queue->func->init_func->gen_cmdline(queue, buf); queue->func->init_func->gen_cmdline(queue, buf);
} }
int
nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *queue,
unsigned long falcon_mask)
{
unsigned long falcon;
if (!queue || !queue->func->acr_func)
return -ENODEV;
/* Does the firmware support booting multiple falcons? */
if (queue->func->acr_func->boot_multiple_falcons)
return queue->func->acr_func->boot_multiple_falcons(queue,
falcon_mask);
/* Else boot all requested falcons individually */
if (!queue->func->acr_func->boot_falcon)
return -ENODEV;
for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END) {
int ret = queue->func->acr_func->boot_falcon(queue, falcon);
if (ret)
return ret;
}
return 0;
}
int int
nvkm_msgqueue_new(u32 version, struct nvkm_falcon *falcon, nvkm_msgqueue_new(u32 version, struct nvkm_falcon *falcon,
const struct nvkm_secboot *sb, struct nvkm_msgqueue **queue) const struct nvkm_secboot *sb, struct nvkm_msgqueue **queue)
......
...@@ -90,20 +90,8 @@ struct nvkm_msgqueue_init_func { ...@@ -90,20 +90,8 @@ struct nvkm_msgqueue_init_func {
int (*init_callback)(struct nvkm_msgqueue *, struct nvkm_msgqueue_hdr *); int (*init_callback)(struct nvkm_msgqueue *, struct nvkm_msgqueue_hdr *);
}; };
/**
* struct nvkm_msgqueue_acr_func - msgqueue functions related to ACR
*
* @boot_falcon: build and send the command to reset a given falcon
* @boot_multiple_falcons: build and send the command to reset several falcons
*/
struct nvkm_msgqueue_acr_func {
int (*boot_falcon)(struct nvkm_msgqueue *, enum nvkm_secboot_falcon);
int (*boot_multiple_falcons)(struct nvkm_msgqueue *, unsigned long);
};
struct nvkm_msgqueue_func { struct nvkm_msgqueue_func {
const struct nvkm_msgqueue_init_func *init_func; const struct nvkm_msgqueue_init_func *init_func;
const struct nvkm_msgqueue_acr_func *acr_func;
void (*dtor)(struct nvkm_msgqueue *); void (*dtor)(struct nvkm_msgqueue *);
void (*recv)(struct nvkm_msgqueue *queue); void (*recv)(struct nvkm_msgqueue *queue);
}; };
......
...@@ -147,8 +147,6 @@ msgqueue_0137c63d_init_func = { ...@@ -147,8 +147,6 @@ msgqueue_0137c63d_init_func = {
enum { enum {
ACR_CMD_INIT_WPR_REGION = 0x00, ACR_CMD_INIT_WPR_REGION = 0x00,
ACR_CMD_BOOTSTRAP_FALCON = 0x01,
ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS = 0x03,
}; };
static int static int
...@@ -198,144 +196,6 @@ acr_init_wpr(struct nvkm_msgqueue *queue) ...@@ -198,144 +196,6 @@ acr_init_wpr(struct nvkm_msgqueue *queue)
pmu, 0); pmu, 0);
} }
static int
acr_boot_falcon_callback(void *priv, struct nv_falcon_msg *hdr)
{
struct acr_bootstrap_falcon_msg {
struct nv_falcon_msg base;
u8 msg_type;
u32 falcon_id;
} *msg = (void *)hdr;
struct nvkm_subdev *subdev = priv;
u32 falcon_id = msg->falcon_id;
if (falcon_id >= NVKM_SECBOOT_FALCON_END) {
nvkm_error(subdev, "in bootstrap falcon callback:\n");
nvkm_error(subdev, "invalid falcon ID 0x%x\n", falcon_id);
return -EINVAL;
}
nvkm_debug(subdev, "%s booted\n", nvkm_secboot_falcon_name[falcon_id]);
return 0;
}
enum {
ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES = 0,
ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO = 1,
};
static int
acr_boot_falcon(struct nvkm_msgqueue *priv, enum nvkm_secboot_falcon falcon)
{
struct nvkm_pmu *pmu = priv->falcon->owner->device->pmu;
/*
* flags - Flag specifying RESET or no RESET.
* falcon id - Falcon id specifying falcon to bootstrap.
*/
struct {
struct nv_falcon_cmd hdr;
u8 cmd_type;
u32 flags;
u32 falcon_id;
} cmd;
if (!wait_for_completion_timeout(&pmu->wpr_ready,
msecs_to_jiffies(1000))) {
nvkm_error(&pmu->subdev, "timeout waiting for WPR init\n");
return -ETIMEDOUT;
}
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.unit_id = MSGQUEUE_0137C63D_UNIT_ACR;
cmd.hdr.size = sizeof(cmd);
cmd.cmd_type = ACR_CMD_BOOTSTRAP_FALCON;
cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
cmd.falcon_id = falcon;
return nvkm_falcon_cmdq_send(pmu->hpq, &cmd.hdr,
acr_boot_falcon_callback, &pmu->subdev,
msecs_to_jiffies(1000));
}
static int
acr_boot_multiple_falcons_callback(void *priv, struct nv_falcon_msg *hdr)
{
struct acr_bootstrap_falcon_msg {
struct nv_falcon_msg base;
u8 msg_type;
u32 falcon_mask;
} *msg = (void *)hdr;
const struct nvkm_subdev *subdev = priv;
unsigned long falcon_mask = msg->falcon_mask;
u32 falcon_id, falcon_treated = 0;
for_each_set_bit(falcon_id, &falcon_mask, NVKM_SECBOOT_FALCON_END) {
nvkm_debug(subdev, "%s booted\n",
nvkm_secboot_falcon_name[falcon_id]);
falcon_treated |= BIT(falcon_id);
}
if (falcon_treated != msg->falcon_mask) {
nvkm_error(subdev, "in bootstrap falcon callback:\n");
nvkm_error(subdev, "invalid falcon mask 0x%x\n",
msg->falcon_mask);
return -EINVAL;
}
return 0;
}
static int
acr_boot_multiple_falcons(struct nvkm_msgqueue *priv, unsigned long falcon_mask)
{
struct nvkm_pmu *pmu = priv->falcon->owner->device->pmu;
/*
* flags - Flag specifying RESET or no RESET.
* falcon id - Falcon id specifying falcon to bootstrap.
*/
struct {
struct nv_falcon_cmd hdr;
u8 cmd_type;
u32 flags;
u32 falcon_mask;
u32 use_va_mask;
u32 wpr_lo;
u32 wpr_hi;
} cmd;
struct msgqueue_0137bca5 *queue = msgqueue_0137bca5(priv);
if (!wait_for_completion_timeout(&pmu->wpr_ready,
msecs_to_jiffies(1000))) {
nvkm_error(&pmu->subdev, "timeout waiting for WPR init\n");
return -ETIMEDOUT;
}
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.unit_id = MSGQUEUE_0137C63D_UNIT_ACR;
cmd.hdr.size = sizeof(cmd);
cmd.cmd_type = ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS;
cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
cmd.falcon_mask = falcon_mask;
cmd.wpr_lo = lower_32_bits(queue->wpr_addr);
cmd.wpr_hi = upper_32_bits(queue->wpr_addr);
return nvkm_falcon_cmdq_send(pmu->hpq, &cmd.hdr,
acr_boot_multiple_falcons_callback,
&pmu->subdev, msecs_to_jiffies(1000));
}
static const struct nvkm_msgqueue_acr_func
msgqueue_0137c63d_acr_func = {
.boot_falcon = acr_boot_falcon,
};
static const struct nvkm_msgqueue_acr_func
msgqueue_0137bca5_acr_func = {
.boot_falcon = acr_boot_falcon,
.boot_multiple_falcons = acr_boot_multiple_falcons,
};
static void static void
msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue) msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue)
{ {
...@@ -345,7 +205,6 @@ msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue) ...@@ -345,7 +205,6 @@ msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue)
static const struct nvkm_msgqueue_func static const struct nvkm_msgqueue_func
msgqueue_0137c63d_func = { msgqueue_0137c63d_func = {
.init_func = &msgqueue_0137c63d_init_func, .init_func = &msgqueue_0137c63d_init_func,
.acr_func = &msgqueue_0137c63d_acr_func,
.recv = msgqueue_0137c63d_process_msgs, .recv = msgqueue_0137c63d_process_msgs,
.dtor = msgqueue_0137c63d_dtor, .dtor = msgqueue_0137c63d_dtor,
}; };
...@@ -370,7 +229,6 @@ msgqueue_0137c63d_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb, ...@@ -370,7 +229,6 @@ msgqueue_0137c63d_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb,
static const struct nvkm_msgqueue_func static const struct nvkm_msgqueue_func
msgqueue_0137bca5_func = { msgqueue_0137bca5_func = {
.init_func = &msgqueue_0137c63d_init_func, .init_func = &msgqueue_0137c63d_init_func,
.acr_func = &msgqueue_0137bca5_acr_func,
.recv = msgqueue_0137c63d_process_msgs, .recv = msgqueue_0137c63d_process_msgs,
.dtor = msgqueue_0137c63d_dtor, .dtor = msgqueue_0137c63d_dtor,
}; };
......
...@@ -130,81 +130,6 @@ msgqueue_0148cdec_init_func = { ...@@ -130,81 +130,6 @@ msgqueue_0148cdec_init_func = {
}; };
/* ACR unit */
#define MSGQUEUE_0148CDEC_UNIT_ACR 0x08
enum {
ACR_CMD_BOOTSTRAP_FALCON = 0x00,
};
static int
acr_boot_falcon_callback(void *priv, struct nv_falcon_msg *hdr)
{
struct acr_bootstrap_falcon_msg {
struct nv_falcon_msg base;
u8 msg_type;
u32 error_code;
u32 falcon_id;
} *msg = (void *)hdr;
const struct nvkm_subdev *subdev = priv;
u32 falcon_id = msg->falcon_id;
if (msg->error_code) {
nvkm_error(subdev, "in bootstrap falcon callback:\n");
nvkm_error(subdev, "expected error code 0x%x\n",
msg->error_code);
return -EINVAL;
}
if (falcon_id >= NVKM_SECBOOT_FALCON_END) {
nvkm_error(subdev, "in bootstrap falcon callback:\n");
nvkm_error(subdev, "invalid falcon ID 0x%x\n", falcon_id);
return -EINVAL;
}
nvkm_debug(subdev, "%s booted\n", nvkm_secboot_falcon_name[falcon_id]);
return 0;
}
enum {
ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES = 0,
ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO = 1,
};
static int
acr_boot_falcon(struct nvkm_msgqueue *priv, enum nvkm_secboot_falcon falcon)
{
struct nvkm_sec2 *sec2 = priv->falcon->owner->device->sec2;
/*
* flags - Flag specifying RESET or no RESET.
* falcon id - Falcon id specifying falcon to bootstrap.
*/
struct {
struct nv_falcon_cmd hdr;
u8 cmd_type;
u32 flags;
u32 falcon_id;
} cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.unit_id = MSGQUEUE_0148CDEC_UNIT_ACR;
cmd.hdr.size = sizeof(cmd);
cmd.cmd_type = ACR_CMD_BOOTSTRAP_FALCON;
cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
cmd.falcon_id = falcon;
return nvkm_falcon_cmdq_send(sec2->cmdq, &cmd.hdr,
acr_boot_falcon_callback,
&sec2->engine.subdev,
msecs_to_jiffies(1000));
}
const struct nvkm_msgqueue_acr_func
msgqueue_0148cdec_acr_func = {
.boot_falcon = acr_boot_falcon,
};
static void static void
msgqueue_0148cdec_dtor(struct nvkm_msgqueue *queue) msgqueue_0148cdec_dtor(struct nvkm_msgqueue *queue)
{ {
...@@ -214,7 +139,6 @@ msgqueue_0148cdec_dtor(struct nvkm_msgqueue *queue) ...@@ -214,7 +139,6 @@ msgqueue_0148cdec_dtor(struct nvkm_msgqueue *queue)
const struct nvkm_msgqueue_func const struct nvkm_msgqueue_func
msgqueue_0148cdec_func = { msgqueue_0148cdec_func = {
.init_func = &msgqueue_0148cdec_init_func, .init_func = &msgqueue_0148cdec_init_func,
.acr_func = &msgqueue_0148cdec_acr_func,
.recv = msgqueue_0148cdec_process_msgs, .recv = msgqueue_0148cdec_process_msgs,
.dtor = msgqueue_0148cdec_dtor, .dtor = msgqueue_0148cdec_dtor,
}; };
......
...@@ -23,19 +23,90 @@ ...@@ -23,19 +23,90 @@
#include <core/firmware.h> #include <core/firmware.h>
static struct nvkm_acr_lsf *
nvkm_acr_falcon(struct nvkm_device *device)
{
struct nvkm_acr *acr = device->acr;
struct nvkm_acr_lsf *lsf;
if (acr) {
list_for_each_entry(lsf, &acr->lsf, head) {
if (lsf->func->bootstrap_falcon)
return lsf;
}
}
return NULL;
}
int
nvkm_acr_bootstrap_falcons(struct nvkm_device *device, unsigned long mask)
{
struct nvkm_acr_lsf *acrflcn = nvkm_acr_falcon(device);
unsigned long id;
if (!acrflcn)
return -ENOSYS;
if (acrflcn->func->bootstrap_multiple_falcons) {
return acrflcn->func->
bootstrap_multiple_falcons(acrflcn->falcon, mask);
}
for_each_set_bit(id, &mask, NVKM_ACR_LSF_NUM) {
int ret = acrflcn->func->bootstrap_falcon(acrflcn->falcon, id);
if (ret)
return ret;
}
return 0;
}
static void
nvkm_acr_cleanup(struct nvkm_acr *acr)
{
nvkm_acr_lsfw_del_all(acr);
}
static int
nvkm_acr_oneinit(struct nvkm_subdev *subdev)
{
struct nvkm_acr *acr = nvkm_acr(subdev);
struct nvkm_acr_lsfw *lsfw;
struct nvkm_acr_lsf *lsf;
list_for_each_entry(lsfw, &acr->lsfw, head) {
if (!(lsf = kmalloc(sizeof(*lsf), GFP_KERNEL)))
return -ENOMEM;
lsf->func = lsfw->func;
lsf->falcon = lsfw->falcon;
lsf->id = lsfw->id;
list_add_tail(&lsf->head, &acr->lsf);
}
nvkm_acr_cleanup(acr);
return 0;
}
static void * static void *
nvkm_acr_dtor(struct nvkm_subdev *subdev) nvkm_acr_dtor(struct nvkm_subdev *subdev)
{ {
struct nvkm_acr *acr = nvkm_acr(subdev); struct nvkm_acr *acr = nvkm_acr(subdev);
struct nvkm_acr_lsf *lsf, *lst;
nvkm_acr_lsfw_del_all(acr); list_for_each_entry_safe(lsf, lst, &acr->lsf, head) {
list_del(&lsf->head);
kfree(lsf);
}
nvkm_acr_cleanup(acr);
return acr; return acr;
} }
static const struct nvkm_subdev_func static const struct nvkm_subdev_func
nvkm_acr = { nvkm_acr = {
.dtor = nvkm_acr_dtor, .dtor = nvkm_acr_dtor,
.oneinit = nvkm_acr_oneinit,
}; };
int int
...@@ -48,6 +119,7 @@ nvkm_acr_new_(const struct nvkm_acr_fwif *fwif, struct nvkm_device *device, ...@@ -48,6 +119,7 @@ nvkm_acr_new_(const struct nvkm_acr_fwif *fwif, struct nvkm_device *device,
return -ENOMEM; return -ENOMEM;
nvkm_subdev_ctor(&nvkm_acr, device, index, &acr->subdev); nvkm_subdev_ctor(&nvkm_acr, device, index, &acr->subdev);
INIT_LIST_HEAD(&acr->lsfw); INIT_LIST_HEAD(&acr->lsfw);
INIT_LIST_HEAD(&acr->lsf);
fwif = nvkm_firmware_load(&acr->subdev, fwif, "Acr", acr); fwif = nvkm_firmware_load(&acr->subdev, fwif, "Acr", acr);
if (IS_ERR(fwif)) if (IS_ERR(fwif))
......
...@@ -18,6 +18,13 @@ struct nvkm_acr_func { ...@@ -18,6 +18,13 @@ struct nvkm_acr_func {
int nvkm_acr_new_(const struct nvkm_acr_fwif *, struct nvkm_device *, int, int nvkm_acr_new_(const struct nvkm_acr_fwif *, struct nvkm_device *, int,
struct nvkm_acr **); struct nvkm_acr **);
struct nvkm_acr_lsf {
const struct nvkm_acr_lsf_func *func;
struct nvkm_falcon *falcon;
enum nvkm_acr_lsf_id id;
struct list_head head;
};
struct nvkm_acr_lsfw *nvkm_acr_lsfw_add(const struct nvkm_acr_lsf_func *, struct nvkm_acr_lsfw *nvkm_acr_lsfw_add(const struct nvkm_acr_lsf_func *,
struct nvkm_acr *, struct nvkm_falcon *, struct nvkm_acr *, struct nvkm_falcon *,
enum nvkm_acr_lsf_id); enum nvkm_acr_lsf_id);
......
...@@ -20,11 +20,45 @@ ...@@ -20,11 +20,45 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#include "priv.h" #include "priv.h"
#include <core/msgqueue.h> #include <core/msgqueue.h>
#include <subdev/acr.h> #include <subdev/acr.h>
#include <nvfw/pmu.h>
static int
gm20b_pmu_acr_bootstrap_falcon_cb(void *priv, struct nv_falcon_msg *hdr)
{
struct nv_pmu_acr_bootstrap_falcon_msg *msg =
container_of(hdr, typeof(*msg), msg.hdr);
return msg->falcon_id;
}
int
gm20b_pmu_acr_bootstrap_falcon(struct nvkm_falcon *falcon,
enum nvkm_acr_lsf_id id)
{
struct nvkm_pmu *pmu = container_of(falcon, typeof(*pmu), falcon);
struct nv_pmu_acr_bootstrap_falcon_cmd cmd = {
.cmd.hdr.unit_id = NV_PMU_UNIT_ACR,
.cmd.hdr.size = sizeof(cmd),
.cmd.cmd_type = NV_PMU_ACR_CMD_BOOTSTRAP_FALCON,
.flags = NV_PMU_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES,
.falcon_id = id,
};
int ret;
ret = nvkm_falcon_cmdq_send(pmu->hpq, &cmd.cmd.hdr,
gm20b_pmu_acr_bootstrap_falcon_cb,
&pmu->subdev, msecs_to_jiffies(1000));
if (ret >= 0 && ret != cmd.falcon_id)
ret = -EIO;
return ret;
}
static const struct nvkm_acr_lsf_func static const struct nvkm_acr_lsf_func
gm20b_pmu_acr = { gm20b_pmu_acr = {
.bootstrap_falcon = gm20b_pmu_acr_bootstrap_falcon,
}; };
void void
......
...@@ -20,10 +20,46 @@ ...@@ -20,10 +20,46 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#include "priv.h" #include "priv.h"
#include <subdev/acr.h> #include <subdev/acr.h>
#include <nvfw/pmu.h>
static int
gp10b_pmu_acr_bootstrap_multiple_falcons_cb(void *priv,
struct nv_falcon_msg *hdr)
{
struct nv_pmu_acr_bootstrap_multiple_falcons_msg *msg =
container_of(hdr, typeof(*msg), msg.hdr);
return msg->falcon_mask;
}
static int
gp10b_pmu_acr_bootstrap_multiple_falcons(struct nvkm_falcon *falcon, u32 mask)
{
struct nvkm_pmu *pmu = container_of(falcon, typeof(*pmu), falcon);
struct nv_pmu_acr_bootstrap_multiple_falcons_cmd cmd = {
.cmd.hdr.unit_id = NV_PMU_UNIT_ACR,
.cmd.hdr.size = sizeof(cmd),
.cmd.cmd_type = NV_PMU_ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS,
.flags = NV_PMU_ACR_BOOTSTRAP_MULTIPLE_FALCONS_FLAGS_RESET_YES,
.falcon_mask = mask,
.wpr_lo = 0, /*XXX*/
.wpr_hi = 0, /*XXX*/
};
int ret;
ret = nvkm_falcon_cmdq_send(pmu->hpq, &cmd.cmd.hdr,
gp10b_pmu_acr_bootstrap_multiple_falcons_cb,
&pmu->subdev, msecs_to_jiffies(1000));
if (ret >= 0 && ret != cmd.falcon_mask)
ret = -EIO;
return ret;
}
static const struct nvkm_acr_lsf_func static const struct nvkm_acr_lsf_func
gp10b_pmu_acr = { gp10b_pmu_acr = {
.bootstrap_falcon = gm20b_pmu_acr_bootstrap_falcon,
.bootstrap_multiple_falcons = gp10b_pmu_acr_bootstrap_multiple_falcons,
}; };
static const struct nvkm_pmu_func static const struct nvkm_pmu_func
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#define nvkm_pmu(p) container_of((p), struct nvkm_pmu, subdev) #define nvkm_pmu(p) container_of((p), struct nvkm_pmu, subdev)
#include <subdev/pmu.h> #include <subdev/pmu.h>
#include <subdev/pmu/fuc/os.h> #include <subdev/pmu/fuc/os.h>
enum nvkm_acr_lsf_id;
struct nvkm_pmu_func { struct nvkm_pmu_func {
const struct nvkm_falcon_func *flcn; const struct nvkm_falcon_func *flcn;
...@@ -41,6 +42,7 @@ void gf100_pmu_reset(struct nvkm_pmu *); ...@@ -41,6 +42,7 @@ void gf100_pmu_reset(struct nvkm_pmu *);
void gk110_pmu_pgob(struct nvkm_pmu *, bool); void gk110_pmu_pgob(struct nvkm_pmu *, bool);
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 *);
struct nvkm_pmu_fwif { struct nvkm_pmu_fwif {
......
...@@ -991,12 +991,13 @@ acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb, ...@@ -991,12 +991,13 @@ acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb,
* load the HS firmware and run it, so once the falcon stops all the managed * load the HS firmware and run it, so once the falcon stops all the managed
* falcons should have their LS firmware loaded and be ready to run. * falcons should have their LS firmware loaded and be ready to run.
*/ */
int nvkm_acr_bootstrap_falcons(struct nvkm_device *, unsigned long);
static int static int
acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb, acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
unsigned long falcon_mask) unsigned long falcon_mask)
{ {
struct acr_r352 *acr = acr_r352(_acr); struct acr_r352 *acr = acr_r352(_acr);
struct nvkm_msgqueue *queue;
int falcon; int falcon;
bool wpr_already_set = sb->wpr_set; bool wpr_already_set = sb->wpr_set;
int ret; int ret;
...@@ -1016,22 +1017,12 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb, ...@@ -1016,22 +1017,12 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
return ret; return ret;
} }
switch (_acr->boot_falcon) {
case NVKM_SECBOOT_FALCON_PMU:
queue = sb->subdev.device->pmu->queue;
break;
case NVKM_SECBOOT_FALCON_SEC2:
queue = sb->subdev.device->sec2->queue;
break;
default:
return -EINVAL;
}
/* Otherwise just ask the LS firmware to reset the falcon */ /* Otherwise just ask the LS firmware to reset the falcon */
for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END) for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END)
nvkm_debug(&sb->subdev, "resetting %s falcon\n", nvkm_debug(&sb->subdev, "resetting %s falcon\n",
nvkm_secboot_falcon_name[falcon]); nvkm_secboot_falcon_name[falcon]);
ret = nvkm_msgqueue_acr_boot_falcons(queue, falcon_mask);
ret = nvkm_acr_bootstrap_falcons(sb->subdev.device, falcon_mask);
if (ret) { if (ret) {
nvkm_error(&sb->subdev, "error during falcon reset: %d\n", ret); nvkm_error(&sb->subdev, "error during falcon reset: %d\n", ret);
return ret; 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