diff --git a/arch/arm64/boot/dts/qcom/milos.dtsi b/arch/arm64/boot/dts/qcom/milos.dtsi index 0f95a9976de7..288e0e658629 100644 --- a/arch/arm64/boot/dts/qcom/milos.dtsi +++ b/arch/arm64/boot/dts/qcom/milos.dtsi @@ -548,14 +548,6 @@ no-map; }; - adsp_rpc_heap_mem: adsp-rpc-heap { - compatible = "shared-dma-pool"; - alloc-ranges = <0x0 0x0 0x0 0xffffffff>; - reusable; - alignment = <0x0 0x400000>; - size = <0x0 0xc00000>; - }; - pvm_fw_mem: pvm-fw-region@824a0000 { reg = <0x0 0x824a0000 0x0 0x100000>; no-map; @@ -1406,9 +1398,6 @@ qcom,glink-channels = "fastrpcglink-apps-dsp"; label = "adsp"; qcom,non-secure-domain; - memory-region = <&adsp_rpc_heap_mem>; - qcom,vmids = ; #address-cells = <1>; #size-cells = <0>; @@ -1433,8 +1422,6 @@ reg = <5>; iommus = <&apps_smmu 0x1005 0x0>, <&apps_smmu 0x1065 0x0>; - /* AUDIO_STATICPD bank, per downstream volcano-dsp.dtsi */ - pd-type = <2>; dma-coherent; }; diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index cb29a429af78..f3a49384586d 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -103,13 +103,6 @@ #define USER_PD (1) #define SENSORS_PD (2) -/* - * Downstream DT "pd-type" context-bank designations (volcano-dsp.dtsi). - * A static PD must be spawned on its designated context bank / SMMU - * stream or the DSP treats it as a generic signed PD. - */ -#define FASTRPC_DT_PD_TYPE_AUDIO_STATICPD 2 - #define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev) struct fastrpc_phy_page { @@ -262,8 +255,6 @@ struct fastrpc_session_ctx { int sid; bool used; bool valid; - /* downstream DT pd-type this context bank is dedicated to (0 = generic) */ - u32 pd_type; }; struct fastrpc_soc_data { @@ -323,11 +314,6 @@ struct fastrpc_user { struct kref refcount; }; -static struct fastrpc_session_ctx *fastrpc_session_alloc_pd_type( - struct fastrpc_user *fl, u32 pd_type); -static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx, - struct fastrpc_session_ctx *session); - /* Extract SMMU PA from consolidated IOVA */ static inline dma_addr_t fastrpc_ipa_to_dma_addr(struct fastrpc_channel_ctx *cctx, dma_addr_t iova) { @@ -1357,7 +1343,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl, struct fastrpc_phy_page pages[1]; char *name; int err; - bool scm_done = false, heap_created = false; + bool scm_done = false; struct { int client_id; u32 namelen; @@ -1385,35 +1371,11 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl, goto err; } - /* - * The audio static PD must live on its designated context bank so the - * DSP sees its memory on the audio SMMU stream; on a generic bank the - * aDSP enforces module signing in the PD (dlopen of unsigned dynamic - * modules fails demanding a testsig). Re-route before anything is - * allocated against the session. Falls back to the already-held - * generic session if no bank is tagged in DT. - */ - if (init.namelen >= strlen("audiopd") && - !memcmp(name, "audiopd", strlen("audiopd"))) { - struct fastrpc_session_ctx *audio_sess; - - audio_sess = fastrpc_session_alloc_pd_type(fl, - FASTRPC_DT_PD_TYPE_AUDIO_STATICPD); - if (audio_sess) { - fastrpc_session_free(fl->cctx, fl->sctx); - fl->sctx = audio_sess; - } - dev_info(&fl->cctx->rpdev->dev, - "audiopd: using session sid %d (%s)\n", fl->sctx->sid, - audio_sess ? "dedicated audio CB" : "no audio CB in DT"); - } - if (!fl->cctx->remote_heap) { err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen, &fl->cctx->remote_heap); if (err) goto err_name; - heap_created = true; /* Map if we have any heap VMIDs associated with this ADSP Static Process. */ if (fl->cctx->vmcount) { @@ -1484,16 +1446,8 @@ err_invoke: &fl->cctx->remote_heap->dma_addr, fl->cctx->remote_heap->size, err); } err_map: - /* - * A heap reused from an earlier spawn is still SCM-assigned to the - * remote VMIDs; freeing it here would return protected pages to the - * allocator and a later touch crashes with a synchronous external - * abort. Keep it for the next spawn attempt. - */ - if (heap_created) { - fastrpc_buf_free(fl->cctx->remote_heap); - fl->cctx->remote_heap = NULL; - } + fastrpc_buf_free(fl->cctx->remote_heap); + fl->cctx->remote_heap = NULL; err_name: kfree(name); err: @@ -1628,9 +1582,7 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc( spin_lock_irqsave(&cctx->lock, flags); for (i = 0; i < cctx->sesscount; i++) { - /* dedicated static-PD context banks are assigned by pd_type only */ - if (!cctx->session[i].used && cctx->session[i].valid && - !cctx->session[i].pd_type) { + if (!cctx->session[i].used && cctx->session[i].valid) { cctx->session[i].used = true; session = &cctx->session[i]; /* any non-zero ID will work, session_idx + 1 is the simplest one */ @@ -1643,29 +1595,6 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc( return session; } -static struct fastrpc_session_ctx *fastrpc_session_alloc_pd_type( - struct fastrpc_user *fl, u32 pd_type) -{ - struct fastrpc_channel_ctx *cctx = fl->cctx; - struct fastrpc_session_ctx *session = NULL; - unsigned long flags; - int i; - - spin_lock_irqsave(&cctx->lock, flags); - for (i = 0; i < cctx->sesscount; i++) { - if (!cctx->session[i].used && cctx->session[i].valid && - cctx->session[i].pd_type == pd_type) { - cctx->session[i].used = true; - session = &cctx->session[i]; - fl->client_id = i + 1; - break; - } - } - spin_unlock_irqrestore(&cctx->lock, flags); - - return session; -} - static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx, struct fastrpc_session_ctx *session) { @@ -2322,9 +2251,6 @@ static int fastrpc_cb_probe(struct platform_device *pdev) if (of_property_read_u32(dev->of_node, "reg", &sess->sid)) dev_info(dev, "FastRPC Session ID not specified in DT\n"); - sess->pd_type = 0; - of_property_read_u32(dev->of_node, "pd-type", &sess->pd_type); - if (sessions > 0) { struct fastrpc_session_ctx *dup_sess; diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c index aae337572be7..db823177e636 100644 --- a/net/qrtr/af_qrtr.c +++ b/net/qrtr/af_qrtr.c @@ -520,54 +520,6 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) qrtr_node_assign(node, le32_to_cpu(pkt->server.node)); } - /* The DSPs are star-connected through this node: forward packets - * destined to another node onto that node's endpoint (e.g. the - * modem's voice stack talking to the ADSP's audio service). Only - * DATA and RESUME_TX transit; control packets keep going to the - * local ns, which does its own mesh-wide redistribution. RESUME_TX - * additionally releases this hop's flow-control token on the - * arrival link: per-hop counters advance in lockstep with the - * end-to-end ones since every packet of the flow transits here. - */ - if (cb->dst_node != qrtr_local_nid && - cb->dst_node != QRTR_NODE_BCAST && - (cb->type == QRTR_TYPE_DATA || cb->type == QRTR_TYPE_RESUME_TX)) { - struct sockaddr_qrtr from = {AF_QIPCRTR, - cb->src_node, cb->src_port}; - struct sockaddr_qrtr to = {AF_QIPCRTR, - cb->dst_node, cb->dst_port}; - struct qrtr_node *dst; - - dst = qrtr_node_lookup(cb->dst_node); - if (!dst || dst == node) { - if (dst) - qrtr_node_release(dst); - goto err; - } - - if (cb->type == QRTR_TYPE_RESUME_TX) { - struct sk_buff *clone; - - clone = skb_clone(skb, GFP_ATOMIC); - if (clone) - qrtr_tx_resume(node, clone); - } - - pr_debug("qrtr: fwd %u:%u -> %u:%u type %d len %zu\n", - cb->src_node, cb->src_port, - cb->dst_node, cb->dst_port, cb->type, size); - - if (skb_cow_head(skb, sizeof(struct qrtr_hdr_v1))) { - qrtr_node_release(dst); - goto err; - } - - qrtr_node_enqueue(dst, skb, cb->type, &from, &to); - qrtr_node_release(dst); - - return 0; - } - if (cb->type == QRTR_TYPE_RESUME_TX) { qrtr_tx_resume(node, skb); } else { diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c index 47a66db76cf1..b3f9bbcf9ab9 100644 --- a/net/qrtr/ns.c +++ b/net/qrtr/ns.c @@ -70,7 +70,6 @@ struct qrtr_node { unsigned int id; struct xarray servers; u32 server_count; - bool hello; }; /* Max nodes, server, lookup limits are chosen based on the current platform @@ -213,60 +212,6 @@ static void lookup_notify(struct sockaddr_qrtr *to, struct qrtr_server *srv, pr_err("failed to send lookup notification\n"); } -/* FP6 voice bring-up: the DSP firmwares expect the downstream IPC-router - * flooding model - they never send NEW_LOOKUP for services on their peers - * and instead rely on the application processor pushing announcements to - * every link. The modem's voice stack locates the ADSP's service-registry - * notifier this way; without it Voice Services never sees avs/audio come - * up and never creates a vocoder session. - * - * Flooding every announcement to every node wedges the phone within - * seconds of the DSPs booting (control packets are exempt from qrtr flow - * control, so any echo between routers runs unbounded). Push exactly the - * one edge voice needs: ADSP-hosted servers, to the modem, only. Any echo - * is structurally loop-free: a re-announcement of an ADSP server arriving - * from the modem is pushed to nobody (target == origin). - */ -#define QRTR_NS_FWD_SRC_NODE 5 /* adsp */ -#define QRTR_NS_FWD_DST_NODE 0 /* modem */ - -/* Runtime kill-switch (qrtr.fp6_ns_push): off by default so a boot is - * always calm; flip it on, then restart the modem rproc so its HELLO - * triggers the replay. - */ -static bool fp6_ns_push; -module_param(fp6_ns_push, bool, 0644); -MODULE_PARM_DESC(fp6_ns_push, "FP6: push adsp service announcements to the modem"); - -static void service_announce_remotes(struct qrtr_server *srv, - unsigned int origin, bool new) -{ - struct sockaddr_qrtr sq; - struct qrtr_node *node; - - if (!fp6_ns_push) - return; - if (srv->node != QRTR_NS_FWD_SRC_NODE) - return; - if (origin == QRTR_NS_FWD_DST_NODE || - srv->node == QRTR_NS_FWD_DST_NODE || - qrtr_ns.local_node == QRTR_NS_FWD_DST_NODE) - return; - - node = xa_load(&nodes, QRTR_NS_FWD_DST_NODE); - if (!node || !node->hello) - return; - - sq.sq_family = AF_QIPCRTR; - sq.sq_node = QRTR_NS_FWD_DST_NODE; - sq.sq_port = QRTR_PORT_CTRL; - - if (new) - service_announce_new(&sq, srv); - else - service_announce_del(&sq, srv); -} - static int announce_servers(struct sockaddr_qrtr *sq) { struct qrtr_server *srv; @@ -289,24 +234,6 @@ static int announce_servers(struct sockaddr_qrtr *sq) return ret; } } - - /* FP6 voice: replay the ADSP's servers to a (re)booting modem (see - * service_announce_remotes()) - */ - if (fp6_ns_push && sq->sq_node == QRTR_NS_FWD_DST_NODE) { - node = xa_load(&nodes, QRTR_NS_FWD_SRC_NODE); - if (!node) - return 0; - - xa_for_each(&node->servers, index, srv) { - ret = service_announce_new(sq, srv); - if (ret < 0 && ret != -ENODEV) { - pr_err("failed to announce new service\n"); - return ret; - } - } - } - return 0; } @@ -381,8 +308,6 @@ static int server_del(struct qrtr_node *node, unsigned int port, bool bcast) /* Broadcast the removal of local servers */ if (srv->node == qrtr_ns.local_node && bcast) service_announce_del(&qrtr_ns.bcast_sq, srv); - else if (bcast) - service_announce_remotes(srv, srv->node, false); /* Announce the service's disappearance to observers */ list_for_each(li, &qrtr_ns.lookups) { @@ -427,13 +352,8 @@ static int say_hello(struct sockaddr_qrtr *dest) /* Announce the list of servers registered on the local node */ static int ctrl_cmd_hello(struct sockaddr_qrtr *sq) { - struct qrtr_node *node; int ret; - node = node_get(sq->sq_node); - if (node) - node->hello = true; - ret = say_hello(sq); if (ret < 0) return ret; @@ -601,8 +521,6 @@ static int ctrl_cmd_new_server(struct sockaddr_qrtr *from, pr_err("failed to announce new service\n"); return ret; } - } else { - service_announce_remotes(srv, from->sq_node, true); } /* Notify any potential lookups about the new server */ diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index d650e0b0ba5b..67267304e7e9 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only snd-q6dsp-common-y := q6dsp-common.o q6dsp-lpass-ports.o q6dsp-lpass-clocks.o -snd-q6apm-y := q6apm.o audioreach.o topology.o q6apm-voice-proto.o +snd-q6apm-y := q6apm.o audioreach.o topology.o obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += snd-q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index 4fea75b021e8..a13f753eff98 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -576,11 +576,10 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, } EXPORT_SYMBOL_GPL(audioreach_alloc_graph_pkt); -int audioreach_send_cmd_sync_timeout(struct device *dev, gpr_device_t *gdev, +int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, struct gpr_ibasic_rsp_result_t *result, struct mutex *cmd_lock, gpr_port_t *port, wait_queue_head_t *cmd_wait, - const struct gpr_pkt *pkt, uint32_t rsp_opcode, - unsigned long timeout_s) + const struct gpr_pkt *pkt, uint32_t rsp_opcode) { const struct gpr_hdr *hdr = &pkt->hdr; @@ -602,9 +601,9 @@ int audioreach_send_cmd_sync_timeout(struct device *dev, gpr_device_t *gdev, if (rsp_opcode) rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode) || - (result->opcode == rsp_opcode), timeout_s * HZ); + (result->opcode == rsp_opcode), 5 * HZ); else - rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode), timeout_s * HZ); + rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode), 5 * HZ); if (!rc) { dev_err(dev, "CMD timeout for [%x] opcode\n", hdr->opcode); @@ -621,16 +620,6 @@ err: mutex_unlock(cmd_lock); return rc; } -EXPORT_SYMBOL_GPL(audioreach_send_cmd_sync_timeout); - -int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, - struct gpr_ibasic_rsp_result_t *result, struct mutex *cmd_lock, - gpr_port_t *port, wait_queue_head_t *cmd_wait, - const struct gpr_pkt *pkt, uint32_t rsp_opcode) -{ - return audioreach_send_cmd_sync_timeout(dev, gdev, result, cmd_lock, - port, cmd_wait, pkt, rsp_opcode, 30); -} EXPORT_SYMBOL_GPL(audioreach_send_cmd_sync); int audioreach_graph_send_cmd_sync(struct q6apm_graph *graph, const struct gpr_pkt *pkt, diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index e52c4b564cbc..6859770b38a6 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -58,15 +58,12 @@ struct q6apm_graph; #define APM_CMD_GRAPH_FLUSH 0x01001005 #define APM_CMD_SET_CFG 0x01001006 #define APM_CMD_GET_CFG 0x01001007 -#define APM_CMD_REGISTER_CFG 0x01001008 #define APM_CMD_SHARED_MEM_MAP_REGIONS 0x0100100C #define APM_CMD_SHARED_MEM_UNMAP_REGIONS 0x0100100D #define APM_CMD_RSP_SHARED_MEM_MAP_REGIONS 0x02001001 #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 @@ -845,11 +842,6 @@ void audioreach_graph_free_buf(struct q6apm_graph *graph); int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, struct gpr_ibasic_rsp_result_t *result, struct mutex *cmd_lock, gpr_port_t *port, wait_queue_head_t *cmd_wait, const struct gpr_pkt *pkt, uint32_t rsp_opcode); -int audioreach_send_cmd_sync_timeout(struct device *dev, gpr_device_t *gdev, - struct gpr_ibasic_rsp_result_t *result, - struct mutex *cmd_lock, gpr_port_t *port, wait_queue_head_t *cmd_wait, - const struct gpr_pkt *pkt, uint32_t rsp_opcode, - unsigned long timeout_s); int audioreach_graph_send_cmd_sync(struct q6apm_graph *graph, const struct gpr_pkt *pkt, uint32_t rsp_opcode); int audioreach_set_media_format(struct q6apm_graph *graph, diff --git a/sound/soc/qcom/qdsp6/q6apm-voice-proto.c b/sound/soc/qcom/qdsp6/q6apm-voice-proto.c deleted file mode 100644 index 87055f979e7a..000000000000 --- a/sound/soc/qcom/qdsp6/q6apm-voice-proto.c +++ /dev/null @@ -1,380 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Voice-call bring-up prototype for the Fairphone (Gen. 6): replay - * pre-generated APM command sequences through the q6apm GPR channel. - * - * The blobs reproduce, byte for byte, the GRAPH_OPEN/SET_CFG/PREPARE/START - * sequence the stock Android PAL/AGM/GSL stack sends to set up the - * handset voice-call graphs (mined from the device ACDB; generated by - * utilities/mkvoiceblobs.py in the bring-up repo). The modem's voice - * engine and the ADSP VCPM service wire up the vocoder themselves once - * these graphs are running. - * - * Local prototype only, NOT for upstream. Interface: - * echo > /sys/kernel/debug/q6apm-voice-proto/play - * where is relative to /lib/firmware. Playback aborts on the - * first command the DSP rejects. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "audioreach.h" -#include "q6apm.h" - -#define Q6VP_MAGIC 0x50563651 /* "Q6VP" little-endian */ -#define Q6VP_VERSION 1 - -/* - * A record opcode with this bit set is sent out-of-band: the payload is - * placed in an ADSP-mapped shared-memory region and the GPR command carries - * only an apm_cmd_header referencing it. Stock GSL sends every voice - * GRAPH_OPEN this way; it is mandatory because a voice graph must be opened - * atomically as one command (all subgraphs + cross-subgraph module - * connections and control links), and the whole payload (~4.3-4.7 KB) - * exceeds the ~4 KiB in-band GPR/GLINK intent limit. Splitting the open - * per-subgraph to fit in-band makes the cross-referencing TX DevicePP - * 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 */ -#define Q6VP_SID_MASK 0xf - -struct q6vp_hdr { - __le32 magic; - __le32 version; - __le32 num_records; -} __packed; - -struct q6vp_rec { - __le32 opcode; - __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; -static struct audioreach_graph_info *q6vp_info; -static void *q6vp_buf; -static dma_addr_t q6vp_buf_iova; -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; - - 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; - /* GET_CFG responds with the param data; payload dumped in callback */ - if (opcode == APM_CMD_GET_CFG) - rsp_opcode = APM_CMD_RSP_GET_CFG; - - 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); - - /* - * Voice blobs need the long wait: a cold TX GRAPH_OPEN that has to - * FastRPC-load the Fluence pp modules takes >120 s. Regular audio - * commands (and especially the probe-time GET_SPF_STATE ready poll) - * must keep the short default or they hold the shared command mutex - * hostage at boot: a 240 s stall in apm_probe delays module loading - * past udev's worker timeout and the sound card never assembles. - */ - ret = q6apm_send_cmd_sync_timeout(q6vp_apm, pkt, rsp_opcode, 240); - kfree(pkt); - - return ret; -} - -/* - * Lazily set up the shared-memory region used for OOB commands: allocate a - * DMA buffer against the q6apm-dais child device (it carries the iommus - * mapping the ADSP expects, same as the PCM data path), register a private - * graph_info so the APM_CMD_RSP_SHARED_MEM_MAP_REGIONS callback has a slot - * to store the handle in, and map the region with the DSP. The mapping is - * kept until the module goes away. - */ -static int q6vp_oob_init(void) -{ - struct device *dev = q6vp_apm->dev; - struct of_phandle_args args; - struct platform_device *pdev; - struct device_node *np; - u64 sid = 0; - u32 graph_id = Q6VP_GRAPH_ID; - int ret; - - if (q6vp_info && q6vp_info->mem_map_handle) - return 0; - - if (!q6vp_dais_dev) { - np = of_get_compatible_child(dev->of_node, "qcom,q6apm-dais"); - if (!np) { - dev_err(dev, "voice-proto: no q6apm-dais node\n"); - return -ENODEV; - } - if (!of_parse_phandle_with_fixed_args(np, "iommus", 1, 0, - &args)) { - sid = args.args[0] & Q6VP_SID_MASK; - of_node_put(args.np); - } - pdev = of_find_device_by_node(np); - of_node_put(np); - if (!pdev) { - dev_err(dev, "voice-proto: no q6apm-dais device\n"); - return -ENODEV; - } - q6vp_dais_dev = &pdev->dev; - - q6vp_buf = dma_alloc_coherent(q6vp_dais_dev, Q6VP_BUF_SZ, - &q6vp_buf_iova, GFP_KERNEL); - if (!q6vp_buf) - return -ENOMEM; - q6vp_buf_dsp_addr = q6vp_buf_iova | (sid << 32); - } - - if (!q6vp_info) { - q6vp_info = kzalloc(sizeof(*q6vp_info), GFP_KERNEL); - if (!q6vp_info) - return -ENOMEM; - INIT_LIST_HEAD(&q6vp_info->sg_list); - q6vp_info->id = Q6VP_GRAPH_ID; - ret = idr_alloc_u32(&q6vp_apm->graph_info_idr, q6vp_info, - &graph_id, graph_id, GFP_KERNEL); - if (ret < 0) { - kfree(q6vp_info); - q6vp_info = NULL; - return ret; - } - } - - ret = q6apm_map_memory_fixed_region(q6vp_dais_dev, Q6VP_GRAPH_ID, - q6vp_buf_dsp_addr, Q6VP_BUF_SZ); - if (ret) { - dev_err(dev, "voice-proto: mem map failed (%d)\n", ret); - return ret; - } - - dev_info(dev, "voice-proto: OOB region mapped, handle 0x%x\n", - q6vp_info->mem_map_handle); - return 0; -} - -/* - * Persistent-slice bump offset: APM_CMD_REGISTER_CFG registers the payload - * with the DSP, which keeps reading that memory for as long as the config - * stays registered — those payloads must never be overwritten. They get - * bump-allocated slices above Q6VP_SCRATCH_SZ that live until reboot; - * transient commands (opens etc.) reuse the scratch slot at offset 0. - */ -static u32 q6vp_persist_off = Q6VP_SCRATCH_SZ; - -static int q6vp_send_oob(uint32_t opcode, const void *payload, uint32_t size) -{ - struct apm_cmd_header *cmd_header; - struct gpr_pkt *pkt; - u32 off = 0; - int ret; - - ret = q6vp_oob_init(); - if (ret) - return ret; - - if (opcode == APM_CMD_REGISTER_CFG) { - if (q6vp_persist_off + size > Q6VP_BUF_SZ) - return -EFBIG; - off = q6vp_persist_off; - q6vp_persist_off += ALIGN(size, SZ_4K); - } else if (size > Q6VP_SCRATCH_SZ) { - return -EFBIG; - } - - memcpy(q6vp_buf + off, payload, size); - - pkt = audioreach_alloc_apm_cmd_pkt(0, opcode, 0); - if (IS_ERR(pkt)) - return PTR_ERR(pkt); - - /* - * The region is mapped in absolute-address mode (mainline's - * q6apm_map_memory_fixed_region passes property_flag 0, unlike GSL - * which maps with IS_OFFSET_MODE and then references offset 0), so - * the header carries the full DSP-visible address of the buffer. - */ - cmd_header = (void *)pkt + GPR_HDR_SIZE; - cmd_header->payload_address_lsw = lower_32_bits(q6vp_buf_dsp_addr + off); - cmd_header->payload_address_msw = upper_32_bits(q6vp_buf_dsp_addr + off); - cmd_header->mem_map_handle = q6vp_info->mem_map_handle; - cmd_header->payload_size = size; - - ret = q6apm_send_cmd_sync_timeout(q6vp_apm, pkt, 0, 240); - kfree(pkt); - - return ret; -} - -static int q6vp_play(const char *name) -{ - const struct firmware *fw; - const struct q6vp_hdr *hdr; - const struct q6vp_rec *rec; - struct device *dev = q6vp_apm->dev; - size_t off; - uint32_t i, num, opcode, size; - int ret, err = 0; - - ret = request_firmware(&fw, name, dev); - if (ret) { - dev_err(dev, "voice-proto: cannot load %s (%d)\n", name, ret); - return ret; - } - - hdr = (const struct q6vp_hdr *)fw->data; - if (fw->size < sizeof(*hdr) || - le32_to_cpu(hdr->magic) != Q6VP_MAGIC || - le32_to_cpu(hdr->version) != Q6VP_VERSION) { - dev_err(dev, "voice-proto: %s: bad header\n", name); - ret = -EINVAL; - goto out; - } - - num = le32_to_cpu(hdr->num_records); - off = sizeof(*hdr); - for (i = 0; i < num; i++) { - if (off + sizeof(*rec) > fw->size) { - ret = -EINVAL; - goto out; - } - rec = (const struct q6vp_rec *)(fw->data + off); - opcode = le32_to_cpu(rec->opcode); - size = le32_to_cpu(rec->size); - off += sizeof(*rec); - if (off + size > fw->size) { - ret = -EINVAL; - goto out; - } - - if (opcode & Q6VP_OOB_FLAG) - 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 | Q6VP_DSTPORT_FLAG), - size, ret); - /* keep going on DSP rejections; each result is logged */ - if (ret) - err = ret; - - off += ALIGN(size, 4); - } - -out: - release_firmware(fw); - return ret ? ret : err; -} - -static ssize_t q6vp_play_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - char name[128]; - int ret; - - if (!q6vp_apm) - return -ENODEV; - if (count >= sizeof(name)) - return -EINVAL; - if (copy_from_user(name, ubuf, count)) - return -EFAULT; - 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; -} - -static const struct file_operations q6vp_play_fops = { - .open = simple_open, - .write = q6vp_play_write, - .llseek = default_llseek, -}; - -void q6apm_voice_proto_init(struct q6apm *apm) -{ - q6vp_apm = apm; - q6vp_dir = debugfs_create_dir("q6apm-voice-proto", NULL); - debugfs_create_file("play", 0200, q6vp_dir, NULL, &q6vp_play_fops); -} - -void q6apm_voice_proto_exit(void) -{ - debugfs_remove_recursive(q6vp_dir); - q6vp_dir = NULL; - - if (q6vp_info) { - if (q6vp_info->mem_map_handle) - q6apm_unmap_memory_fixed_region(q6vp_dais_dev, - Q6VP_GRAPH_ID); - idr_remove(&q6vp_apm->graph_info_idr, Q6VP_GRAPH_ID); - kfree(q6vp_info); - q6vp_info = NULL; - } - if (q6vp_buf) { - dma_free_coherent(q6vp_dais_dev, Q6VP_BUF_SZ, q6vp_buf, - q6vp_buf_iova); - q6vp_buf = NULL; - } - q6vp_dais_dev = NULL; - q6vp_apm = NULL; -} diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 220f61cbd4c3..2ab378fb5032 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -38,16 +38,6 @@ int q6apm_send_cmd_sync(struct q6apm *apm, const struct gpr_pkt *pkt, NULL, &apm->wait, pkt, rsp_opcode); } -int q6apm_send_cmd_sync_timeout(struct q6apm *apm, const struct gpr_pkt *pkt, - uint32_t rsp_opcode, unsigned long timeout_s) -{ - gpr_device_t *gdev = apm->gdev; - - return audioreach_send_cmd_sync_timeout(&gdev->dev, gdev, &apm->result, - &apm->lock, NULL, &apm->wait, - pkt, rsp_opcode, timeout_s); -} - static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, uint32_t graph_id) { struct audioreach_graph_info *info; @@ -774,8 +764,6 @@ static int apm_probe(gpr_device_t *gdev) g_apm = apm; - q6apm_voice_proto_init(apm); - q6apm_get_apm_state(apm); ret = snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0); @@ -793,7 +781,6 @@ static int apm_probe(gpr_device_t *gdev) static void apm_remove(gpr_device_t *gdev) { - q6apm_voice_proto_exit(); of_platform_depopulate(&gdev->dev); snd_soc_unregister_component(&gdev->dev); } @@ -830,7 +817,6 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op) case GPR_BASIC_RSP_RESULT: switch (result->opcode) { case APM_CMD_SHARED_MEM_MAP_REGIONS: - case APM_CMD_REGISTER_CFG: case APM_CMD_GRAPH_START: case APM_CMD_GRAPH_OPEN: case APM_CMD_GRAPH_PREPARE: @@ -838,7 +824,6 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op) case APM_CMD_GRAPH_FLUSH: case APM_CMD_GRAPH_STOP: case APM_CMD_SET_CFG: - case APM_CMD_GET_CFG: apm->result.opcode = result->opcode; apm->result.status = result->status; if (result->status) @@ -861,62 +846,9 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op) wake_up(&apm->wait); break; default: - /* - * Unlisted command results (debug/probe opcodes sent - * via voice-proto) must still wake the sync waiter or - * every such send stalls for the full timeout. - */ - apm->result.opcode = result->opcode; - apm->result.status = result->status; - if (result->status) - dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", - result->status, result->opcode); - wake_up(&apm->wait); break; } break; - case 0x03001000: { /* APM_EVENT_MODULE_TO_CLIENT */ - /* apm_module_event_t: event_id, payload_size, payload */ - const u32 *ev = data->payload; - u32 ev_sz = hdr->pkt_size - hdr->hdr_size * 4; - - dev_info(dev, "MODULE EVENT from 0x%x: event_id 0x%08x size %u\n", - hdr->src_port, ev[0], ev[1]); - print_hex_dump(KERN_INFO, "EVENT: ", DUMP_PREFIX_OFFSET, - 16, 4, ev, ev_sz, false); - break; - } - case APM_CMD_RSP_GET_CFG: { - /* status word, then apm_module_param_data_t sections */ - const u32 *rsp_pl = data->payload; - u32 pl_sz = hdr->pkt_size - hdr->hdr_size * 4; - - dev_info(dev, "GET_CFG rsp: status %d, %u bytes\n", - rsp_pl[0], pl_sz); - print_hex_dump(KERN_INFO, "GET_CFG: ", DUMP_PREFIX_OFFSET, - 16, 4, rsp_pl, pl_sz, false); - apm->result.opcode = hdr->opcode; - apm->result.status = rsp_pl[0]; - wake_up(&apm->wait); - 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; diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h index f8a66ff5f29f..376a36700c53 100644 --- a/sound/soc/qcom/qdsp6/q6apm.h +++ b/sound/soc/qcom/qdsp6/q6apm.h @@ -144,8 +144,6 @@ int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id); /* Helpers */ int q6apm_send_cmd_sync(struct q6apm *apm, const struct gpr_pkt *pkt, uint32_t rsp_opcode); -int q6apm_send_cmd_sync_timeout(struct q6apm *apm, const struct gpr_pkt *pkt, - uint32_t rsp_opcode, unsigned long timeout_s); /* Callback for graph specific */ struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, @@ -159,8 +157,4 @@ int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples); int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph, uint32_t codec_id); int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir); - -/* FP6 voice-call bring-up prototype (q6apm-voice-proto.c) */ -void q6apm_voice_proto_init(struct q6apm *apm); -void q6apm_voice_proto_exit(void); #endif /* __APM_GRAPH_ */