mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-04 11:07:51 +00:00
dm: mei: implement rx flow.
Rx is triggered from epoll event (mevent), a host client is retrieved from associated event data. P proper mei message header is attached to the packet and sent to the virtio FE device. Tracked-On: #1536 Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Acked-by: Wang, Yu1 <yu1.wang@intel.com>
This commit is contained in:
parent
50ecd93b24
commit
6a1f824229
@ -980,6 +980,8 @@ static int vmei_add_reset_event(struct virtio_mei *vmei)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vmei_rx_callback(int fd, enum ev_type type, void *param);
|
||||||
|
|
||||||
static inline uint8_t
|
static inline uint8_t
|
||||||
errno_to_hbm_conn_status(int err)
|
errno_to_hbm_conn_status(int err)
|
||||||
{
|
{
|
||||||
@ -1656,6 +1658,233 @@ vmei_host_client_native_read(struct vmei_host_client *hclient)
|
|||||||
return hclient->recv_offset;
|
return hclient->recv_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vmei_rx_callback(int fd, enum ev_type type, void *param)
|
||||||
|
{
|
||||||
|
struct vmei_host_client *hclient = param;
|
||||||
|
struct virtio_mei *vmei = vmei_host_client_to_vmei(hclient);
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
if (!vmei)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!vmei_host_client_get(hclient)) {
|
||||||
|
DPRINTF("RX: client has been released, ignore data.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&vmei->rx_mutex);
|
||||||
|
if (vmei->status != VMEI_STS_READY) {
|
||||||
|
HCL_DBG(hclient, "vmei is not ready %d\n", vmei->status);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hclient->recv_offset) {
|
||||||
|
/* still has data in recv_buf, wait guest reading */
|
||||||
|
HCL_DBG(hclient, "data in recv_buf, wait for UOS reading.\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read data from mei driver */
|
||||||
|
ret = vmei_host_client_native_read(hclient);
|
||||||
|
if (ret <= 0) {
|
||||||
|
HCL_DBG(hclient, "RX: no data %zd\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
vmei->rx_need_sched = true;
|
||||||
|
|
||||||
|
HCL_DBG(hclient, "RX: read %zd bytes from the FW\n", ret);
|
||||||
|
|
||||||
|
/* wake up rx thread. */
|
||||||
|
pthread_cond_signal(&vmei->rx_cond);
|
||||||
|
|
||||||
|
out:
|
||||||
|
pthread_mutex_unlock(&vmei->rx_mutex);
|
||||||
|
vmei_host_client_put(hclient);
|
||||||
|
if (vmei->status == VMEI_STS_PENDING_RESET) {
|
||||||
|
vmei_virtual_fw_reset(vmei);
|
||||||
|
/* Let's wait 100ms for HBM enumeration done */
|
||||||
|
usleep(100000);
|
||||||
|
virtio_config_changed(&vmei->base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process the data received from native mei cdev and hbm emulation
|
||||||
|
* handler, assemable related mei header then copy to rx virtqueue.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
vmei_proc_vclient_rx(struct vmei_host_client *hclient,
|
||||||
|
struct virtio_vq_info *vq)
|
||||||
|
{
|
||||||
|
struct iovec iov[VMEI_RX_SEGS + 1];
|
||||||
|
struct mei_msg_hdr *hdr;
|
||||||
|
uint16_t idx = 0;
|
||||||
|
int n, len;
|
||||||
|
int buf_len;
|
||||||
|
uint8_t *buf;
|
||||||
|
bool complete = true;
|
||||||
|
|
||||||
|
n = vq_getchain(vq, &idx, iov, VMEI_RX_SEGS, NULL);
|
||||||
|
assert(n == VMEI_RX_SEGS);
|
||||||
|
if (n != VMEI_RX_SEGS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
len = hclient->recv_offset - hclient->recv_handled;
|
||||||
|
HCL_DBG(hclient, "RX: DM->UOS: off=%d len=%d\n",
|
||||||
|
hclient->recv_handled, len);
|
||||||
|
|
||||||
|
buf_len = VMEI_BUF_SZ - sizeof(*hdr);
|
||||||
|
hdr = (struct mei_msg_hdr *)iov[0].iov_base;
|
||||||
|
buf = (uint8_t *)iov[0].iov_base + sizeof(*hdr);
|
||||||
|
|
||||||
|
if (len > buf_len) {
|
||||||
|
len = buf_len;
|
||||||
|
complete = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mei_set_msg_hdr(hclient, hdr, len, complete);
|
||||||
|
memcpy(buf, hclient->recv_buf + hclient->recv_handled, len);
|
||||||
|
hclient->recv_handled += len;
|
||||||
|
|
||||||
|
HCL_DBG(hclient, "RX: complete = %d DM->UOS:off=%d len=%d\n",
|
||||||
|
complete, hclient->recv_handled, len);
|
||||||
|
len += sizeof(struct mei_msg_hdr);
|
||||||
|
|
||||||
|
if (complete) {
|
||||||
|
hclient->recv_offset = 0;
|
||||||
|
hclient->recv_handled = 0;
|
||||||
|
if (hclient->host_addr) {
|
||||||
|
hclient->recv_creds--;
|
||||||
|
mevent_disable(hclient->rx_mevp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vq_relchain(vq, idx, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vmei_proc_rx() process rx UOS
|
||||||
|
* @vmei: virtio mei device
|
||||||
|
* @vq: virtio queue
|
||||||
|
*
|
||||||
|
* Function looks for client with pending buffer and sends
|
||||||
|
* it to the UOS.
|
||||||
|
*
|
||||||
|
* Locking: Must run under rx mutex
|
||||||
|
* Return:
|
||||||
|
* true - need reschedule
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
vmei_proc_rx(struct virtio_mei *vmei, struct virtio_vq_info *vq)
|
||||||
|
{
|
||||||
|
struct vmei_me_client *me;
|
||||||
|
struct vmei_host_client *e, *hclient = NULL;
|
||||||
|
|
||||||
|
/* Find a client with data */
|
||||||
|
pthread_mutex_lock(&vmei->list_mutex);
|
||||||
|
LIST_FOREACH(me, &vmei->active_clients, list) {
|
||||||
|
pthread_mutex_lock(&me->list_mutex);
|
||||||
|
LIST_FOREACH(e, &me->connections, list) {
|
||||||
|
if (e->recv_offset - e->recv_handled > 0) {
|
||||||
|
if (e->recv_creds) {
|
||||||
|
hclient = vmei_host_client_get(e);
|
||||||
|
pthread_mutex_unlock(&me->list_mutex);
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&me->list_mutex);
|
||||||
|
}
|
||||||
|
found:
|
||||||
|
pthread_mutex_unlock(&vmei->list_mutex);
|
||||||
|
|
||||||
|
/* no client has data to be processed */
|
||||||
|
if (!hclient) {
|
||||||
|
DPRINTF("RX: No client with data\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vmei_proc_vclient_rx(hclient, vq);
|
||||||
|
pthread_mutex_lock(&vmei->tx_mutex);
|
||||||
|
if (vmei_host_ready_send_buffers(hclient))
|
||||||
|
pthread_cond_signal(&vmei->tx_cond);
|
||||||
|
pthread_mutex_unlock(&vmei->tx_mutex);
|
||||||
|
vmei_host_client_put(hclient);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Thread which will handle processing of RX desc
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void *vmei_rx_thread(void *param)
|
||||||
|
{
|
||||||
|
struct virtio_mei *vmei = param;
|
||||||
|
struct virtio_vq_info *vq;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
vq = &vmei->vqs[VMEI_RXQ];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Let us wait till the rx queue pointers get initialised &
|
||||||
|
* first tx signaled
|
||||||
|
*/
|
||||||
|
pthread_mutex_lock(&vmei->rx_mutex);
|
||||||
|
err = pthread_cond_wait(&vmei->rx_cond, &vmei->rx_mutex);
|
||||||
|
assert(err == 0);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
while (vmei->status != VMEI_STST_DEINIT) {
|
||||||
|
/* note - rx mutex is locked here */
|
||||||
|
while (vq_ring_ready(vq)) {
|
||||||
|
vq->used->flags &= ~ACRN_VRING_USED_F_NO_NOTIFY;
|
||||||
|
mb();
|
||||||
|
if (vq_has_descs(vq) &&
|
||||||
|
vmei->rx_need_sched &&
|
||||||
|
vmei->status != VMEI_STS_RESET)
|
||||||
|
break;
|
||||||
|
|
||||||
|
err = pthread_cond_wait(&vmei->rx_cond,
|
||||||
|
&vmei->rx_mutex);
|
||||||
|
assert(err == 0);
|
||||||
|
if (err || vmei->status == VMEI_STST_DEINIT)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
vq->used->flags |= ACRN_VRING_USED_F_NO_NOTIFY;
|
||||||
|
|
||||||
|
do {
|
||||||
|
vmei->rx_need_sched = vmei_proc_rx(vmei, vq);
|
||||||
|
} while (vq_has_descs(vq) && vmei->rx_need_sched);
|
||||||
|
|
||||||
|
if (!vq_has_descs(vq))
|
||||||
|
vq_endchains(vq, 1);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
pthread_mutex_unlock(&vmei->rx_mutex);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vmei_notify_rx(void *data, struct virtio_vq_info *vq)
|
||||||
|
{
|
||||||
|
struct virtio_mei *vmei = data;
|
||||||
|
/*
|
||||||
|
* Any ring entries to process?
|
||||||
|
*/
|
||||||
|
if (!vq_has_descs(vq))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Signal the rx thread for processing */
|
||||||
|
pthread_mutex_lock(&vmei->rx_mutex);
|
||||||
|
DPRINTF("RX: New IN buffer available!\n");
|
||||||
|
vq->used->flags |= ACRN_VRING_USED_F_NO_NOTIFY;
|
||||||
|
pthread_cond_signal(&vmei->rx_cond);
|
||||||
|
pthread_mutex_unlock(&vmei->rx_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vmei_cfgread(void *vsc, int offset, int size, uint32_t *retval)
|
vmei_cfgread(void *vsc, int offset, int size, uint32_t *retval)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user