1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#pragma once
6
7#include <fbl/intrusive_double_list.h>
8#include <lib/sync/completion.h>
9#include <zircon/thread_annotations.h>
10
11#include <intel-hda/utils/intel-audio-dsp-ipc.h>
12
13#include "debug-logging.h"
14
15namespace audio {
16namespace intel_hda {
17
18class IntelAudioDsp;
19
20class IntelDspIpc {
21public:
22    IntelDspIpc(IntelAudioDsp& dsp);
23
24    const char*  log_prefix() const { return log_prefix_; }
25
26    class Txn : public fbl::DoublyLinkedListable<Txn*> {
27    public:
28        Txn(const void* tx, size_t txs, void* rx, size_t rxs)
29            : tx_data(tx), tx_size(txs), rx_data(rx), rx_size(rxs) { }
30        Txn(uint32_t pri, uint32_t ext, const void* tx, size_t txs, void* rx, size_t rxs)
31            : request(pri, ext), tx_data(tx), tx_size(txs), rx_data(rx), rx_size(rxs) { }
32
33        DISALLOW_NEW;
34
35        bool success() {
36            return done && reply.status() == MsgStatus::IPC_SUCCESS;
37        }
38
39        IpcMessage request;
40        IpcMessage reply;
41
42        bool done = false;
43
44        const void* tx_data = nullptr;
45        size_t      tx_size = 0;
46        void*       rx_data = nullptr;
47        size_t      rx_size = 0;
48        size_t      rx_actual = 0;
49
50        sync_completion_t completion;
51    };
52
53    void SetLogPrefix(const char* new_prefix);
54
55    zx_status_t WaitForFirmwareReady(zx_duration_t timeout) {
56        return sync_completion_wait(&fw_ready_completion_, timeout);
57    }
58    void Shutdown();
59
60    // Library & Module Management IPC
61    zx_status_t InitInstance(uint16_t module_id, uint8_t instance_id, ProcDomain proc_domain,
62                             uint8_t core_id, uint8_t ppl_instance_id, uint16_t param_block_size,
63                             const void* param_data);
64    zx_status_t LargeConfigGet(Txn* txn, uint16_t module_id, uint8_t instance_id,
65                               uint8_t large_param_id, uint32_t data_off_size);
66    zx_status_t Bind(uint16_t src_module_id, uint8_t src_instance_id, uint8_t src_queue,
67                     uint16_t dst_module_id, uint8_t dst_instance_id, uint8_t dst_queue);
68
69    // Pipeline Management IPC
70    zx_status_t CreatePipeline(uint8_t instance_id, uint8_t ppl_priority,
71                               uint16_t ppl_mem_size, bool lp);
72    zx_status_t SetPipelineState(uint8_t ppl_id, PipelineState state, bool sync_stop_start);
73
74    // Process responses from DSP
75    void ProcessIpc(const IpcMessage& message);
76    void ProcessIpcNotification(const IpcMessage& reply);
77    void ProcessIpcReply(const IpcMessage& reply);
78    void ProcessLargeConfigGetReply(Txn* txn);
79
80private:
81    // Send an IPC message and wait for response
82    zx_status_t SendIpcWait(Txn* txn);
83
84    void SendIpc(const Txn& txn);
85
86    zx_status_t dsp_to_zx_status(MsgStatus status) {
87        return (status == MsgStatus::IPC_SUCCESS) ? ZX_OK : ZX_ERR_INTERNAL;
88    }
89
90    // Log prefix storage
91    char log_prefix_[LOG_PREFIX_STORAGE] = { 0 };
92
93    // Pending IPC
94    fbl::Mutex ipc_lock_;
95    fbl::DoublyLinkedList<Txn*> ipc_queue_ TA_GUARDED(ipc_lock_);
96
97    // A reference to the owning DSP
98    IntelAudioDsp& dsp_;
99
100    // Used to wait for firmware ready
101    sync_completion_t fw_ready_completion_;
102};
103
104}  // namespace intel_hda
105}  // namespace audio
106