Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
Show All 34 Lines | |||||
#include <dev/hyperv/include/hyperv_busdma.h> | #include <dev/hyperv/include/hyperv_busdma.h> | ||||
#include <dev/hyperv/vmbus/hv_vmbus_priv.h> | #include <dev/hyperv/vmbus/hv_vmbus_priv.h> | ||||
#include <dev/hyperv/vmbus/vmbus_reg.h> | #include <dev/hyperv/vmbus/vmbus_reg.h> | ||||
#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 void vmbus_channel_on_offer_internal(struct vmbus_softc *, | static void vmbus_channel_on_offer_internal(struct vmbus_softc *, | ||||
const struct vmbus_chanmsg_choffer *); | const struct vmbus_chanmsg_choffer *); | ||||
static void vmbus_chan_detach_task(void *, int); | 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_offers_delivered(struct vmbus_softc *, | static void vmbus_channel_on_offers_delivered(struct vmbus_softc *, | ||||
const struct vmbus_message *); | const struct vmbus_message *); | ||||
Show All 19 Lines | vmbus_chanmsg_process[VMBUS_CHANMSG_TYPE_MAX] = { | ||||
VMBUS_CHANMSG_PROC_WAKEUP(GPADL_CONNRESP), | VMBUS_CHANMSG_PROC_WAKEUP(GPADL_CONNRESP), | ||||
VMBUS_CHANMSG_PROC_WAKEUP(GPADL_DISCONNRESP), | VMBUS_CHANMSG_PROC_WAKEUP(GPADL_DISCONNRESP), | ||||
VMBUS_CHANMSG_PROC_WAKEUP(CONNECT_RESP) | VMBUS_CHANMSG_PROC_WAKEUP(CONNECT_RESP) | ||||
}; | }; | ||||
#undef VMBUS_CHANMSG_PROC_WAKEUP | #undef VMBUS_CHANMSG_PROC_WAKEUP | ||||
#undef VMBUS_CHANMSG_PROC | #undef VMBUS_CHANMSG_PROC | ||||
/** | |||||
* @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) | vmbus_chan_alloc(struct vmbus_softc *sc) | ||||
{ | { | ||||
struct hv_vmbus_channel *channel; | struct hv_vmbus_channel *chan; | ||||
channel = malloc(sizeof(*channel), M_DEVBUF, M_WAITOK | M_ZERO); | chan = malloc(sizeof(*chan), M_DEVBUF, M_WAITOK | M_ZERO); | ||||
channel->vmbus_sc = sc; | |||||
mtx_init(&channel->sc_lock, "vmbus multi channel", NULL, MTX_DEF); | chan->ch_monprm = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev), | ||||
TAILQ_INIT(&channel->sc_list_anchor); | HYPERCALL_PARAM_ALIGN, 0, sizeof(struct hyperv_mon_param), | ||||
TASK_INIT(&channel->ch_detach_task, 0, vmbus_chan_detach_task, channel); | &chan->ch_monprm_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); | ||||
if (chan->ch_monprm == NULL) { | |||||
device_printf(sc->vmbus_dev, "monprm alloc failed\n"); | |||||
free(chan, M_DEVBUF); | |||||
return NULL; | |||||
} | |||||
return (channel); | chan->vmbus_sc = sc; | ||||
mtx_init(&chan->sc_lock, "vmbus multi channel", NULL, MTX_DEF); | |||||
TAILQ_INIT(&chan->sc_list_anchor); | |||||
TASK_INIT(&chan->ch_detach_task, 0, vmbus_chan_detach_task, chan); | |||||
return chan; | |||||
} | } | ||||
/** | static void | ||||
* @brief Release the resources used by the vmbus channel object | vmbus_chan_free(struct hv_vmbus_channel *chan) | ||||
*/ | |||||
void | |||||
hv_vmbus_free_vmbus_channel(hv_vmbus_channel* channel) | |||||
{ | { | ||||
mtx_destroy(&channel->sc_lock); | /* TODO: assert sub-channel list is empty */ | ||||
free(channel, M_DEVBUF); | /* TODO: asset no longer on the primary channel's sub-channel list */ | ||||
/* TODO: asset no longer on the vmbus channel list */ | |||||
hyperv_dmamem_free(&chan->ch_monprm_dma, chan->ch_monprm); | |||||
mtx_destroy(&chan->sc_lock); | |||||
free(chan, M_DEVBUF); | |||||
} | } | ||||
/** | /** | ||||
* @brief Process the offer by creating a channel/device | * @brief Process the offer by creating a channel/device | ||||
* associated with this offer | * associated with this offer | ||||
*/ | */ | ||||
static void | static void | ||||
vmbus_channel_process_offer(hv_vmbus_channel *new_channel) | vmbus_channel_process_offer(hv_vmbus_channel *new_channel) | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | if (new_channel->ch_subidx != 0) { | ||||
mtx_unlock(&channel->sc_lock); | mtx_unlock(&channel->sc_lock); | ||||
wakeup(channel); | wakeup(channel); | ||||
return; | return; | ||||
} | } | ||||
printf("VMBUS: duplicated primary channel%u\n", | printf("VMBUS: duplicated primary channel%u\n", | ||||
new_channel->ch_id); | new_channel->ch_id); | ||||
hv_vmbus_free_vmbus_channel(new_channel); | vmbus_chan_free(new_channel); | ||||
return; | return; | ||||
} | } | ||||
new_channel->state = HV_CHANNEL_OPEN_STATE; | new_channel->state = HV_CHANNEL_OPEN_STATE; | ||||
/* | /* | ||||
* Add the new device to the bus. This will kick off device-driver | * Add the new device to the bus. This will kick off device-driver | ||||
* binding which eventually invokes the device driver's AddDevice() | * binding which eventually invokes the device driver's AddDevice() | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
vmbus_channel_on_offer_internal(struct vmbus_softc *sc, | vmbus_channel_on_offer_internal(struct vmbus_softc *sc, | ||||
const struct vmbus_chanmsg_choffer *offer) | const struct vmbus_chanmsg_choffer *offer) | ||||
{ | { | ||||
hv_vmbus_channel* new_channel; | hv_vmbus_channel* new_channel; | ||||
/* | /* | ||||
* Allocate the channel object and save this offer | * Allocate the channel object and save this offer | ||||
*/ | */ | ||||
new_channel = hv_vmbus_allocate_channel(sc); | new_channel = vmbus_chan_alloc(sc); | ||||
if (new_channel == NULL) { | |||||
device_printf(sc->vmbus_dev, "allocate chan%u failed\n", | |||||
offer->chm_chanid); | |||||
return; | |||||
} | |||||
new_channel->ch_id = offer->chm_chanid; | new_channel->ch_id = offer->chm_chanid; | ||||
new_channel->ch_subidx = offer->chm_subidx; | new_channel->ch_subidx = offer->chm_subidx; | ||||
new_channel->ch_guid_type = offer->chm_chtype; | new_channel->ch_guid_type = offer->chm_chtype; | ||||
new_channel->ch_guid_inst = offer->chm_chinst; | new_channel->ch_guid_inst = offer->chm_chinst; | ||||
/* Batch reading is on by default */ | /* Batch reading is on by default */ | ||||
new_channel->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD; | new_channel->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD; | ||||
if (offer->chm_flags1 & VMBUS_CHOFFER_FLAG1_HASMNF) | if (offer->chm_flags1 & VMBUS_CHOFFER_FLAG1_HASMNF) | ||||
new_channel->ch_flags |= VMBUS_CHAN_FLAG_HASMNF; | new_channel->ch_flags |= VMBUS_CHAN_FLAG_HASMNF; | ||||
new_channel->ch_monprm = hyperv_dmamem_alloc( | |||||
bus_get_dma_tag(sc->vmbus_dev), | |||||
HYPERCALL_PARAM_ALIGN, 0, sizeof(struct hyperv_mon_param), | |||||
&new_channel->ch_monprm_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); | |||||
if (new_channel->ch_monprm == NULL) { | |||||
device_printf(sc->vmbus_dev, "monprm alloc failed\n"); | |||||
/* XXX */ | |||||
mtx_destroy(&new_channel->sc_lock); | |||||
free(new_channel, M_DEVBUF); | |||||
return; | |||||
} | |||||
new_channel->ch_monprm->mp_connid = VMBUS_CONNID_EVENT; | new_channel->ch_monprm->mp_connid = VMBUS_CONNID_EVENT; | ||||
if (sc->vmbus_version != VMBUS_VERSION_WS2008) | if (sc->vmbus_version != VMBUS_VERSION_WS2008) | ||||
new_channel->ch_monprm->mp_connid = offer->chm_connid; | new_channel->ch_monprm->mp_connid = offer->chm_connid; | ||||
if (new_channel->ch_flags & VMBUS_CHAN_FLAG_HASMNF) { | if (new_channel->ch_flags & VMBUS_CHAN_FLAG_HASMNF) { | ||||
new_channel->ch_montrig_idx = | new_channel->ch_montrig_idx = | ||||
offer->chm_montrig / VMBUS_MONTRIG_LEN; | offer->chm_montrig / VMBUS_MONTRIG_LEN; | ||||
if (new_channel->ch_montrig_idx >= VMBUS_MONTRIGS_MAX) | if (new_channel->ch_montrig_idx >= VMBUS_MONTRIGS_MAX) | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | remove: | ||||
mtx_lock(&pri_chan->sc_lock); | mtx_lock(&pri_chan->sc_lock); | ||||
TAILQ_REMOVE(&pri_chan->sc_list_anchor, chan, sc_list_entry); | TAILQ_REMOVE(&pri_chan->sc_list_anchor, chan, sc_list_entry); | ||||
KASSERT(pri_chan->subchan_cnt > 0, | KASSERT(pri_chan->subchan_cnt > 0, | ||||
("invalid subchan_cnt %d", pri_chan->subchan_cnt)); | ("invalid subchan_cnt %d", pri_chan->subchan_cnt)); | ||||
pri_chan->subchan_cnt--; | pri_chan->subchan_cnt--; | ||||
mtx_unlock(&pri_chan->sc_lock); | mtx_unlock(&pri_chan->sc_lock); | ||||
wakeup(pri_chan); | wakeup(pri_chan); | ||||
hv_vmbus_free_vmbus_channel(chan); | vmbus_chan_free(chan); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* | * | ||||
* @brief Invoked when all offers have been delivered. | * @brief Invoked when all offers have been delivered. | ||||
*/ | */ | ||||
static void | static void | ||||
Show All 18 Lines | hv_vmbus_release_unattached_channels(struct vmbus_softc *sc) | ||||
while (!TAILQ_EMPTY(&sc->vmbus_chlist)) { | while (!TAILQ_EMPTY(&sc->vmbus_chlist)) { | ||||
channel = TAILQ_FIRST(&sc->vmbus_chlist); | channel = TAILQ_FIRST(&sc->vmbus_chlist); | ||||
TAILQ_REMOVE(&sc->vmbus_chlist, channel, ch_link); | TAILQ_REMOVE(&sc->vmbus_chlist, channel, ch_link); | ||||
if (HV_VMBUS_CHAN_ISPRIMARY(channel)) { | if (HV_VMBUS_CHAN_ISPRIMARY(channel)) { | ||||
/* Only primary channel owns the device */ | /* Only primary channel owns the device */ | ||||
hv_vmbus_child_device_unregister(channel); | hv_vmbus_child_device_unregister(channel); | ||||
} | } | ||||
hv_vmbus_free_vmbus_channel(channel); | vmbus_chan_free(channel); | ||||
} | } | ||||
bzero(sc->vmbus_chmap, | bzero(sc->vmbus_chmap, | ||||
sizeof(struct hv_vmbus_channel *) * VMBUS_CHAN_MAX); | sizeof(struct hv_vmbus_channel *) * VMBUS_CHAN_MAX); | ||||
mtx_unlock(&sc->vmbus_chlist_lock); | mtx_unlock(&sc->vmbus_chlist_lock); | ||||
} | } | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 119 Lines • Show Last 20 Lines |