Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/vmbus/vmbus.c
Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
static int vmbus_probe_guid_method(device_t, device_t, | static int vmbus_probe_guid_method(device_t, device_t, | ||||
const struct hyperv_guid *); | const struct hyperv_guid *); | ||||
static int vmbus_init(struct vmbus_softc *); | static int vmbus_init(struct vmbus_softc *); | ||||
static int vmbus_connect(struct vmbus_softc *, uint32_t); | static int vmbus_connect(struct vmbus_softc *, uint32_t); | ||||
static int vmbus_req_channels(struct vmbus_softc *sc); | static int vmbus_req_channels(struct vmbus_softc *sc); | ||||
static void vmbus_disconnect(struct vmbus_softc *); | static void vmbus_disconnect(struct vmbus_softc *); | ||||
static int vmbus_scan(struct vmbus_softc *); | static int vmbus_scan(struct vmbus_softc *); | ||||
static void vmbus_scan_wait(struct vmbus_softc *); | static void vmbus_scan_teardown(struct vmbus_softc *); | ||||
static void vmbus_scan_newchan(struct vmbus_softc *); | |||||
static void vmbus_scan_newdev(struct vmbus_softc *); | |||||
static void vmbus_scan_done(struct vmbus_softc *, | static void vmbus_scan_done(struct vmbus_softc *, | ||||
const struct vmbus_message *); | const struct vmbus_message *); | ||||
static void vmbus_chanmsg_handle(struct vmbus_softc *, | static void vmbus_chanmsg_handle(struct vmbus_softc *, | ||||
const struct vmbus_message *); | const struct vmbus_message *); | ||||
static void vmbus_msg_task(void *, int); | static void vmbus_msg_task(void *, int); | ||||
static void vmbus_synic_setup(void *); | static void vmbus_synic_setup(void *); | ||||
static void vmbus_synic_teardown(void *); | static void vmbus_synic_teardown(void *); | ||||
static int vmbus_sysctl_version(SYSCTL_HANDLER_ARGS); | static int vmbus_sysctl_version(SYSCTL_HANDLER_ARGS); | ||||
▲ Show 20 Lines • Show All 291 Lines • ▼ Show 20 Lines | vmbus_req_channels(struct vmbus_softc *sc) | ||||
error = vmbus_msghc_exec_noresult(mh); | error = vmbus_msghc_exec_noresult(mh); | ||||
vmbus_msghc_put(sc, mh); | vmbus_msghc_put(sc, mh); | ||||
return error; | return error; | ||||
} | } | ||||
static void | static void | ||||
vmbus_scan_newchan(struct vmbus_softc *sc) | vmbus_scan_done_task(void *xsc, int pending __unused) | ||||
{ | { | ||||
mtx_lock(&sc->vmbus_scan_lock); | struct vmbus_softc *sc = xsc; | ||||
if ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0) | |||||
sc->vmbus_scan_chcnt++; | mtx_lock(&Giant); | ||||
mtx_unlock(&sc->vmbus_scan_lock); | sc->vmbus_scandone = true; | ||||
mtx_unlock(&Giant); | |||||
wakeup(&sc->vmbus_scandone); | |||||
} | } | ||||
static void | static void | ||||
vmbus_scan_done(struct vmbus_softc *sc, | vmbus_scan_done(struct vmbus_softc *sc, | ||||
const struct vmbus_message *msg __unused) | const struct vmbus_message *msg __unused) | ||||
{ | { | ||||
mtx_lock(&sc->vmbus_scan_lock); | |||||
sc->vmbus_scan_chcnt |= VMBUS_SCAN_CHCNT_DONE; | |||||
mtx_unlock(&sc->vmbus_scan_lock); | |||||
wakeup(&sc->vmbus_scan_chcnt); | |||||
} | |||||
static void | taskqueue_enqueue(sc->vmbus_devtq, &sc->vmbus_scandone_task); | ||||
vmbus_scan_newdev(struct vmbus_softc *sc) | |||||
{ | |||||
mtx_lock(&sc->vmbus_scan_lock); | |||||
sc->vmbus_scan_devcnt++; | |||||
mtx_unlock(&sc->vmbus_scan_lock); | |||||
wakeup(&sc->vmbus_scan_devcnt); | |||||
} | } | ||||
static void | |||||
vmbus_scan_wait(struct vmbus_softc *sc) | |||||
{ | |||||
uint32_t chancnt; | |||||
mtx_lock(&sc->vmbus_scan_lock); | |||||
while ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0) { | |||||
mtx_sleep(&sc->vmbus_scan_chcnt, &sc->vmbus_scan_lock, 0, | |||||
"waitch", 0); | |||||
} | |||||
chancnt = sc->vmbus_scan_chcnt & ~VMBUS_SCAN_CHCNT_DONE; | |||||
while (sc->vmbus_scan_devcnt != chancnt) { | |||||
mtx_sleep(&sc->vmbus_scan_devcnt, &sc->vmbus_scan_lock, 0, | |||||
"waitdev", 0); | |||||
} | |||||
mtx_unlock(&sc->vmbus_scan_lock); | |||||
} | |||||
static int | static int | ||||
vmbus_scan(struct vmbus_softc *sc) | vmbus_scan(struct vmbus_softc *sc) | ||||
{ | { | ||||
int error; | int error; | ||||
/* | /* | ||||
* Identify, probe and attach for non-channel devices. | |||||
*/ | |||||
bus_generic_probe(sc->vmbus_dev); | |||||
bus_generic_attach(sc->vmbus_dev); | |||||
/* | |||||
* This taskqueue serializes vmbus devices' attach and detach | |||||
* for channel offer and rescind messages. | |||||
*/ | |||||
sc->vmbus_devtq = taskqueue_create("vmbus dev", M_WAITOK, | |||||
taskqueue_thread_enqueue, &sc->vmbus_devtq); | |||||
taskqueue_start_threads(&sc->vmbus_devtq, 1, PI_NET, "vmbusdev"); | |||||
TASK_INIT(&sc->vmbus_scandone_task, 0, vmbus_scan_done_task, sc); | |||||
/* | |||||
* This taskqueue handles sub-channel detach, so that vmbus | |||||
* device's detach running in vmbus_devtq can drain its sub- | |||||
* channels. | |||||
*/ | |||||
sc->vmbus_subchtq = taskqueue_create("vmbus subch", M_WAITOK, | |||||
taskqueue_thread_enqueue, &sc->vmbus_subchtq); | |||||
taskqueue_start_threads(&sc->vmbus_subchtq, 1, PI_NET, "vmbussch"); | |||||
/* | |||||
* Start vmbus scanning. | * Start vmbus scanning. | ||||
*/ | */ | ||||
error = vmbus_req_channels(sc); | error = vmbus_req_channels(sc); | ||||
if (error) { | if (error) { | ||||
device_printf(sc->vmbus_dev, "channel request failed: %d\n", | device_printf(sc->vmbus_dev, "channel request failed: %d\n", | ||||
error); | error); | ||||
return error; | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Wait for all devices are added to vmbus. | * Wait for all vmbus devices from the initial channel offers to be | ||||
* attached. | |||||
*/ | */ | ||||
vmbus_scan_wait(sc); | GIANT_REQUIRED; | ||||
while (!sc->vmbus_scandone) | |||||
mtx_sleep(&sc->vmbus_scandone, &Giant, 0, "vmbusdev", 0); | |||||
/* | |||||
* Identify, probe and attach. | |||||
*/ | |||||
bus_generic_probe(sc->vmbus_dev); | |||||
bus_generic_attach(sc->vmbus_dev); | |||||
if (bootverbose) { | if (bootverbose) { | ||||
device_printf(sc->vmbus_dev, "device scan, probe and attach " | device_printf(sc->vmbus_dev, "device scan, probe and attach " | ||||
"done\n"); | "done\n"); | ||||
} | } | ||||
return 0; | return (0); | ||||
} | } | ||||
static void | static void | ||||
vmbus_scan_teardown(struct vmbus_softc *sc) | |||||
{ | |||||
GIANT_REQUIRED; | |||||
if (sc->vmbus_devtq != NULL) { | |||||
mtx_unlock(&Giant); | |||||
taskqueue_free(sc->vmbus_devtq); | |||||
mtx_lock(&Giant); | |||||
sc->vmbus_devtq = NULL; | |||||
} | |||||
if (sc->vmbus_subchtq != NULL) { | |||||
mtx_unlock(&Giant); | |||||
taskqueue_free(sc->vmbus_subchtq); | |||||
mtx_lock(&Giant); | |||||
sc->vmbus_subchtq = NULL; | |||||
} | |||||
} | |||||
static void | |||||
vmbus_chanmsg_handle(struct vmbus_softc *sc, const struct vmbus_message *msg) | vmbus_chanmsg_handle(struct vmbus_softc *sc, const struct vmbus_message *msg) | ||||
{ | { | ||||
vmbus_chanmsg_proc_t msg_proc; | vmbus_chanmsg_proc_t msg_proc; | ||||
uint32_t msg_type; | uint32_t msg_type; | ||||
msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type; | msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type; | ||||
if (msg_type >= VMBUS_CHANMSG_TYPE_MAX) { | if (msg_type >= VMBUS_CHANMSG_TYPE_MAX) { | ||||
device_printf(sc->vmbus_dev, "unknown message type 0x%x\n", | device_printf(sc->vmbus_dev, "unknown message type 0x%x\n", | ||||
▲ Show 20 Lines • Show All 429 Lines • ▼ Show 20 Lines | vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
vmbus_add_child(struct vmbus_channel *chan) | vmbus_add_child(struct vmbus_channel *chan) | ||||
{ | { | ||||
struct vmbus_softc *sc = chan->ch_vmbus; | struct vmbus_softc *sc = chan->ch_vmbus; | ||||
device_t parent = sc->vmbus_dev; | device_t parent = sc->vmbus_dev; | ||||
int error = 0; | |||||
/* New channel has been offered */ | mtx_lock(&Giant); | ||||
vmbus_scan_newchan(sc); | |||||
chan->ch_dev = device_add_child(parent, NULL, -1); | chan->ch_dev = device_add_child(parent, NULL, -1); | ||||
if (chan->ch_dev == NULL) { | if (chan->ch_dev == NULL) { | ||||
mtx_unlock(&Giant); | |||||
device_printf(parent, "device_add_child for chan%u failed\n", | device_printf(parent, "device_add_child for chan%u failed\n", | ||||
chan->ch_id); | chan->ch_id); | ||||
error = ENXIO; | return (ENXIO); | ||||
goto done; | |||||
} | } | ||||
device_set_ivars(chan->ch_dev, chan); | device_set_ivars(chan->ch_dev, chan); | ||||
device_probe_and_attach(chan->ch_dev); | |||||
done: | mtx_unlock(&Giant); | ||||
/* New device has been/should be added to vmbus. */ | return (0); | ||||
vmbus_scan_newdev(sc); | |||||
return error; | |||||
} | } | ||||
int | int | ||||
vmbus_delete_child(struct vmbus_channel *chan) | vmbus_delete_child(struct vmbus_channel *chan) | ||||
{ | { | ||||
int error; | int error = 0; | ||||
if (chan->ch_dev == NULL) { | |||||
/* Failed to add a device. */ | |||||
return 0; | |||||
} | |||||
/* | |||||
* XXXKYS: Ensure that this is the opposite of | |||||
* device_add_child() | |||||
*/ | |||||
mtx_lock(&Giant); | mtx_lock(&Giant); | ||||
error = device_delete_child(chan->ch_vmbus->vmbus_dev, chan->ch_dev); | if (chan->ch_dev != NULL) { | ||||
error = device_delete_child(chan->ch_vmbus->vmbus_dev, | |||||
chan->ch_dev); | |||||
} | |||||
mtx_unlock(&Giant); | mtx_unlock(&Giant); | ||||
return (error); | |||||
return error; | |||||
} | } | ||||
static int | static int | ||||
vmbus_sysctl_version(SYSCTL_HANDLER_ARGS) | vmbus_sysctl_version(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct vmbus_softc *sc = arg1; | struct vmbus_softc *sc = arg1; | ||||
char verstr[16]; | char verstr[16]; | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | vmbus_doattach(struct vmbus_softc *sc) | ||||
struct sysctl_oid_list *child; | struct sysctl_oid_list *child; | ||||
struct sysctl_ctx_list *ctx; | struct sysctl_ctx_list *ctx; | ||||
int ret; | int ret; | ||||
if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) | if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) | ||||
return (0); | return (0); | ||||
sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; | sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; | ||||
mtx_init(&sc->vmbus_scan_lock, "vmbus scan", NULL, MTX_DEF); | |||||
sc->vmbus_gpadl = VMBUS_GPADL_START; | sc->vmbus_gpadl = VMBUS_GPADL_START; | ||||
mtx_init(&sc->vmbus_prichan_lock, "vmbus prichan", NULL, MTX_DEF); | mtx_init(&sc->vmbus_prichan_lock, "vmbus prichan", NULL, MTX_DEF); | ||||
TAILQ_INIT(&sc->vmbus_prichans); | TAILQ_INIT(&sc->vmbus_prichans); | ||||
mtx_init(&sc->vmbus_chan_lock, "vmbus channel", NULL, MTX_DEF); | |||||
TAILQ_INIT(&sc->vmbus_chans); | |||||
sc->vmbus_chmap = malloc( | sc->vmbus_chmap = malloc( | ||||
sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX, M_DEVBUF, | sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX, M_DEVBUF, | ||||
M_WAITOK | M_ZERO); | M_WAITOK | M_ZERO); | ||||
/* | /* | ||||
* Create context for "post message" Hypercalls | * Create context for "post message" Hypercalls | ||||
*/ | */ | ||||
sc->vmbus_xc = vmbus_xact_ctx_create(bus_get_dma_tag(sc->vmbus_dev), | sc->vmbus_xc = vmbus_xact_ctx_create(bus_get_dma_tag(sc->vmbus_dev), | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | vmbus_doattach(struct vmbus_softc *sc) | ||||
child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vmbus_dev)); | child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vmbus_dev)); | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "version", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "version", | ||||
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, | CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, | ||||
vmbus_sysctl_version, "A", "vmbus version"); | vmbus_sysctl_version, "A", "vmbus version"); | ||||
return (ret); | return (ret); | ||||
cleanup: | cleanup: | ||||
vmbus_scan_teardown(sc); | |||||
vmbus_intr_teardown(sc); | vmbus_intr_teardown(sc); | ||||
vmbus_dma_free(sc); | vmbus_dma_free(sc); | ||||
if (sc->vmbus_xc != NULL) { | if (sc->vmbus_xc != NULL) { | ||||
vmbus_xact_ctx_destroy(sc->vmbus_xc); | vmbus_xact_ctx_destroy(sc->vmbus_xc); | ||||
sc->vmbus_xc = NULL; | sc->vmbus_xc = NULL; | ||||
} | } | ||||
free(sc->vmbus_chmap, M_DEVBUF); | free(sc->vmbus_chmap, M_DEVBUF); | ||||
mtx_destroy(&sc->vmbus_scan_lock); | |||||
mtx_destroy(&sc->vmbus_prichan_lock); | mtx_destroy(&sc->vmbus_prichan_lock); | ||||
mtx_destroy(&sc->vmbus_chan_lock); | |||||
return (ret); | return (ret); | ||||
} | } | ||||
static void | static void | ||||
vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused) | vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused) | ||||
{ | { | ||||
} | } | ||||
Show All 26 Lines | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
vmbus_detach(device_t dev) | vmbus_detach(device_t dev) | ||||
{ | { | ||||
struct vmbus_softc *sc = device_get_softc(dev); | struct vmbus_softc *sc = device_get_softc(dev); | ||||
bus_generic_detach(dev); | |||||
vmbus_chan_destroy_all(sc); | vmbus_chan_destroy_all(sc); | ||||
vmbus_scan_teardown(sc); | |||||
vmbus_disconnect(sc); | vmbus_disconnect(sc); | ||||
if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) { | if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) { | ||||
sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC; | sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC; | ||||
smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL); | smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL); | ||||
} | } | ||||
vmbus_intr_teardown(sc); | vmbus_intr_teardown(sc); | ||||
vmbus_dma_free(sc); | vmbus_dma_free(sc); | ||||
if (sc->vmbus_xc != NULL) { | if (sc->vmbus_xc != NULL) { | ||||
vmbus_xact_ctx_destroy(sc->vmbus_xc); | vmbus_xact_ctx_destroy(sc->vmbus_xc); | ||||
sc->vmbus_xc = NULL; | sc->vmbus_xc = NULL; | ||||
} | } | ||||
free(sc->vmbus_chmap, M_DEVBUF); | free(sc->vmbus_chmap, M_DEVBUF); | ||||
mtx_destroy(&sc->vmbus_scan_lock); | |||||
mtx_destroy(&sc->vmbus_prichan_lock); | mtx_destroy(&sc->vmbus_prichan_lock); | ||||
mtx_destroy(&sc->vmbus_chan_lock); | |||||
return (0); | return (0); | ||||
} | } | ||||
#ifndef EARLY_AP_STARTUP | #ifndef EARLY_AP_STARTUP | ||||
static void | static void | ||||
vmbus_sysinit(void *arg __unused) | vmbus_sysinit(void *arg __unused) | ||||
Show All 23 Lines |