Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
Show All 36 Lines | |||||
#include <dev/hyperv/vmbus/vmbus_var.h> | #include <dev/hyperv/vmbus/vmbus_var.h> | ||||
typedef void (*vmbus_chanmsg_proc_t) | typedef void (*vmbus_chanmsg_proc_t) | ||||
(struct vmbus_softc *, const struct vmbus_message *); | (struct vmbus_softc *, const struct vmbus_message *); | ||||
static struct hv_vmbus_channel *hv_vmbus_allocate_channel(struct vmbus_softc *); | static struct hv_vmbus_channel *hv_vmbus_allocate_channel(struct vmbus_softc *); | ||||
static void vmbus_channel_on_offer_internal(struct vmbus_softc *, | static void vmbus_channel_on_offer_internal(struct vmbus_softc *, | ||||
const hv_vmbus_channel_offer_channel *offer); | const hv_vmbus_channel_offer_channel *offer); | ||||
static void vmbus_channel_on_offer_rescind_internal(void *context); | static void vmbus_chan_detach_task(void *, int); | ||||
static void vmbus_channel_on_offer(struct vmbus_softc *, | static void vmbus_channel_on_offer(struct vmbus_softc *, | ||||
const struct vmbus_message *); | const struct vmbus_message *); | ||||
static void vmbus_channel_on_open_result(struct vmbus_softc *, | static void vmbus_channel_on_open_result(struct vmbus_softc *, | ||||
const struct vmbus_message *); | const struct vmbus_message *); | ||||
static void vmbus_channel_on_offer_rescind(struct vmbus_softc *, | static void vmbus_channel_on_offer_rescind(struct vmbus_softc *, | ||||
const struct vmbus_message *); | const struct vmbus_message *); | ||||
static void vmbus_channel_on_gpadl_created(struct vmbus_softc *, | static void vmbus_channel_on_gpadl_created(struct vmbus_softc *, | ||||
Show All 21 Lines | vmbus_chanmsg_process[HV_CHANNEL_MESSAGE_COUNT] = { | ||||
[HV_CHANNEL_MESSAGE_GPADL_CREATED] = | [HV_CHANNEL_MESSAGE_GPADL_CREATED] = | ||||
vmbus_channel_on_gpadl_created, | vmbus_channel_on_gpadl_created, | ||||
[HV_CHANNEL_MESSAGE_GPADL_TORNDOWN] = | [HV_CHANNEL_MESSAGE_GPADL_TORNDOWN] = | ||||
vmbus_channel_on_gpadl_torndown, | vmbus_channel_on_gpadl_torndown, | ||||
[HV_CHANNEL_MESSAGE_VERSION_RESPONSE] = | [HV_CHANNEL_MESSAGE_VERSION_RESPONSE] = | ||||
vmbus_channel_on_version_response | vmbus_channel_on_version_response | ||||
}; | }; | ||||
typedef struct hv_work_item { | |||||
struct task work; | |||||
void (*callback)(void *); | |||||
void* context; | |||||
} hv_work_item; | |||||
static struct mtx vmbus_chwait_lock; | static struct mtx vmbus_chwait_lock; | ||||
MTX_SYSINIT(vmbus_chwait_lk, &vmbus_chwait_lock, "vmbus primarych wait lock", | MTX_SYSINIT(vmbus_chwait_lk, &vmbus_chwait_lock, "vmbus primarych wait lock", | ||||
MTX_DEF); | MTX_DEF); | ||||
static uint32_t vmbus_chancnt; | static uint32_t vmbus_chancnt; | ||||
static uint32_t vmbus_devcnt; | static uint32_t vmbus_devcnt; | ||||
#define VMBUS_CHANCNT_DONE 0x80000000 | #define VMBUS_CHANCNT_DONE 0x80000000 | ||||
/** | /** | ||||
* Implementation of the work abstraction. | |||||
*/ | |||||
static void | |||||
work_item_callback(void *work, int pending) | |||||
{ | |||||
struct hv_work_item *w = (struct hv_work_item *)work; | |||||
w->callback(w->context); | |||||
free(w, M_DEVBUF); | |||||
} | |||||
/** | |||||
* @brief Create work item | |||||
*/ | |||||
static int | |||||
hv_queue_work_item( | |||||
void (*callback)(void *), void *context) | |||||
{ | |||||
struct hv_work_item *w = malloc(sizeof(struct hv_work_item), | |||||
M_DEVBUF, M_NOWAIT); | |||||
KASSERT(w != NULL, ("Error VMBUS: Failed to allocate WorkItem\n")); | |||||
if (w == NULL) | |||||
return (ENOMEM); | |||||
w->callback = callback; | |||||
w->context = context; | |||||
TASK_INIT(&w->work, 0, work_item_callback, w); | |||||
return (taskqueue_enqueue(taskqueue_thread, &w->work)); | |||||
} | |||||
/** | |||||
* @brief Allocate and initialize a vmbus channel object | * @brief Allocate and initialize a vmbus channel object | ||||
*/ | */ | ||||
static struct hv_vmbus_channel * | static struct hv_vmbus_channel * | ||||
hv_vmbus_allocate_channel(struct vmbus_softc *sc) | hv_vmbus_allocate_channel(struct vmbus_softc *sc) | ||||
{ | { | ||||
struct hv_vmbus_channel *channel; | struct hv_vmbus_channel *channel; | ||||
channel = malloc(sizeof(*channel), M_DEVBUF, M_WAITOK | M_ZERO); | channel = malloc(sizeof(*channel), M_DEVBUF, M_WAITOK | M_ZERO); | ||||
channel->vmbus_sc = sc; | channel->vmbus_sc = sc; | ||||
mtx_init(&channel->sc_lock, "vmbus multi channel", NULL, MTX_DEF); | mtx_init(&channel->sc_lock, "vmbus multi channel", NULL, MTX_DEF); | ||||
TAILQ_INIT(&channel->sc_list_anchor); | TAILQ_INIT(&channel->sc_list_anchor); | ||||
TASK_INIT(&channel->ch_detach_task, 0, vmbus_chan_detach_task, channel); | |||||
return (channel); | return (channel); | ||||
} | } | ||||
/** | /** | ||||
* @brief Release the resources used by the vmbus channel object | * @brief Release the resources used by the vmbus channel object | ||||
*/ | */ | ||||
void | void | ||||
▲ Show 20 Lines • Show All 273 Lines • ▼ Show 20 Lines | vmbus_channel_on_offer_internal(struct vmbus_softc *sc, | ||||
vmbus_channel_process_offer(new_channel); | vmbus_channel_process_offer(new_channel); | ||||
} | } | ||||
/** | /** | ||||
* @brief Rescind offer handler. | * @brief Rescind offer handler. | ||||
* | * | ||||
* We queue a work item to process this offer | * We queue a work item to process this offer | ||||
* synchronously | * synchronously. | ||||
* | |||||
* XXX pretty broken; need rework. | |||||
*/ | */ | ||||
static void | static void | ||||
vmbus_channel_on_offer_rescind(struct vmbus_softc *sc, | vmbus_channel_on_offer_rescind(struct vmbus_softc *sc, | ||||
const struct vmbus_message *msg) | const struct vmbus_message *msg) | ||||
{ | { | ||||
const hv_vmbus_channel_msg_header *hdr = | |||||
(const hv_vmbus_channel_msg_header *)msg->msg_data; | |||||
const hv_vmbus_channel_rescind_offer *rescind; | const hv_vmbus_channel_rescind_offer *rescind; | ||||
hv_vmbus_channel* channel; | hv_vmbus_channel* channel; | ||||
rescind = (const hv_vmbus_channel_rescind_offer *)hdr; | rescind = (const hv_vmbus_channel_rescind_offer *)msg->msg_data; | ||||
channel = hv_vmbus_g_connection.channels[rescind->child_rel_id]; | channel = hv_vmbus_g_connection.channels[rescind->child_rel_id]; | ||||
if (channel == NULL) | if (channel == NULL) | ||||
return; | return; | ||||
hv_queue_work_item(vmbus_channel_on_offer_rescind_internal, channel); | |||||
hv_vmbus_g_connection.channels[rescind->child_rel_id] = NULL; | hv_vmbus_g_connection.channels[rescind->child_rel_id] = NULL; | ||||
taskqueue_enqueue(taskqueue_thread, &channel->ch_detach_task); | |||||
} | } | ||||
static void | static void | ||||
vmbus_channel_on_offer_rescind_internal(void *context) | vmbus_chan_detach_task(void *xchan, int pending __unused) | ||||
{ | { | ||||
hv_vmbus_channel* channel; | struct hv_vmbus_channel *chan = xchan; | ||||
channel = (hv_vmbus_channel*)context; | if (HV_VMBUS_CHAN_ISPRIMARY(chan)) { | ||||
if (HV_VMBUS_CHAN_ISPRIMARY(channel)) { | |||||
/* Only primary channel owns the hv_device */ | /* Only primary channel owns the hv_device */ | ||||
hv_vmbus_child_device_unregister(channel->device); | hv_vmbus_child_device_unregister(chan->device); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* | * | ||||
* @brief Invoked when all offers have been delivered. | * @brief Invoked when all offers have been delivered. | ||||
*/ | */ | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 310 Lines • Show Last 20 Lines |