From f6e6e8584e4ff844ee8ba197f8a751d805b33c51 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 19 Oct 2018 15:32:33 +0300 Subject: [PATCH] dm: mei: implement vmei_start/stop() In vmei_start() the HBM host client is created, it handles HBM protocol. The HBM client is a management object and is not exposed by the mei native driver. The communication between TX and RX threads is handed via internal pipe(2). Second, we connect all fixed address clients as the mei protocol doesn't provide connection mechanism for them, they appear always connected. Last, the hw_ready is set. Define virtio_mei_ops, ass all the handlers are now available. Tracked-On: #1536 Signed-off-by: Liu Shuo Signed-off-by: Tomas Winkler Acked-by: Wang, Yu1 --- devicemodel/hw/pci/virtio/virtio_mei.c | 238 ++++++++++++++++++++----- 1 file changed, 192 insertions(+), 46 deletions(-) diff --git a/devicemodel/hw/pci/virtio/virtio_mei.c b/devicemodel/hw/pci/virtio/virtio_mei.c index e314aa7c1..85884488d 100644 --- a/devicemodel/hw/pci/virtio/virtio_mei.c +++ b/devicemodel/hw/pci/virtio/virtio_mei.c @@ -934,52 +934,6 @@ static void vmei_del_reset_event(struct virtio_mei *vmei) vmei->reset_mevp = NULL; } -static void -vmei_reset_callback(int fd, enum ev_type type, void *param) -{ - static bool first_time = true; - struct virtio_mei *vmei = param; - char buf[MEI_DEV_STATE_LEN] = {0}; - int sz; - - lseek(fd, 0, SEEK_SET); - sz = read(fd, buf, 12); - if (first_time) { - first_time = false; - return; - } - - if (sz != 7 || memcmp(buf, "ENABLED", 7)) - return; - - DPRINTF("Reset state callback\n"); - - vmei_virtual_fw_reset(vmei); - vmei_free_me_clients(vmei); - vmei_start(vmei, true); -} - -static int vmei_add_reset_event(struct virtio_mei *vmei) -{ - char devpath[256]; - int dev_state_fd; - - snprintf(devpath, sizeof(devpath) - 1, "%s/%s/%s", - MEI_SYSFS_ROOT, vmei->name, "dev_state"); - - dev_state_fd = open(devpath, O_RDONLY); - if (dev_state_fd < 0) - return -errno; - - vmei->reset_mevp = mevent_add(dev_state_fd, EVF_READ_ET, - vmei_reset_callback, vmei); - if (!vmei->reset_mevp) { - close(dev_state_fd); - return -ENOMEM; - } - return 0; -} - static void vmei_rx_callback(int fd, enum ev_type type, void *param); static inline uint8_t @@ -1352,6 +1306,51 @@ vmei_hbm_handler(struct virtio_mei *vmei, const void *data) } } +int vmei_fixed_client_connect(struct vmei_me_client *mclient) +{ + struct vmei_host_client *hclient; + uint8_t status; + + /* SKIP over HBM */ + if (!mclient->client_id) + return 0; + + if (!mclient->props.fixed_address) + return 0; + + hclient = vmei_host_client_create(mclient, 0); + if (!hclient) { + DPRINTF("vmei_host_client_create failed %d!\n", + mclient->client_id); + return -1; + } + + status = vmei_host_client_native_connect(hclient); + if (status) { + vmei_host_client_put(hclient); + DPRINTF("vmei_host_client_connect failed %d!\n", + mclient->client_id); + return -1; + } + + return 0; +} + +static int vmei_fixed_clients_connect(struct virtio_mei *vmei) +{ + struct vmei_me_client *e; + + DPRINTF("connecting fixed clients\n"); + + pthread_mutex_lock(&vmei->list_mutex); + LIST_FOREACH(e, &vmei->active_clients, list) { + vmei_fixed_client_connect(e); + } + pthread_mutex_unlock(&vmei->list_mutex); + + return 0; +} + static inline bool hdr_is_hbm(const struct mei_msg_hdr *hdr) { return hdr->host_addr == 0 && hdr->me_addr == 0; @@ -1885,6 +1884,141 @@ vmei_notify_rx(void *data, struct virtio_vq_info *vq) pthread_mutex_unlock(&vmei->rx_mutex); } +static int +vmei_start(struct virtio_mei *vmei, bool do_rescan) +{ + static struct vmei_host_client *hclient; + const struct mei_client_properties props = { + .protocol_name = NULL_UUID_LE, + .protocol_version = 0, + .max_connections = 1, + .fixed_address = 1, + .single_recv_buf = 0, + .max_msg_length = VMEI_BUF_SZ, + }; + int pipefd[2]; + + /* create HBM client (address 0) */ + if (do_rescan && !vmei->hbm_client) + vmei->hbm_client = vmei_me_client_create(vmei, 0, &props); + + if (!vmei->hbm_client) { + WPRINTF("hbm client creation failed\n"); + return -1; + } + + /* + * create a dummy host client for the HBM client + * so that the HBM client will have rx/tx buffers + */ + hclient = vmei_host_client_create(vmei->hbm_client, 0); + if (!hclient) + goto hclient_failed; + + if (pipe2(pipefd, O_DIRECT) < 0) + goto scan_failed; + + hclient->client_fd = pipefd[0]; + hclient->rx_mevp = mevent_add(hclient->client_fd, EVF_READ, + vmei_rx_callback, hclient); + vmei->hbm_fd = pipefd[1]; + + if (do_rescan) { + vmei_add_me_client(vmei->hbm_client); + if (vmei_me_client_scan_list(vmei) < 0) + goto scan_failed; + } + + vmei_fixed_clients_connect(vmei); + + vmei->config->hw_ready = 1; + vmei_set_status(vmei, VMEI_STS_READY); + + return 0; + +scan_failed: + vmei_host_client_put(hclient); + +hclient_failed: + vmei_me_client_put(vmei->hbm_client); + vmei->hbm_client = NULL; + + return -1; +} + +static int +vmei_stop(struct virtio_mei *vmei) +{ + vmei_set_status(vmei, VMEI_STST_DEINIT); + pthread_mutex_lock(&vmei->tx_mutex); + pthread_cond_signal(&vmei->tx_cond); + pthread_mutex_unlock(&vmei->tx_mutex); + + pthread_mutex_lock(&vmei->rx_mutex); + pthread_cond_signal(&vmei->rx_cond); + pthread_mutex_unlock(&vmei->rx_mutex); + + vmei_virtual_fw_reset(vmei); + + pthread_join(vmei->rx_thread, NULL); + pthread_join(vmei->tx_thread, NULL); + + vmei_free_me_clients(vmei); + + pthread_mutex_destroy(&vmei->rx_mutex); + pthread_mutex_destroy(&vmei->tx_mutex); + pthread_mutex_destroy(&vmei->list_mutex); + + return 0; +} + +static void +vmei_reset_callback(int fd, enum ev_type type, void *param) +{ + static bool first_time = true; + struct virtio_mei *vmei = param; + char buf[MEI_DEV_STATE_LEN] = {0}; + int sz; + + lseek(fd, 0, SEEK_SET); + sz = read(fd, buf, 12); + if (first_time) { + first_time = false; + return; + } + + if (sz != 7 || memcmp(buf, "ENABLED", 7)) + return; + + DPRINTF("Reset state callback\n"); + + vmei_virtual_fw_reset(vmei); + vmei_free_me_clients(vmei); + vmei_start(vmei, true); +} + +static int vmei_add_reset_event(struct virtio_mei *vmei) +{ + char devpath[256]; + int dev_state_fd; + + snprintf(devpath, sizeof(devpath) - 1, "%s/%s/%s", + MEI_SYSFS_ROOT, vmei->name, "dev_state"); + + dev_state_fd = open(devpath, O_RDONLY); + if (dev_state_fd < 0) + return -errno; + + vmei->reset_mevp = mevent_add(dev_state_fd, EVF_READ_ET, + vmei_reset_callback, vmei); + if (!vmei->reset_mevp) { + close(dev_state_fd); + return -ENOMEM; + } + return 0; +} + + static int vmei_cfgread(void *vsc, int offset, int size, uint32_t *retval) { @@ -1927,9 +2061,21 @@ vmei_cfgwrite(void *vsc, int offset, int size, uint32_t val) DPRINTF("cfgwrite: host_reset_release [%d]\n", val); /* guest initate reset need restart */ + vmei_start(vmei, false); virtio_config_changed(&vmei->base); } return 0; } +struct virtio_ops virtio_mei_ops = { + .name = "virtio_heci", + .nvq = VMEI_VQ_NUM, + .cfgsize = sizeof(struct mei_virtio_cfg), + .reset = vmei_reset, + .qnotify = NULL, + .cfgread = vmei_cfgread, + .cfgwrite = vmei_cfgwrite, + .apply_features = NULL, + .set_status = NULL, +};