Index: sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c =================================================================== --- sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -113,6 +113,7 @@ #include #include +#include #include "hv_net_vsc.h" #include "hv_rndis.h" #include "hv_rndis_filter.h" @@ -480,6 +481,10 @@ hn_tx_chimney_size < sc->hn_tx_chimney_max) hn_set_tx_chimney_size(sc, hn_tx_chimney_size); + ring_buffer_stat(device_get_sysctl_ctx(dev), + device_get_name(dev), device_get_unit(dev), + device_ctx->channel); + return (0); failed: hn_destroy_tx_data(sc); Index: sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c =================================================================== --- sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c +++ sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c @@ -72,6 +72,8 @@ #include #include +#include + #include "hv_vstorage.h" #define STORVSC_RINGBUFFER_SIZE (20*PAGE_SIZE) @@ -1106,6 +1108,9 @@ mtx_unlock(&sc->hs_lock); + ring_buffer_stat(device_get_sysctl_ctx(dev), + device_get_name(dev), device_get_unit(dev), + hv_dev->channel); root_mount_rel(root_mount_token); return (0); Index: sys/dev/hyperv/vmbus/hv_ring_buffer.c =================================================================== --- sys/dev/hyperv/vmbus/hv_ring_buffer.c +++ sys/dev/hyperv/vmbus/hv_ring_buffer.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include "hv_vmbus_priv.h" @@ -37,6 +39,87 @@ #define HV_BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))? \ ((z) - ((w) - (r))):((r) - (w)) +SYSCTL_DECL(_hw_hyperv); + +static char rbi_stats[256]; + +static int +rbi_sysctl_stats(SYSCTL_HANDLER_ARGS) +{ + hv_vmbus_ring_buffer_info* rbi; + uint32_t read_index, write_index, interrupt_mask, sz; + uint32_t read_avail, write_avail; + + rbi = (hv_vmbus_ring_buffer_info*)arg1; + read_index = rbi->ring_buffer->read_index; + write_index = rbi->ring_buffer->write_index; + interrupt_mask = rbi->ring_buffer->interrupt_mask; + sz = rbi->ring_data_size; + write_avail = HV_BYTES_AVAIL_TO_WRITE(read_index, + write_index, sz); + read_avail = sz - write_avail; + snprintf(rbi_stats, sizeof(rbi_stats), + "r_idx: %d " + "w_idx: %d " + "int_mask: %d " + "r_avail: %d " + "w_avail: %d", + read_index, write_index, interrupt_mask, + read_avail, write_avail); + + return (sysctl_handle_string(oidp, rbi_stats, + sizeof(rbi_stats), req)); +} + +#define RBI_SYSCTL_STAT(rbi, ctx, desc, parent, oid) \ + SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, oid, \ + CTLTYPE_STRING|CTLFLAG_RD, rbi, 0, \ + rbi_sysctl_stats, "A", desc) +void +ring_buffer_stat(struct sysctl_ctx_list *ctx, + const char* devname, + int unit, hv_vmbus_channel* channel) +{ + struct sysctl_oid *dev_sysctl, *devunit_sysctl, *devch_sysctl; + struct sysctl_oid *devch_id_sysctl; + struct sysctl_oid *devch_id_out_sysctl, *devch_id_in_sysctl; + + char name[16]; + /* This creates hw.hyperv.DEVNAME tree */ + dev_sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw_hyperv), + OID_AUTO, devname, CTLFLAG_RD, 0, ""); + /* This creates hw.hyperv.DEVNAME.DEVUNIT tree */ + snprintf(name, sizeof(name), "%d", unit); + devunit_sysctl = SYSCTL_ADD_NODE(ctx, + SYSCTL_CHILDREN(dev_sysctl), + OID_AUTO, name, CTLFLAG_RD, 0, ""); + /* This creates hw.hyperv.DEVNAME.DEVUNIT.channel tree */ + devch_sysctl = SYSCTL_ADD_NODE(ctx, + SYSCTL_CHILDREN(devunit_sysctl), + OID_AUTO, "channel", CTLFLAG_RD, 0, ""); + /* This creates hw.hyperv.DEVNAME.DEVUNIT.channel.CHANID tree */ + snprintf(name, sizeof(name), "%d", channel->offer_msg.child_rel_id); + devch_id_sysctl = SYSCTL_ADD_NODE(ctx, + SYSCTL_CHILDREN(devch_sysctl), + OID_AUTO, name, CTLFLAG_RD, 0, ""); + + devch_id_out_sysctl = SYSCTL_ADD_NODE(ctx, + SYSCTL_CHILDREN(devch_id_sysctl), + OID_AUTO, "out", CTLFLAG_RD, 0, ""); + devch_id_in_sysctl = SYSCTL_ADD_NODE(ctx, + SYSCTL_CHILDREN(devch_id_sysctl), + OID_AUTO, "in", CTLFLAG_RD, 0, ""); + + RBI_SYSCTL_STAT(&(channel->outbound), ctx, + "outbound ring buffer stats", + SYSCTL_CHILDREN(devch_id_out_sysctl), + "ring_buffer_stats"); + RBI_SYSCTL_STAT(&(channel->inbound), ctx, + "inbound ring buffer stats", + SYSCTL_CHILDREN(devch_id_in_sysctl), + "ring_buffer_stats"); +} + /** * @brief Get number of bytes available to read and to write to * for the specified ring buffer Index: sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c =================================================================== --- sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c +++ sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c @@ -69,7 +69,10 @@ static hv_setup_args setup_args; /* only CPU 0 supported at this time */ static char *vmbus_ids[] = { "VMBUS", NULL }; - +/** + * sysctl root tree node for statistic information : hw.hyperv + */ +SYSCTL_NODE(_hw, OID_AUTO, hyperv, CTLFLAG_RD, NULL, "Hyper-V"); /** * @brief Software interrupt thread routine to handle channel messages from * the hypervisor. Index: sys/dev/hyperv/vmbus/hv_vmbus_priv.h =================================================================== --- sys/dev/hyperv/vmbus/hv_vmbus_priv.h +++ sys/dev/hyperv/vmbus/hv_vmbus_priv.h @@ -639,6 +639,11 @@ /* * Private, VM Bus functions */ +void ring_buffer_stat( + struct sysctl_ctx_list *ctx, + const char *devname, + int uint, + hv_vmbus_channel *channel); int hv_vmbus_ring_buffer_init( hv_vmbus_ring_buffer_info *ring_info,