Subject: DM: virtio-heci: process all available client each time

Right now, the virtio_heci_proc_rx only process the first
available client at a time, then clear rx_need_sched flag to make
rx_thread sleep. It cause the remain data available clients lost the
current change to be processed. This patch resolves this issue, to
process all data available clients in a round prior to push rx_thread
enter sleep.

Signed-off-by: Long Liu <long.liu@intel.com>
Reviewed-by: Shuo Liu <shuo.a.liu@intel.com>
Reviewed-by: Yu Wang <yu1.wang@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Long Liu 2018-04-22 17:15:09 +08:00 committed by Jack Ren
parent 5ed3dbf93c
commit 2550d719d3

View File

@ -255,7 +255,12 @@ virtio_heci_add_client(struct virtio_heci *vheci,
struct virtio_heci_client *client) struct virtio_heci_client *client)
{ {
pthread_mutex_lock(&vheci->list_mutex); pthread_mutex_lock(&vheci->list_mutex);
LIST_INSERT_HEAD(&vheci->active_clients, client, list); if (client->type == TYPE_HBM)
/* make sure hbm client at the head of the list */
LIST_INSERT_HEAD(&vheci->active_clients, client, list);
else
LIST_INSERT_AFTER(LIST_FIRST(&vheci->active_clients),
client, list);
pthread_mutex_unlock(&vheci->list_mutex); pthread_mutex_unlock(&vheci->list_mutex);
} }
@ -820,7 +825,6 @@ virtio_heci_hbm_handler(struct virtio_heci *vheci, void *data)
DPRINTF(("vheci: HBM cmd[%d] is done!\n\r", hbm_cmd->cmd)); DPRINTF(("vheci: HBM cmd[%d] is done!\n\r", hbm_cmd->cmd));
} }
static void static void
virtio_heci_proc_tx(struct virtio_heci *vheci, struct virtio_vq_info *vq) virtio_heci_proc_tx(struct virtio_heci *vheci, struct virtio_vq_info *vq)
{ {
@ -1013,118 +1017,104 @@ out:
pthread_exit(NULL); pthread_exit(NULL);
} }
/* caller need hold rx_mutex /*
* return: * Process the data received from native mei cdev and hbm emulation
* true - data processed * handler, assemable related heci header then copy to rx virtqueue.
* fasle - need resched
*/ */
static bool virtio_heci_proc_rx(struct virtio_heci *vheci, static void
virtio_heci_proc_vclient_rx(struct virtio_heci_client *client,
struct virtio_vq_info *vq) struct virtio_vq_info *vq)
{ {
struct iovec iov[VIRTIO_HECI_RXSEGS + 1]; struct iovec iov[VIRTIO_HECI_RXSEGS + 1];
struct heci_msg_hdr *heci_hdr; struct heci_msg_hdr *heci_hdr;
int n; uint16_t idx = 0;
uint16_t idx; int n, len = 0;
struct virtio_heci_client *pclient, *client = NULL;
uint8_t *buf; uint8_t *buf;
int len;
bool finished = false;
/* search all clients who has message received to fill the recv buf */
pthread_mutex_lock(&vheci->list_mutex);
LIST_FOREACH(pclient, &vheci->active_clients, list) {
if (pclient->recv_offset - pclient->recv_handled > 0) {
client = virtio_heci_client_get(pclient);
break;
}
}
pthread_mutex_unlock(&vheci->list_mutex);
/* no client has data received, ignore RX request! */
if (!client) {
DPRINTF(("vheci: RX: none client has data!\n\r"));
vheci->rx_need_sched = false;
return false;
}
/*
* Obtain chain of descriptors.
* The first dword is heci_hdr, the rest are for payload.
*/
n = vq_getchain(vq, &idx, iov, VIRTIO_HECI_RXSEGS, NULL); n = vq_getchain(vq, &idx, iov, VIRTIO_HECI_RXSEGS, NULL);
assert(n == VIRTIO_HECI_RXSEGS); assert(n == VIRTIO_HECI_RXSEGS);
heci_hdr = (struct heci_msg_hdr *)iov[0].iov_base;
/* buffer length need remove HECI header */
len = (vheci->config->buf_depth - 1) * sizeof(struct heci_msg_hdr);
buf = (uint8_t *)iov[0].iov_base + sizeof(struct heci_msg_hdr);
if (client->type == TYPE_HBM) { if (client->type == TYPE_HBM) {
/* HBM client has data to FE */ /* HBM client has data to FE */
len = client->recv_offset - client->recv_handled; len = client->recv_offset - client->recv_handled;
memcpy(iov[0].iov_base, memcpy(iov[0].iov_base,
client->recv_buf + client->recv_handled, len); client->recv_buf + client->recv_handled, len);
DPRINTF(("vheci: RX: data DM:ME[%d]fd[%d]off[%d]" client->recv_offset = client->recv_handled = 0;
" -> UOS:client_addr[%d] len[%d]\n\r", DPRINTF(("vheci: RX: DM:ME[%d]fd[%d]off[%d]"
"-> UOS:client_addr[%d] len[%d]\n\r",
client->client_id, client->client_fd, client->client_id, client->client_fd,
client->recv_handled, client->recv_handled,
client->client_addr, len)); client->client_addr, len));
print_hex(iov[0].iov_base, len);
client->recv_offset = client->recv_handled = 0;
finished = true;
goto out; goto out;
} }
if (client->recv_creds == 0) { /* NORMAL client buffer length need remove HECI header */
/* len = (VIRTIO_HECI_FIFOSZ - 1) * sizeof(struct heci_msg_hdr);
* FE client is not ready to recv message buf = (uint8_t *)iov[0].iov_base + sizeof(struct heci_msg_hdr);
* return 1 here to unmask rx_need_sched, to avoid spin in heci_hdr = (struct heci_msg_hdr *)iov[0].iov_base;
* this checking loop, tag rx_need_sched when we receive creds
*/ if (client->recv_offset - client->recv_handled > len) {
DPRINTF(("vheci: RX: ME[%d]fd[%d] recv_creds is not ready\n\r",
client->client_id, client->client_fd));
virtio_heci_client_put(vheci, client);
vq_retchain(vq);
return true;
} else if (client->recv_offset - client->recv_handled > len) {
/* this client has data to guest, and
* need split the data into multi buffers
* FE only support one buffer now. Need expand later.
*/
populate_heci_hdr(client, heci_hdr, len, 0); populate_heci_hdr(client, heci_hdr, len, 0);
memcpy(buf, client->recv_buf + client->recv_handled, len); memcpy(buf, client->recv_buf + client->recv_handled, len);
client->recv_handled += len;
len += sizeof(struct heci_msg_hdr);
DPRINTF(("vheci: RX: data(partly) DM:ME[%d]fd[%d]off[%d]" DPRINTF(("vheci: RX: data(partly) DM:ME[%d]fd[%d]off[%d]"
" -> UOS:client_addr[%d] len[%d]\n\r", " -> UOS:client_addr[%d] len[%d]\n\r",
client->client_id, client->client_fd, client->client_id, client->client_fd,
client->recv_handled, client->recv_handled,
client->client_addr, len)); client->client_addr, len));
client->recv_handled += len;
finished = false;
len += sizeof(struct heci_msg_hdr);
} else { } else {
/* this client has data to guest, can be in one recv buf */ /* this client has data to guest, can be in one recv buf */
len = client->recv_offset - client->recv_handled; len = client->recv_offset - client->recv_handled;
populate_heci_hdr(client, heci_hdr, len, 1); populate_heci_hdr(client, heci_hdr, len, 1);
memcpy(buf, client->recv_buf + client->recv_handled, len); memcpy(buf, client->recv_buf + client->recv_handled, len);
client->recv_offset = client->recv_handled = 0; client->recv_offset = client->recv_handled = 0;
finished = true;
client->recv_creds--; client->recv_creds--;
len += sizeof(struct heci_msg_hdr); len += sizeof(struct heci_msg_hdr);
DPRINTF(("vheci: RX: data(end) DM:ME[%d]fd[%d]off[%d]" DPRINTF(("vheci: RX: data(end) DM:ME[%d]fd[%d]off[%d]"
"-> UOS:client_addr[%d] len[%d]\n\r", " -> UOS:client_addr[%d] len[%d]\n\r",
client->client_id, client->client_fd, client->client_id, client->client_fd,
client->recv_handled, client->recv_handled,
client->client_addr, len)); client->client_addr, len));
print_hex((uint8_t *)iov[0].iov_base, len); }
out:
vq_relchain(vq, idx, len);
}
/* caller need hold rx_mutex
* return:
* true - data processed
* fasle - need resched
*/
static bool
virtio_heci_proc_rx(struct virtio_heci *vheci,
struct virtio_vq_info *vq)
{
struct virtio_heci_client *pclient, *client = NULL;
/*
* Traverse the list find all available clients, ignore these normal
* type clients, which have data but it's receieve creds is Zero.
*/
pthread_mutex_lock(&vheci->list_mutex);
LIST_FOREACH(pclient, &vheci->active_clients, list) {
if ((pclient->recv_offset - pclient->recv_handled > 0) &&
(pclient->recv_creds > 0 || pclient->type == TYPE_HBM)) {
client = virtio_heci_client_get(pclient);
break;
}
}
pthread_mutex_unlock(&vheci->list_mutex);
/* no client has data need to be processed */
if (!client) {
DPRINTF(("vheci: RX: no available client!\n\r"));
return true;
} }
out: virtio_heci_proc_vclient_rx(client, vq);
virtio_heci_client_put(vheci, client); virtio_heci_client_put(vheci, client);
/* chain is processed, release it and set tlen */ return false;
vq_relchain(vq, idx, len);
DPRINTF(("vheci: RX: release IN-vq idx[%d]\r\n", idx));
return finished;
} }
/* /*