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 <shuo.a.liu@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Acked-by: Wang, Yu1 <yu1.wang@intel.com>
This commit is contained in:
Tomas Winkler 2018-10-19 15:32:33 +03:00 committed by wenlingz
parent 6a1f824229
commit f6e6e8584e

View File

@ -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,
};