blob: d65cb4adfca695aaa080e5386d6c6d310a78f0f4 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Mailbox manager abstracts the mailbox interfaces of user commands.
*
* Copyright (C) 2022 Google LLC
*/
#include "gxp-mailbox-driver.h"
#include "gxp-mailbox-manager.h"
#include "gxp-mailbox.h"
#include "gxp.h"
#if GXP_HAS_MCU
#include "gxp-mcu-platform.h"
#endif
#define DEBUGFS_MAILBOX "mailbox"
static int debugfs_mailbox_execute_cmd(void *data, u64 val)
{
int core = 0, retval;
u16 status;
struct gxp_dev *gxp = (struct gxp_dev *)data;
struct gxp_mailbox *mbx;
struct gxp_client *client;
struct gxp_power_states power_states = {
.power = GXP_POWER_STATE_NOM,
.memory = MEMORY_POWER_STATE_UNDEFINED,
};
u16 cmd_code;
int ret;
mutex_lock(&gxp->debugfs_client_lock);
client = gxp->debugfs_client;
if (gxp_is_direct_mode(gxp)) {
core = val / 1000;
if (core >= GXP_NUM_CORES) {
dev_notice(gxp->dev,
"Mailbox for core %d doesn't exist.\n",
core);
ret = -EINVAL;
goto out;
}
if (gxp->mailbox_mgr->mailboxes[core] == NULL) {
dev_notice(
gxp->dev,
"Unable to send mailbox command -- mailbox %d not ready\n",
core);
ret = -EINVAL;
goto out;
}
/* Create a dummy client to access @client->gxp from the `execute_cmd` callback. */
if (!client)
client = gxp_client_create(gxp);
mbx = gxp->mailbox_mgr->mailboxes[core];
cmd_code = GXP_MBOX_CODE_DISPATCH;
} else {
#if GXP_HAS_MCU
if (!client) {
dev_err(gxp->dev,
"You should load firmwares via gxp/firmware_run first\n");
ret = -EIO;
goto out;
}
down_read(&gxp->debugfs_client->semaphore);
if (!gxp_client_has_available_vd(gxp->debugfs_client,
"GXP_MAILBOX_COMMAND")) {
ret = -ENODEV;
up_read(&gxp->debugfs_client->semaphore);
goto out;
}
up_read(&gxp->debugfs_client->semaphore);
mbx = to_mcu_dev(gxp)->mcu.uci.mbx;
if (!mbx) {
dev_err(gxp->dev, "UCI is not initialized.\n");
ret = -EIO;
goto out;
}
cmd_code = CORE_COMMAND;
#endif /* GXP_HAS_MCU */
}
retval = gxp->mailbox_mgr->execute_cmd(client, mbx, core, cmd_code, 0,
0, 0, 0, 1, power_states, NULL,
&status);
dev_info(
gxp->dev,
"Mailbox Command Sent: core=%d, resp.status=%d, resp.retval=%d\n",
core, status, retval);
ret = 0;
out:
if (client && client != gxp->debugfs_client)
gxp_client_destroy(client);
mutex_unlock(&gxp->debugfs_client_lock);
return ret;
}
DEFINE_DEBUGFS_ATTRIBUTE(debugfs_mailbox_fops, NULL,
debugfs_mailbox_execute_cmd, "%llu\n");
struct gxp_mailbox_manager *gxp_mailbox_create_manager(struct gxp_dev *gxp,
uint num_cores)
{
struct gxp_mailbox_manager *mgr;
mgr = devm_kzalloc(gxp->dev, sizeof(*mgr), GFP_KERNEL);
if (!mgr)
return ERR_PTR(-ENOMEM);
mgr->gxp = gxp;
mgr->num_cores = num_cores;
mgr->get_mailbox_csr_base = gxp_mailbox_get_csr_base;
mgr->get_mailbox_data_base = gxp_mailbox_get_data_base;
mgr->mailboxes = devm_kcalloc(gxp->dev, mgr->num_cores,
sizeof(*mgr->mailboxes), GFP_KERNEL);
if (!mgr->mailboxes)
return ERR_PTR(-ENOMEM);
debugfs_create_file(DEBUGFS_MAILBOX, 0200, gxp->d_entry, gxp,
&debugfs_mailbox_fops);
return mgr;
}
void gxp_mailbox_destroy_manager(struct gxp_dev *gxp,
struct gxp_mailbox_manager *mgr)
{
debugfs_remove(debugfs_lookup(DEBUGFS_MAILBOX, gxp->d_entry));
devm_kfree(gxp->dev, mgr->mailboxes);
devm_kfree(gxp->dev, mgr);
}