191 lines
5.5 KiB
C
191 lines
5.5 KiB
C
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
#include "hab.h"
|
|
#include "hab_qvm.h"
|
|
|
|
static unsigned long long xvm_sche_tx_tv_buffer[2];
|
|
|
|
static void pipe_read_trace(struct hab_pipe *pipe, struct hab_pipe_endpoint *ep,
|
|
int size, int ret)
|
|
{
|
|
struct hab_shared_buf *sh_buf = ep->rx_info.sh_buf;
|
|
struct dbg_items *its = (struct dbg_items *)pipe->buf_a;
|
|
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, payload, read_size, 0);
|
|
|
|
/* log */
|
|
pipe_read_trace(dev->pipe, dev->pipe_ep, read_size, ret);
|
|
|
|
return ret;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
#define HAB_HEAD_SIGNATURE 0xBEE1BEE1
|
|
|
|
int physical_channel_send(struct physical_channel *pchan,
|
|
struct hab_header *header,
|
|
void *payload)
|
|
{
|
|
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;
|
|
int irqs_disabled = irqs_disabled();
|
|
|
|
if (total_size > dev->pipe_ep->tx_info.sh_buf->size)
|
|
return -EINVAL; /* too much data for ring */
|
|
|
|
hab_spin_lock(&dev->io_lock, irqs_disabled);
|
|
|
|
if ((dev->pipe_ep->tx_info.sh_buf->size -
|
|
(dev->pipe_ep->tx_info.wr_count -
|
|
dev->pipe_ep->tx_info.sh_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,
|
|
(unsigned char *)header,
|
|
sizeof(*header)) != sizeof(*header)) {
|
|
hab_spin_unlock(&dev->io_lock, irqs_disabled);
|
|
pr_err("***incompleted pchan send id-type-size %x session %d seq# %d\n",
|
|
header->id_type_size, header->session_id,
|
|
header->sequence);
|
|
return -EIO;
|
|
}
|
|
|
|
if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_PROFILE) {
|
|
struct timeval tv;
|
|
struct habmm_xing_vm_stat *pstat =
|
|
(struct habmm_xing_vm_stat *)payload;
|
|
|
|
if (pstat) {
|
|
do_gettimeofday(&tv);
|
|
pstat->tx_sec = tv.tv_sec;
|
|
pstat->tx_usec = tv.tv_usec;
|
|
} else {
|
|
hab_spin_unlock(&dev->io_lock, irqs_disabled);
|
|
pr_err("***incompleted pchan send prof id-type-size %x session %d seq# %d\n",
|
|
header->id_type_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,
|
|
(unsigned char *)payload,
|
|
sizebytes) != sizebytes) {
|
|
hab_spin_unlock(&dev->io_lock, irqs_disabled);
|
|
pr_err("***incompleted pchan send id-type-size %x session %d seq# %d\n",
|
|
header->id_type_size, header->session_id,
|
|
header->sequence);
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
hab_pipe_write_commit(dev->pipe_ep);
|
|
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);
|
|
++pchan->sequence_tx;
|
|
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();
|
|
int i;
|
|
|
|
hab_spin_lock(&pchan->rxbuf_lock, irqs_disabled);
|
|
i = 0;
|
|
while (1) {
|
|
uint32_t rd, wr, idx;
|
|
int ret;
|
|
|
|
ret = hab_pipe_read(dev->pipe_ep,
|
|
(unsigned char *)&header,
|
|
sizeof(header), 1); /* clear head after read */
|
|
|
|
/* debug */
|
|
pipe_read_trace(dev->pipe, dev->pipe_ep, sizeof(header), ret);
|
|
|
|
if (ret != sizeof(header))
|
|
break; /* no data available */
|
|
|
|
hab_pipe_rxinfo(dev->pipe_ep, &rd, &wr, &idx);
|
|
if (header.signature != HAB_HEAD_SIGNATURE) {
|
|
pr_err("!!!!! HAB signature mismatch expect %X received %X, id_type_size %X session %X sequence %X i %d\n",
|
|
HAB_HEAD_SIGNATURE, header.signature,
|
|
header.id_type_size,
|
|
header.session_id,
|
|
header.sequence, i);
|
|
|
|
pr_err("!!!!! rxinfo rd %d wr %d index %X\n",
|
|
rd, wr, idx);
|
|
|
|
memcpy(dev->side_buf,
|
|
(void *)&dev->pipe_ep->rx_info.sh_buf->data[0],
|
|
dev->pipe_ep->rx_info.sh_buf->size);
|
|
|
|
hab_spin_unlock(&pchan->rxbuf_lock, irqs_disabled);
|
|
/* cannot run in elevated context */
|
|
dump_hab_wq(dev);
|
|
hab_spin_lock(&pchan->rxbuf_lock, irqs_disabled);
|
|
}
|
|
|
|
pchan->sequence_rx = header.sequence;
|
|
|
|
hab_msg_recv(pchan, &header);
|
|
i++;
|
|
}
|
|
hab_spin_unlock(&pchan->rxbuf_lock, irqs_disabled);
|
|
}
|