voice-proto: AMDB module pre-loading, longer cmd timeout
Three findings from the 2026-07-10 warm-capture session (journal/calls.md): the stock voice sequence is byte-identical warm vs cold, so our replay bytes were never the problem; VCPM rejects TX-side cal (EBADPARAM) while accepting byte-identical RX cal through the same transport; and a voice GRAPH_OPEN that has to FastRPC-load the Fluence pp modules takes >120 s cold, so the client-side timeout/verify dance leaves failed opens in VCPM's session history. - apm_callback: handle AMDB_CMD_RSP_LOAD_MODULES (AMDB load responds with its own opcode, not an ibasic result); log per-module handles (handle 0 = not registered - e.g. 0x70010a3, which only appears after fluence_nn_module_fvxiii.so.1 is parsed). - voice-proto: Q6VP_DSTPORT_FLAG record flag - first payload word carries the GPR destination port, so blobs can address static services other than APM (AMDB port 3 module pre-loading via mkamdbload.py). - Raise the shared command timeout to 300 s so a cold TX voice GRAPH_OPEN (~125 s through the Fluence loads) completes inside ONE command with no retry dance. Assisted-by: Claude:claude-fable-5 Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
This commit is contained in:
parent
3c381d76fc
commit
cfc2b6a276
4 changed files with 67 additions and 7 deletions
|
|
@ -601,9 +601,9 @@ int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev,
|
|||
|
||||
if (rsp_opcode)
|
||||
rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode) ||
|
||||
(result->opcode == rsp_opcode), 30 * HZ);
|
||||
(result->opcode == rsp_opcode), 240 * HZ);
|
||||
else
|
||||
rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode), 30 * HZ);
|
||||
rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode), 240 * HZ);
|
||||
|
||||
if (!rc) {
|
||||
dev_err(dev, "CMD timeout for [%x] opcode\n", hdr->opcode);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ struct q6apm_graph;
|
|||
#define APM_CMD_RSP_GET_CFG 0x02001000
|
||||
#define APM_CMD_CLOSE_ALL 0x01001013
|
||||
#define APM_CMD_REGISTER_SHARED_CFG 0x0100100A
|
||||
#define AMDB_CMD_LOAD_MODULES 0x01001020
|
||||
#define AMDB_CMD_RSP_LOAD_MODULES 0x02001008
|
||||
|
||||
#define APM_MEMORY_MAP_SHMEM8_4K_POOL 3
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,17 @@
|
|||
* subgraph invalid (rejected at open) — see journal/calls.md 2026-07-08.
|
||||
*/
|
||||
#define Q6VP_OOB_FLAG 0x80000000
|
||||
/*
|
||||
* A record opcode with this bit set carries the GPR destination port in the
|
||||
* first payload word (stripped before sending). Lets a blob address static
|
||||
* services other than APM — e.g. AMDB (port 3) module pre-loading, so the
|
||||
* dynamic Fluence pp modules can be made resident BEFORE the voice
|
||||
* GRAPH_OPENs. A first open that has to FastRPC-load them can fail or block
|
||||
* so long that the client-side retry dance corrupts VCPM's per-VSID voice
|
||||
* session (TX cal EBADPARAM / TX START EFAILED, journal/calls.md
|
||||
* 2026-07-10). In-band records only.
|
||||
*/
|
||||
#define Q6VP_DSTPORT_FLAG 0x40000000
|
||||
#define Q6VP_GRAPH_ID 0xf000 /* private mem-map handle owner */
|
||||
#define Q6VP_BUF_SZ 0x800000 /* 8 MiB shared region */
|
||||
#define Q6VP_SCRATCH_SZ 0x10000 /* [0, 64K): transient commands */
|
||||
|
|
@ -60,6 +71,7 @@ struct q6vp_rec {
|
|||
__le32 size;
|
||||
} __packed;
|
||||
|
||||
static DEFINE_MUTEX(q6vp_play_lock);
|
||||
static struct q6apm *q6vp_apm;
|
||||
static struct dentry *q6vp_dir;
|
||||
static struct device *q6vp_dais_dev;
|
||||
|
|
@ -70,16 +82,32 @@ static phys_addr_t q6vp_buf_dsp_addr;
|
|||
|
||||
static int q6vp_send(uint32_t opcode, const void *payload, uint32_t size)
|
||||
{
|
||||
uint32_t dest_port = APM_MODULE_INSTANCE_ID;
|
||||
uint32_t rsp_opcode = 0;
|
||||
struct gpr_pkt *pkt;
|
||||
int ret;
|
||||
|
||||
pkt = audioreach_alloc_apm_cmd_pkt(size, opcode, 0);
|
||||
if (opcode & Q6VP_DSTPORT_FLAG) {
|
||||
if (size < sizeof(__le32))
|
||||
return -EINVAL;
|
||||
dest_port = le32_to_cpup(payload);
|
||||
payload += sizeof(__le32);
|
||||
size -= sizeof(__le32);
|
||||
opcode &= ~Q6VP_DSTPORT_FLAG;
|
||||
}
|
||||
|
||||
/* AMDB load responds with its own opcode, not an ibasic result */
|
||||
if (opcode == AMDB_CMD_LOAD_MODULES)
|
||||
rsp_opcode = AMDB_CMD_RSP_LOAD_MODULES;
|
||||
|
||||
pkt = audioreach_alloc_cmd_pkt(size, opcode, 0, GPR_APM_MODULE_IID,
|
||||
dest_port);
|
||||
if (IS_ERR(pkt))
|
||||
return PTR_ERR(pkt);
|
||||
|
||||
memcpy((void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE, payload, size);
|
||||
|
||||
ret = q6apm_send_cmd_sync(q6vp_apm, pkt, 0);
|
||||
ret = q6apm_send_cmd_sync(q6vp_apm, pkt, rsp_opcode);
|
||||
kfree(pkt);
|
||||
|
||||
return ret;
|
||||
|
|
@ -254,12 +282,15 @@ static int q6vp_play(const char *name)
|
|||
}
|
||||
|
||||
if (opcode & Q6VP_OOB_FLAG)
|
||||
ret = q6vp_send_oob(opcode & ~Q6VP_OOB_FLAG,
|
||||
fw->data + off, size);
|
||||
ret = (opcode & Q6VP_DSTPORT_FLAG) ? -EINVAL :
|
||||
q6vp_send_oob(opcode & ~Q6VP_OOB_FLAG,
|
||||
fw->data + off, size);
|
||||
else
|
||||
ret = q6vp_send(opcode, fw->data + off, size);
|
||||
dev_info(dev, "voice-proto: %s[%u] opcode 0x%08x size %u -> %d\n",
|
||||
name, i, opcode & ~Q6VP_OOB_FLAG, size, ret);
|
||||
name, i,
|
||||
opcode & ~(Q6VP_OOB_FLAG | Q6VP_DSTPORT_FLAG),
|
||||
size, ret);
|
||||
/* keep going on DSP rejections; each result is logged */
|
||||
if (ret)
|
||||
err = ret;
|
||||
|
|
@ -287,7 +318,17 @@ static ssize_t q6vp_play_write(struct file *file, const char __user *ubuf,
|
|||
name[count] = '\0';
|
||||
strim(name);
|
||||
|
||||
/*
|
||||
* Serialize blob playback: concurrent debugfs writers (e.g. a
|
||||
* dropped ssh session whose write is still stuck in a DSP wait)
|
||||
* would interleave their records on the GPR channel and corrupt
|
||||
* both sequences (seen 2026-07-10).
|
||||
*/
|
||||
ret = mutex_lock_interruptible(&q6vp_play_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = q6vp_play(name);
|
||||
mutex_unlock(&q6vp_play_lock);
|
||||
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -853,6 +853,23 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case AMDB_CMD_RSP_LOAD_MODULES: {
|
||||
/* amdb_module_load_unload_t: proc_domain, error_code,
|
||||
* num_modules, {module_id, handle_lsw, handle_msw}[].
|
||||
* A zero handle = module not registered with the AMDB.
|
||||
*/
|
||||
const u32 *amdb = data->payload;
|
||||
u32 i, n = amdb[2];
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
dev_info(dev, "AMDB load: module 0x%08x handle 0x%08x%08x\n",
|
||||
amdb[3 + 3 * i], amdb[5 + 3 * i],
|
||||
amdb[4 + 3 * i]);
|
||||
apm->result.opcode = hdr->opcode;
|
||||
apm->result.status = amdb[1];
|
||||
wake_up(&apm->wait);
|
||||
break;
|
||||
}
|
||||
case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS:
|
||||
apm->result.opcode = hdr->opcode;
|
||||
apm->result.status = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue