From f462601b0a76460d54dcc3215bdb1b6381049837 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: Aviad Nissel" Date: Tue, 16 Oct 2018 01:37:49 +0300 Subject: [PATCH] dm: mei: add reset handlers There are multiple types of resets that need to be handled by the mei device. The reset may be initiated from both sides host or fw. The host requests reset on probe and remove, power state transaction, and errors, while ME FW may request reset upon error. If the native device undergo reset the host application has to be notified. Tracked-On: #1536 Signed-off-by: Aviad Nissel Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Acked-by: Wang, Yu1 --- devicemodel/hw/pci/virtio/virtio_mei.c | 85 ++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/devicemodel/hw/pci/virtio/virtio_mei.c b/devicemodel/hw/pci/virtio/virtio_mei.c index 1399bcf81..0feaf94fa 100644 --- a/devicemodel/hw/pci/virtio/virtio_mei.c +++ b/devicemodel/hw/pci/virtio/virtio_mei.c @@ -222,6 +222,9 @@ static void vmei_dbg_print_hex(const char *title, #define VMEI_BUF_SZ (VMEI_BUF_DEPTH * VMEI_SLOT_SZ) #define VMEI_RING_SZ 64 +#define MEI_SYSFS_ROOT "/sys/class/mei" +#define MEI_DEV_STATE_LEN 12 + struct mei_virtio_cfg { uint32_t buf_depth; uint8_t hw_ready; @@ -661,3 +664,85 @@ static int mei_sysfs_read_property_uuid(char *fname, guid_t *uuid) return guid_parse(buf, sizeof(buf), uuid); } + +static void +vmei_virtual_fw_reset(struct virtio_mei *vmei) +{ + DPRINTF("Firmware reset\n"); + struct vmei_me_client *e; + + vmei_set_status(vmei, VMEI_STS_RESET); + vmei->config->hw_ready = 0; + close(vmei->hbm_fd); + + /* disconnect all */ + pthread_mutex_lock(&vmei->list_mutex); + LIST_FOREACH(e, &vmei->active_clients, list) { + vmei_me_client_destroy_host_clients(e); + } + pthread_mutex_unlock(&vmei->list_mutex); +} + +static void +vmei_reset(void *vth) +{ + struct virtio_mei *vmei = vth; + + DPRINTF("device reset requested!\n"); + vmei_virtual_fw_reset(vmei); + virtio_reset_dev(&vmei->base); +} + +static void vmei_del_reset_event(struct virtio_mei *vmei) +{ + if (vmei->reset_mevp) + mevent_delete_close(vmei->reset_mevp); + + 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; +}