mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-28 10:04:14 +00:00
dm: mei: add client management infrastructure
1. virtio_mei structure represents an instance of mei device. 2. vmei_me_client represents an ME application in the MEI FW. 3. vmei_host_client represent a host application talking to the ME application, ME application can support multiple connections. 4. Add debug helpers 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
445f419304
commit
a632ac3dae
@ -153,6 +153,57 @@ refcnt_put(const struct refcnt *ref)
|
||||
ref->destroy(ref);
|
||||
}
|
||||
|
||||
static int vmei_debug;
|
||||
static FILE *vmei_dbg_file;
|
||||
|
||||
#define DPRINTF(format, arg...) do { \
|
||||
if (vmei_debug && vmei_dbg_file) { \
|
||||
fprintf(vmei_dbg_file, "vmei: %s: " format, \
|
||||
__func__, ##arg); \
|
||||
fflush(vmei_dbg_file); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define WPRINTF(format, arg...) do { \
|
||||
fprintf(stderr, "vmei: %s: " format, __func__, ##arg); \
|
||||
if (vmei_dbg_file) { \
|
||||
fprintf(vmei_dbg_file, "vmei: %s: " format, \
|
||||
__func__, ##arg); \
|
||||
fflush(vmei_dbg_file); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MEI_HCL_FMT(format) "CL:[%02d:%02d](%04d): " format
|
||||
#define MEI_HCL_PRM(_hcl) (_hcl)->host_addr, (_hcl)->me_addr, (_hcl)->client_fd
|
||||
#define HCL_DBG(_hcl, format, arg...) \
|
||||
DPRINTF(MEI_HCL_FMT(format), MEI_HCL_PRM(_hcl), ##arg)
|
||||
#define HCL_WARN(_hcl, format, arg...) \
|
||||
WPRINTF(MEI_HCL_FMT(format), MEI_HCL_PRM(_hcl), ##arg)
|
||||
|
||||
static void vmei_dbg_print_hex(const char *title,
|
||||
const void *data, size_t length)
|
||||
{
|
||||
const unsigned char *bytes = data;
|
||||
FILE *dbg_file;
|
||||
size_t i;
|
||||
|
||||
if (vmei_debug < 2)
|
||||
return;
|
||||
|
||||
dbg_file = (vmei_dbg_file) ? vmei_dbg_file : stdout;
|
||||
|
||||
if (title)
|
||||
fprintf(dbg_file, "%s ", title);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (i % 16 == 0 && i != 0)
|
||||
fprintf(dbg_file, "\n");
|
||||
fprintf(dbg_file, "%02x ", bytes[i]);
|
||||
}
|
||||
fprintf(dbg_file, "\n");
|
||||
}
|
||||
|
||||
|
||||
#define MEI_FW_STATUS_MAX 6
|
||||
|
||||
#define VMEI_VQ_NUM 2
|
||||
@ -179,6 +230,369 @@ struct mei_virtio_cfg {
|
||||
uint32_t fw_status[MEI_FW_STATUS_MAX];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define VMEI_IOBUFS_MAX 8
|
||||
struct vmei_circular_iobufs {
|
||||
struct iovec bufs[VMEI_IOBUFS_MAX];
|
||||
uint8_t complete[VMEI_IOBUFS_MAX];
|
||||
size_t buf_sz;
|
||||
uint8_t i_idx; /* insert index */
|
||||
uint8_t r_idx; /* remove index */
|
||||
};
|
||||
|
||||
struct virtio_mei;
|
||||
|
||||
struct vmei_host_client {
|
||||
struct refcnt ref;
|
||||
struct vmei_me_client *mclient;
|
||||
LIST_ENTRY(vmei_host_client) list;
|
||||
|
||||
uint8_t me_addr;
|
||||
uint8_t host_addr;
|
||||
uint8_t reserved[2];
|
||||
int client_fd;
|
||||
|
||||
struct mevent *rx_mevp;
|
||||
uint8_t *recv_buf;
|
||||
size_t recv_buf_sz;
|
||||
int recv_offset;
|
||||
int recv_handled;
|
||||
int recv_creds;
|
||||
|
||||
struct vmei_circular_iobufs send_bufs;
|
||||
};
|
||||
|
||||
struct vmei_me_client {
|
||||
struct refcnt ref;
|
||||
struct virtio_mei *vmei;
|
||||
LIST_ENTRY(vmei_me_client) list;
|
||||
|
||||
uint8_t client_id;
|
||||
struct mei_client_properties props;
|
||||
pthread_mutex_t list_mutex;
|
||||
LIST_HEAD(connhead, vmei_host_client) connections;
|
||||
};
|
||||
|
||||
enum vmei_status {
|
||||
VMEI_STS_READY,
|
||||
VMEI_STS_PENDING_RESET,
|
||||
VMEI_STS_RESET,
|
||||
VMEI_STST_DEINIT
|
||||
};
|
||||
|
||||
struct virtio_mei {
|
||||
struct virtio_base base;
|
||||
char name[16];
|
||||
char devnode[32];
|
||||
struct mei_enumerate_me_clients me_clients_map;
|
||||
struct virtio_vq_info vqs[VMEI_VQ_NUM];
|
||||
volatile enum vmei_status status;
|
||||
uint8_t vtag;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
struct mevent *reset_mevp;
|
||||
|
||||
struct mei_virtio_cfg *config;
|
||||
|
||||
pthread_t tx_thread;
|
||||
pthread_mutex_t tx_mutex;
|
||||
pthread_cond_t tx_cond;
|
||||
|
||||
pthread_t rx_thread;
|
||||
pthread_mutex_t rx_mutex;
|
||||
pthread_cond_t rx_cond;
|
||||
bool rx_need_sched;
|
||||
|
||||
pthread_mutex_t list_mutex;
|
||||
LIST_HEAD(clhead, vmei_me_client) active_clients;
|
||||
struct vmei_me_client *hbm_client;
|
||||
int hbm_fd;
|
||||
};
|
||||
|
||||
static inline void
|
||||
vmei_set_status(struct virtio_mei *vmei, enum vmei_status status)
|
||||
{
|
||||
if (status == VMEI_STST_DEINIT ||
|
||||
status == VMEI_STS_READY ||
|
||||
status > vmei->status)
|
||||
vmei->status = status;
|
||||
}
|
||||
|
||||
static void
|
||||
vmei_host_client_destroy(const struct refcnt *ref)
|
||||
{
|
||||
struct vmei_host_client *hclient;
|
||||
struct vmei_me_client *mclient;
|
||||
unsigned int i;
|
||||
|
||||
hclient = container_of(ref, struct vmei_host_client, ref);
|
||||
|
||||
mclient = hclient->mclient;
|
||||
|
||||
pthread_mutex_lock(&mclient->list_mutex);
|
||||
LIST_REMOVE(hclient, list);
|
||||
pthread_mutex_unlock(&mclient->list_mutex);
|
||||
|
||||
if (hclient->rx_mevp)
|
||||
mevent_delete(hclient->rx_mevp);
|
||||
if (hclient->client_fd > -1)
|
||||
close(hclient->client_fd);
|
||||
for (i = 0; i < VMEI_IOBUFS_MAX; i++)
|
||||
free(hclient->send_bufs.bufs[i].iov_base);
|
||||
free(hclient->recv_buf);
|
||||
free(hclient);
|
||||
}
|
||||
|
||||
static struct vmei_host_client *
|
||||
vmei_host_client_create(struct vmei_me_client *mclient, uint8_t host_addr)
|
||||
{
|
||||
struct vmei_host_client *hclient;
|
||||
size_t size = mclient->props.max_msg_length;
|
||||
unsigned int i;
|
||||
|
||||
hclient = calloc(1, sizeof(*hclient));
|
||||
if (!hclient)
|
||||
return NULL;
|
||||
|
||||
hclient->ref = (struct refcnt){vmei_host_client_destroy, 1};
|
||||
|
||||
hclient->me_addr = mclient->client_id;
|
||||
hclient->host_addr = host_addr;
|
||||
hclient->mclient = mclient;
|
||||
hclient->client_fd = -1;
|
||||
hclient->rx_mevp = NULL;
|
||||
|
||||
/* HBM and fixed address doesn't provide flow control
|
||||
* make the receiving part always available.
|
||||
*/
|
||||
if (host_addr == 0)
|
||||
hclient->recv_creds = 1;
|
||||
|
||||
/* setup send_buf and recv_buf for the client */
|
||||
for (i = 0; i < VMEI_IOBUFS_MAX; i++) {
|
||||
hclient->send_bufs.bufs[i].iov_base = calloc(1, size);
|
||||
if (!hclient->send_bufs.bufs[i].iov_base) {
|
||||
HCL_WARN(hclient, "allocation failed\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
hclient->recv_buf = calloc(1, size);
|
||||
if (!hclient->recv_buf) {
|
||||
HCL_WARN(hclient, "allocation failed\n");
|
||||
goto fail;
|
||||
}
|
||||
hclient->send_bufs.buf_sz = size;
|
||||
hclient->recv_buf_sz = size;
|
||||
|
||||
pthread_mutex_lock(&mclient->list_mutex);
|
||||
LIST_INSERT_HEAD(&mclient->connections, hclient, list);
|
||||
pthread_mutex_unlock(&mclient->list_mutex);
|
||||
|
||||
return hclient;
|
||||
|
||||
fail:
|
||||
for (i = 0; i < VMEI_IOBUFS_MAX; i++)
|
||||
free(hclient->send_bufs.bufs[i].iov_base);
|
||||
memset(&hclient->send_bufs, 0, sizeof(hclient->send_bufs));
|
||||
free(hclient->recv_buf);
|
||||
free(hclient);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct vmei_host_client*
|
||||
vmei_host_client_get(struct vmei_host_client *hclient)
|
||||
{
|
||||
refcnt_get(&hclient->ref);
|
||||
return hclient;
|
||||
}
|
||||
|
||||
static void
|
||||
vmei_host_client_put(struct vmei_host_client *hclient)
|
||||
{
|
||||
refcnt_put(&hclient->ref);
|
||||
}
|
||||
|
||||
struct virtio_mei *
|
||||
vmei_host_client_to_vmei(struct vmei_host_client *hclient)
|
||||
{
|
||||
if (hclient && hclient->mclient)
|
||||
return hclient->mclient->vmei;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
vmei_del_me_client(struct vmei_me_client *mclient)
|
||||
{
|
||||
struct virtio_mei *vmei = mclient->vmei;
|
||||
|
||||
pthread_mutex_lock(&vmei->list_mutex);
|
||||
LIST_REMOVE(mclient, list);
|
||||
pthread_mutex_unlock(&vmei->list_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
vmei_me_client_destroy_host_clients(struct vmei_me_client *mclient)
|
||||
{
|
||||
struct vmei_host_client *e, *n;
|
||||
|
||||
pthread_mutex_lock(&mclient->list_mutex);
|
||||
e = LIST_FIRST(&mclient->connections);
|
||||
while (e) {
|
||||
n = LIST_NEXT(e, list);
|
||||
vmei_host_client_put(e);
|
||||
e = n;
|
||||
}
|
||||
pthread_mutex_unlock(&mclient->list_mutex);
|
||||
LIST_INIT(&mclient->connections);
|
||||
}
|
||||
|
||||
static void
|
||||
vmei_me_client_destroy(const struct refcnt *ref)
|
||||
{
|
||||
struct vmei_me_client *mclient;
|
||||
|
||||
mclient = container_of(ref, struct vmei_me_client, ref);
|
||||
|
||||
vmei_del_me_client(mclient);
|
||||
vmei_me_client_destroy_host_clients(mclient);
|
||||
pthread_mutex_destroy(&mclient->list_mutex);
|
||||
free(mclient);
|
||||
}
|
||||
|
||||
static struct vmei_me_client *
|
||||
vmei_me_client_create(struct virtio_mei *vmei, uint8_t client_id,
|
||||
const struct mei_client_properties *props)
|
||||
{
|
||||
struct vmei_me_client *mclient;
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
if (!props)
|
||||
return NULL;
|
||||
|
||||
mclient = calloc(1, sizeof(*mclient));
|
||||
if (!mclient)
|
||||
return mclient;
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&mclient->list_mutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
|
||||
mclient->vmei = vmei;
|
||||
mclient->client_id = client_id;
|
||||
mclient->ref = (struct refcnt){vmei_me_client_destroy, 1};
|
||||
|
||||
memcpy(&mclient->props, props, sizeof(*props));
|
||||
vmei_dbg_client_properties(&mclient->props);
|
||||
|
||||
DPRINTF("ME client created %d\n", client_id);
|
||||
|
||||
return mclient;
|
||||
}
|
||||
|
||||
static struct vmei_me_client*
|
||||
vmei_me_client_get(struct vmei_me_client *mclient)
|
||||
{
|
||||
refcnt_get(&mclient->ref);
|
||||
return mclient;
|
||||
}
|
||||
|
||||
static void
|
||||
vmei_me_client_put(struct vmei_me_client *mclient)
|
||||
{
|
||||
refcnt_put(&mclient->ref);
|
||||
}
|
||||
|
||||
static struct vmei_host_client*
|
||||
vmei_me_client_get_host_client(struct vmei_me_client *mclient,
|
||||
uint8_t host_addr)
|
||||
{
|
||||
struct vmei_host_client *e, *hclient = NULL;
|
||||
|
||||
pthread_mutex_lock(&mclient->list_mutex);
|
||||
LIST_FOREACH(e, &mclient->connections, list) {
|
||||
if (e->host_addr == host_addr) {
|
||||
hclient = vmei_host_client_get(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mclient->list_mutex);
|
||||
|
||||
return hclient;
|
||||
}
|
||||
|
||||
static void vmei_add_me_client(struct vmei_me_client *mclient)
|
||||
{
|
||||
struct virtio_mei *vmei = mclient->vmei;
|
||||
|
||||
pthread_mutex_lock(&vmei->list_mutex);
|
||||
if (mclient->client_id == 0)
|
||||
/* make sure hbm client at the head of the list */
|
||||
LIST_INSERT_HEAD(&vmei->active_clients, mclient, list);
|
||||
else
|
||||
LIST_INSERT_AFTER(LIST_FIRST(&vmei->active_clients),
|
||||
mclient, list);
|
||||
pthread_mutex_unlock(&vmei->list_mutex);
|
||||
}
|
||||
|
||||
static struct vmei_me_client *
|
||||
vmei_find_me_client(struct virtio_mei *vmei, uint8_t client_id)
|
||||
{
|
||||
struct vmei_me_client *e, *mclient = NULL;
|
||||
|
||||
pthread_mutex_lock(&vmei->list_mutex);
|
||||
LIST_FOREACH(e, &vmei->active_clients, list) {
|
||||
if (e->client_id == client_id) {
|
||||
mclient = vmei_me_client_get(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&vmei->list_mutex);
|
||||
return mclient;
|
||||
}
|
||||
|
||||
|
||||
static struct vmei_host_client*
|
||||
vmei_find_host_client(struct virtio_mei *vmei,
|
||||
uint8_t me_addr, uint8_t host_addr)
|
||||
{
|
||||
struct vmei_me_client *mclient;
|
||||
struct vmei_host_client *hclient;
|
||||
|
||||
mclient = vmei_find_me_client(vmei, me_addr);
|
||||
if (!mclient) {
|
||||
DPRINTF("client with me address %d was not found\n", me_addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hclient = vmei_me_client_get_host_client(mclient, host_addr);
|
||||
if (!hclient)
|
||||
DPRINTF("host client %d does not exists!\n", host_addr);
|
||||
|
||||
vmei_me_client_put(mclient);
|
||||
|
||||
return hclient;
|
||||
}
|
||||
|
||||
static void vmei_free_me_clients(struct virtio_mei *vmei)
|
||||
{
|
||||
struct vmei_me_client *e, *n;
|
||||
|
||||
pthread_mutex_lock(&vmei->list_mutex);
|
||||
e = LIST_FIRST(&vmei->active_clients);
|
||||
while (e) {
|
||||
n = LIST_NEXT(e, list);
|
||||
vmei_me_client_put(e);
|
||||
e = n;
|
||||
}
|
||||
LIST_INIT(&vmei->active_clients);
|
||||
pthread_mutex_unlock(&vmei->list_mutex);
|
||||
}
|
||||
|
||||
|
||||
static int mei_sysfs_read_property_file(const char *fname, char *buf, size_t sz)
|
||||
{
|
||||
int fd;
|
||||
|
Loading…
Reference in New Issue
Block a user