123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include "hab.h"
- #include "hab_qvm.h"
- #include "hab_trace_os.h"
- static unsigned long long xvm_sche_tx_tv_buffer[2];
- static void pipe_read_trace(struct qvm_channel *dev,
- int size, int ret)
- {
- struct hab_pipe_endpoint *ep = dev->pipe_ep;
- struct hab_shared_buf *sh_buf = dev->rx_buf;
- struct dbg_items *its = dev->dbg_itms;
- struct dbg_item *it = &its->it[its->idx];
- it->rd_cnt = sh_buf->rd_count;
- it->wr_cnt = sh_buf->wr_count;
- it->va = (void *)&sh_buf->data[ep->rx_info.index];
- it->index = ep->rx_info.index;
- it->sz = size;
- it->ret = ret;
- its->idx++;
- if (its->idx >= DBG_ITEM_SIZE)
- its->idx = 0;
- }
- /* this is only used to read payload, never the head! */
- int physical_channel_read(struct physical_channel *pchan,
- void *payload,
- size_t read_size)
- {
- struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
- if (dev) {
- int ret = hab_pipe_read(dev->pipe_ep,
- dev->rx_buf, PIPE_SHMEM_SIZE,
- payload, read_size, 0);
- /* log */
- pipe_read_trace(dev, read_size, ret);
- return ret;
- } else
- return 0;
- }
- int physical_channel_send(struct physical_channel *pchan,
- struct hab_header *header,
- void *payload,
- unsigned int flags)
- {
- size_t sizebytes = HAB_HEADER_GET_SIZE(*header);
- struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
- size_t total_size = sizeof(*header) + sizebytes;
- uint32_t buf_size = PIPE_SHMEM_SIZE;
- int irqs_disabled = irqs_disabled();
- /* Only used in virtio arch */
- (void)flags;
- if (total_size > buf_size)
- return -EINVAL; /* too much data for ring */
- hab_spin_lock(&dev->io_lock, irqs_disabled);
- trace_hab_pchan_send_start(pchan);
- if ((buf_size -
- (dev->pipe_ep->tx_info.wr_count -
- dev->tx_buf->rd_count)) < total_size) {
- hab_spin_unlock(&dev->io_lock, irqs_disabled);
- return -EAGAIN; /* not enough free space */
- }
- header->sequence = pchan->sequence_tx + 1;
- header->signature = HAB_HEAD_SIGNATURE;
- if (hab_pipe_write(dev->pipe_ep, dev->tx_buf, buf_size,
- (unsigned char *)header,
- sizeof(*header)) != sizeof(*header)) {
- hab_spin_unlock(&dev->io_lock, irqs_disabled);
- pr_err("***incompleted pchan send id-type %x size %x session %d seq# %d\n",
- header->id_type, header->payload_size,
- header->session_id,
- header->sequence);
- return -EIO;
- }
- if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_PROFILE) {
- struct timespec64 ts = {0};
- struct habmm_xing_vm_stat *pstat =
- (struct habmm_xing_vm_stat *)payload;
- if (pstat) {
- ktime_get_ts64(&ts);
- pstat->tx_sec = ts.tv_sec;
- pstat->tx_usec = ts.tv_nsec/NSEC_PER_USEC;
- } else {
- hab_spin_unlock(&dev->io_lock, irqs_disabled);
- pr_err("***incompleted pchan send prof id-type %x size %x session %d seq# %d\n",
- header->id_type, header->payload_size,
- header->session_id,
- header->sequence);
- return -EINVAL;
- }
- } else if (HAB_HEADER_GET_TYPE(*header)
- == HAB_PAYLOAD_TYPE_SCHE_RESULT_REQ) {
- ((unsigned long long *)payload)[0] = xvm_sche_tx_tv_buffer[0];
- } else if (HAB_HEADER_GET_TYPE(*header)
- == HAB_PAYLOAD_TYPE_SCHE_RESULT_RSP) {
- ((unsigned long long *)payload)[2] = xvm_sche_tx_tv_buffer[1];
- }
- if (sizebytes) {
- if (hab_pipe_write(dev->pipe_ep, dev->tx_buf, buf_size,
- (unsigned char *)payload,
- sizebytes) != sizebytes) {
- hab_spin_unlock(&dev->io_lock, irqs_disabled);
- pr_err("***incompleted pchan send id-type %x size %x session %d seq# %d\n",
- header->id_type, header->payload_size,
- header->session_id,
- header->sequence);
- return -EIO;
- }
- }
- hab_pipe_write_commit(dev->pipe_ep, dev->tx_buf);
- /* locally +1 as late as possible but before unlock */
- ++pchan->sequence_tx;
- trace_hab_pchan_send_done(pchan);
- hab_spin_unlock(&dev->io_lock, irqs_disabled);
- if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_SCHE_MSG)
- xvm_sche_tx_tv_buffer[0] = msm_timer_get_sclk_ticks();
- else if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_SCHE_MSG_ACK)
- xvm_sche_tx_tv_buffer[1] = msm_timer_get_sclk_ticks();
- habhyp_notify(dev);
- return 0;
- }
- void physical_channel_rx_dispatch(unsigned long data)
- {
- struct hab_header header;
- struct physical_channel *pchan = (struct physical_channel *)data;
- struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
- int irqs_disabled = irqs_disabled();
- uint32_t buf_size = PIPE_SHMEM_SIZE;
- hab_spin_lock(&pchan->rxbuf_lock, irqs_disabled);
- while (1) {
- uint32_t rd, wr, idx;
- int ret;
- ret = hab_pipe_read(dev->pipe_ep,
- dev->rx_buf, buf_size,
- (unsigned char *)&header,
- sizeof(header), 1); /* clear head after read */
- /* debug */
- pipe_read_trace(dev, sizeof(header), ret);
- if (ret == 0xFFFFFFFF) { /* signature mismatched first time */
- hab_pipe_rxinfo(dev->pipe_ep, dev->rx_buf, &rd, &wr, &idx);
- pr_err("!!!!! HAB signature mismatch expect %X received %X, id_type %X size %X session %X sequence %X\n",
- HAB_HEAD_SIGNATURE, header.signature,
- header.id_type,
- header.payload_size,
- header.session_id,
- header.sequence);
- pr_err("!!!!! rxinfo rd %d wr %d index %X\n",
- rd, wr, idx);
- memcpy(dev->side_buf,
- (void *)&dev->rx_buf->data[0],
- buf_size);
- hab_spin_unlock(&pchan->rxbuf_lock, irqs_disabled);
- /* cannot run in elevated context */
- dump_hab_wq(pchan);
- hab_spin_lock(&pchan->rxbuf_lock, irqs_disabled);
- } else if (ret == 0xFFFFFFFE) { /* continuous signature mismatches */
- continue;
- } else if (ret != sizeof(header))
- break; /* no data available */
- if (pchan->sequence_rx + 1 != header.sequence)
- pr_err("%s: expected sequence_rx is %u, received is %u\n",
- pchan->name, pchan->sequence_rx, header.sequence);
- pchan->sequence_rx = header.sequence;
- /* log msg recv timestamp: enter pchan dispatcher */
- trace_hab_pchan_recv_start(pchan);
- hab_msg_recv(pchan, &header);
- }
- hab_spin_unlock(&pchan->rxbuf_lock, irqs_disabled);
- }
|