iPXE
vmbus.c File Reference

Hyper-V virtual machine bus. More...

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
#include <ipxe/nap.h>
#include <ipxe/malloc.h>
#include <ipxe/iobuf.h>
#include <ipxe/bitops.h>
#include <ipxe/hyperv.h>
#include <ipxe/vmbus.h>

Go to the source code of this file.

Macros

#define VMBUS_GPADL_MAGIC   0x18ae0000
 VMBus initial GPADL ID.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static int vmbus_post_message (struct hv_hypervisor *hv, const struct vmbus_message_header *header, size_t len)
 Post message.
static int vmbus_post_empty_message (struct hv_hypervisor *hv, unsigned int type)
 Post empty message.
static int vmbus_wait_for_any_message (struct hv_hypervisor *hv)
 Wait for received message of any type.
static int vmbus_wait_for_message (struct hv_hypervisor *hv, unsigned int type)
 Wait for received message of a specified type, ignoring any others.
static int vmbus_initiate_contact (struct hv_hypervisor *hv, unsigned int raw)
 Initiate contact.
static int vmbus_unload (struct hv_hypervisor *hv)
 Terminate contact.
static int vmbus_negotiate_version (struct hv_hypervisor *hv)
 Negotiate protocol version.
int vmbus_establish_gpadl (struct vmbus_device *vmdev, void *data, size_t len)
 Establish GPA descriptor list.
int vmbus_gpadl_teardown (struct vmbus_device *vmdev, unsigned int gpadl)
 Tear down GPA descriptor list.
int vmbus_open (struct vmbus_device *vmdev, struct vmbus_channel_operations *op, size_t out_len, size_t in_len, size_t mtu)
 Open VMBus channel.
void vmbus_close (struct vmbus_device *vmdev)
 Close VMBus channel.
static void vmbus_signal_monitor (struct vmbus_device *vmdev)
 Signal channel via monitor page.
static void vmbus_signal_event (struct vmbus_device *vmdev)
 Signal channel via hypervisor event.
static size_t vmbus_produce (struct vmbus_device *vmdev, size_t prod, const void *data, size_t len)
 Fill outbound ring buffer.
static size_t vmbus_consume (struct vmbus_device *vmdev, size_t cons, void *data, size_t len)
 Consume inbound ring buffer.
static int vmbus_send (struct vmbus_device *vmdev, struct vmbus_packet_header *header, const void *data, size_t len)
 Send packet via ring buffer.
int vmbus_send_control (struct vmbus_device *vmdev, uint64_t xid, const void *data, size_t len)
 Send control packet via ring buffer.
int vmbus_send_data (struct vmbus_device *vmdev, uint64_t xid, const void *data, size_t len, struct io_buffer *iobuf)
 Send data packet via ring buffer.
int vmbus_send_completion (struct vmbus_device *vmdev, uint64_t xid, const void *data, size_t len)
 Send completion packet via ring buffer.
int vmbus_send_cancellation (struct vmbus_device *vmdev, uint64_t xid)
 Send cancellation packet via ring buffer.
static struct vmbus_xfer_pages * vmbus_xfer_pages (struct vmbus_device *vmdev, uint16_t pageset)
 Get transfer page set from pageset ID.
static int vmbus_xfer_page_iobufs (struct vmbus_device *vmdev, struct vmbus_packet_header *header, struct list_head *list)
 Construct I/O buffer list from transfer pages.
int vmbus_poll (struct vmbus_device *vmdev)
 Poll ring buffer.
void vmbus_dump_channel (struct vmbus_device *vmdev)
 Dump channel status (for debugging)
static struct vmbus_drivervmbus_find_driver (const union uuid *type)
 Find driver for VMBus device.
static int vmbus_probe_channels (struct hv_hypervisor *hv, struct device *parent)
 Probe channels.
static int vmbus_reset_channels (struct hv_hypervisor *hv, struct device *parent)
 Reset channels.
static void vmbus_remove_channels (struct hv_hypervisor *hv __unused, struct device *parent)
 Remove channels.
int vmbus_probe (struct hv_hypervisor *hv, struct device *parent)
 Probe Hyper-V virtual machine bus.
int vmbus_reset (struct hv_hypervisor *hv, struct device *parent)
 Reset Hyper-V virtual machine bus.
void vmbus_remove (struct hv_hypervisor *hv, struct device *parent)
 Remove Hyper-V virtual machine bus.

Variables

static unsigned int vmbus_gpadl = VMBUS_GPADL_MAGIC
 Current (i.e.
unsigned int vmbus_obsolete_gpadl
 Obsolete GPADL ID threshold.

Detailed Description

Hyper-V virtual machine bus.

Definition in file vmbus.c.

Macro Definition Documentation

◆ VMBUS_GPADL_MAGIC

#define VMBUS_GPADL_MAGIC   0x18ae0000

VMBus initial GPADL ID.

This is an opaque value with no meaning. The Linux kernel uses 0xe1e10.

Definition at line 51 of file vmbus.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ vmbus_post_message()

int vmbus_post_message ( struct hv_hypervisor * hv,
const struct vmbus_message_header * header,
size_t len )
static

Post message.

Parameters
hvHyper-V hypervisor
headerMessage header
lenLength of message (including header)
Return values
rcReturn status code

Definition at line 71 of file vmbus.c.

73 {
74 struct vmbus *vmbus = hv->vmbus;
75 int rc;
76
77 /* Post message */
79 header, len ) ) != 0 ) {
80 DBGC ( vmbus, "VMBUS %p could not post message: %s\n",
81 vmbus, strerror ( rc ) );
82 return rc;
83 }
84
85 return 0;
86}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
ring len
Length.
Definition dwmac.h:226
struct ena_llq_option header
Header locations.
Definition ena.h:5
#define DBGC(...)
Definition compiler.h:505
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
struct vmbus * vmbus
Virtual machine bus.
Definition hyperv.h:211
A posted message.
Definition hyperv.h:81
A virtual machine bus.
Definition vmbus.h:382
#define VMBUS_MESSAGE_ID
VMBus message connection ID.
Definition vmbus.h:20
#define VMBUS_MESSAGE_TYPE
VMBus message type.
Definition vmbus.h:26

References DBGC, header, len, rc, strerror(), hv_hypervisor::vmbus, VMBUS_MESSAGE_ID, and VMBUS_MESSAGE_TYPE.

Referenced by vmbus_close(), vmbus_establish_gpadl(), vmbus_gpadl_teardown(), vmbus_initiate_contact(), vmbus_open(), and vmbus_post_empty_message().

◆ vmbus_post_empty_message()

int vmbus_post_empty_message ( struct hv_hypervisor * hv,
unsigned int type )
static

Post empty message.

Parameters
hvHyper-V hypervisor
typeMessage type
Return values
rcReturn status code

Definition at line 95 of file vmbus.c.

96 {
97 struct vmbus_message_header header = { .type = cpu_to_le32 ( type ) };
98
99 return vmbus_post_message ( hv, &header, sizeof ( header ) );
100}
uint32_t type
Operating system type.
Definition ena.h:1
#define cpu_to_le32(value)
Definition byteswap.h:108
VMBus message header.
Definition vmbus.h:71
static int vmbus_post_message(struct hv_hypervisor *hv, const struct vmbus_message_header *header, size_t len)
Post message.
Definition vmbus.c:71

References cpu_to_le32, header, type, and vmbus_post_message().

Referenced by vmbus_probe_channels(), vmbus_reset_channels(), and vmbus_unload().

◆ vmbus_wait_for_any_message()

int vmbus_wait_for_any_message ( struct hv_hypervisor * hv)
static

Wait for received message of any type.

Parameters
hvHyper-V hypervisor
Return values
rcReturn status code

Definition at line 108 of file vmbus.c.

108 {
109 struct vmbus *vmbus = hv->vmbus;
110 int rc;
111
112 /* Wait for message */
113 if ( ( rc = hv_wait_for_message ( hv, VMBUS_MESSAGE_SINT ) ) != 0 ) {
114 DBGC ( vmbus, "VMBUS %p failed waiting for message: %s\n",
115 vmbus, strerror ( rc ) );
116 return rc;
117 }
118
119 /* Sanity check */
121 DBGC ( vmbus, "VMBUS %p invalid message type %d\n",
123 return -EINVAL;
124 }
125
126 return 0;
127}
#define EINVAL
Invalid argument.
Definition errno.h:429
int hv_wait_for_message(struct hv_hypervisor *hv, unsigned int sintx)
Wait for received message.
Definition hyperv.c:486
#define le32_to_cpu(value)
Definition byteswap.h:114
union hv_message_buffer * message
Message buffer.
Definition hyperv.h:209
uint32_t type
Type.
Definition hyperv.h:102
struct hv_message received
Received message.
Definition hyperv.h:197
#define VMBUS_MESSAGE_SINT
VMBus message synthetic interrupt.
Definition vmbus.h:29

References cpu_to_le32, DBGC, EINVAL, hv_wait_for_message(), le32_to_cpu, hv_hypervisor::message, rc, hv_message_buffer::received, strerror(), hv_message::type, hv_hypervisor::vmbus, VMBUS_MESSAGE_SINT, and VMBUS_MESSAGE_TYPE.

Referenced by vmbus_probe_channels(), vmbus_reset_channels(), and vmbus_wait_for_message().

◆ vmbus_wait_for_message()

int vmbus_wait_for_message ( struct hv_hypervisor * hv,
unsigned int type )
static

Wait for received message of a specified type, ignoring any others.

Parameters
hvHyper-V hypervisor
typeMessage type
Return values
rcReturn status code

Definition at line 136 of file vmbus.c.

137 {
138 struct vmbus *vmbus = hv->vmbus;
140 int rc;
141
142 /* Loop until specified message arrives, or until an error occurs */
143 while ( 1 ) {
144
145 /* Wait for message */
146 if ( ( rc = vmbus_wait_for_any_message ( hv ) ) != 0 )
147 return rc;
148
149 /* Check for requested message type */
150 if ( header->type == cpu_to_le32 ( type ) )
151 return 0;
152
153 /* Ignore any other messages (e.g. due to additional
154 * channels being offered at runtime).
155 */
156 DBGC ( vmbus, "VMBUS %p ignoring message type %d (expecting "
157 "%d)\n", vmbus, le32_to_cpu ( header->type ), type );
158 }
159}
const union vmbus_message * message
Received message buffer.
Definition vmbus.h:390
struct vmbus_message_header header
Common message header.
Definition vmbus.h:241
static int vmbus_wait_for_any_message(struct hv_hypervisor *hv)
Wait for received message of any type.
Definition vmbus.c:108

References cpu_to_le32, DBGC, header, vmbus_message::header, le32_to_cpu, vmbus::message, rc, type, hv_hypervisor::vmbus, and vmbus_wait_for_any_message().

Referenced by vmbus_establish_gpadl(), vmbus_gpadl_teardown(), vmbus_initiate_contact(), vmbus_open(), and vmbus_unload().

◆ vmbus_initiate_contact()

int vmbus_initiate_contact ( struct hv_hypervisor * hv,
unsigned int raw )
static

Initiate contact.

Parameters
hvHyper-V hypervisor
rawVMBus protocol (raw) version
Return values
rcReturn status code

Definition at line 168 of file vmbus.c.

169 {
170 struct vmbus *vmbus = hv->vmbus;
172 struct vmbus_initiate_contact initiate;
173 int rc;
174
175 /* Construct message */
176 memset ( &initiate, 0, sizeof ( initiate ) );
177 initiate.header.type = cpu_to_le32 ( VMBUS_INITIATE_CONTACT );
178 initiate.version.raw = cpu_to_le32 ( raw );
179 initiate.intr = virt_to_phys ( vmbus->intr );
180 initiate.monitor_in = virt_to_phys ( vmbus->monitor_in );
181 initiate.monitor_out = virt_to_phys ( vmbus->monitor_out );
182
183 /* Post message */
184 if ( ( rc = vmbus_post_message ( hv, &initiate.header,
185 sizeof ( initiate ) ) ) != 0 )
186 return rc;
187
188 /* Wait for response */
189 if ( ( rc = vmbus_wait_for_message ( hv, VMBUS_VERSION_RESPONSE ) ) !=0)
190 return rc;
191
192 /* Check response */
193 if ( ! version->supported ) {
194 DBGC ( vmbus, "VMBUS %p requested version not supported\n",
195 vmbus );
196 return -ENOTSUP;
197 }
198
199 DBGC ( vmbus, "VMBUS %p initiated contact using version %d.%d\n",
200 vmbus, le16_to_cpu ( initiate.version.major ),
201 le16_to_cpu ( initiate.version.minor ) );
202 return 0;
203}
__be32 raw[7]
Definition CIB_PRM.h:0
u32 version
Driver version.
Definition ath9k_hw.c:1985
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define le16_to_cpu(value)
Definition byteswap.h:113
void * memset(void *dest, int character, size_t len) __nonnull
VMBus "initiate contact" message.
Definition vmbus.h:211
VMBus "version response" message.
Definition vmbus.h:227
struct vmbus_interrupt * intr
Interrupt page.
Definition vmbus.h:384
struct hv_monitor * monitor_out
Outbound notifications.
Definition vmbus.h:388
struct hv_monitor * monitor_in
Inbound notifications.
Definition vmbus.h:386
struct vmbus_version_response version
"Version response" message
Definition vmbus.h:261
static int vmbus_wait_for_message(struct hv_hypervisor *hv, unsigned int type)
Wait for received message of a specified type, ignoring any others.
Definition vmbus.c:136
@ VMBUS_INITIATE_CONTACT
Definition vmbus.h:90
@ VMBUS_VERSION_RESPONSE
Definition vmbus.h:91

References cpu_to_le32, DBGC, ENOTSUP, vmbus_initiate_contact::header, vmbus::intr, vmbus_initiate_contact::intr, le16_to_cpu, vmbus_version::major, memset(), vmbus::message, vmbus_version::minor, vmbus::monitor_in, vmbus_initiate_contact::monitor_in, vmbus::monitor_out, vmbus_initiate_contact::monitor_out, raw, vmbus_version::raw, rc, vmbus_message_header::type, version, vmbus_initiate_contact::version, vmbus_message::version, hv_hypervisor::vmbus, VMBUS_INITIATE_CONTACT, vmbus_post_message(), VMBUS_VERSION_RESPONSE, and vmbus_wait_for_message().

◆ vmbus_unload()

int vmbus_unload ( struct hv_hypervisor * hv)
static

Terminate contact.

Parameters
hvHyper-V hypervisor
Return values
rcReturn status code

Definition at line 211 of file vmbus.c.

211 {
212 int rc;
213
214 /* Post message */
215 if ( ( rc = vmbus_post_empty_message ( hv, VMBUS_UNLOAD ) ) != 0 )
216 return rc;
217
218 /* Wait for response */
219 if ( ( rc = vmbus_wait_for_message ( hv, VMBUS_UNLOAD_RESPONSE ) ) != 0)
220 return rc;
221
222 return 0;
223}
static int vmbus_post_empty_message(struct hv_hypervisor *hv, unsigned int type)
Post empty message.
Definition vmbus.c:95
@ VMBUS_UNLOAD_RESPONSE
Definition vmbus.h:93
@ VMBUS_UNLOAD
Definition vmbus.h:92

References rc, vmbus_post_empty_message(), VMBUS_UNLOAD, VMBUS_UNLOAD_RESPONSE, and vmbus_wait_for_message().

Referenced by vmbus_negotiate_version(), vmbus_probe(), and vmbus_remove().

◆ vmbus_negotiate_version()

int vmbus_negotiate_version ( struct hv_hypervisor * hv)
static

Negotiate protocol version.

Parameters
hvHyper-V hypervisor
Return values
rcReturn status code

Definition at line 231 of file vmbus.c.

231 {
232 int rc;
233
234 /* We require the ability to disconnect from and reconnect to
235 * VMBus; if we don't have this then there is no (viable) way
236 * for a loaded operating system to continue to use any VMBus
237 * devices. (There is also a small but non-zero risk that the
238 * host will continue to write to our interrupt and monitor
239 * pages, since the VMBUS_UNLOAD message in earlier versions
240 * is essentially a no-op.)
241 *
242 * This requires us to ensure that the host supports protocol
243 * version 3.0 (VMBUS_VERSION_WIN8_1). However, we can't
244 * actually _use_ protocol version 3.0, since doing so causes
245 * an iSCSI-booted Windows Server 2012 R2 VM to crash due to a
246 * NULL pointer dereference in vmbus.sys.
247 *
248 * To work around this problem, we first ensure that we can
249 * connect using protocol v3.0, then disconnect and reconnect
250 * using the oldest known protocol.
251 */
252
253 /* Initiate contact to check for required protocol support */
254 if ( ( rc = vmbus_initiate_contact ( hv, VMBUS_VERSION_WIN8_1 ) ) != 0 )
255 return rc;
256
257 /* Terminate contact */
258 if ( ( rc = vmbus_unload ( hv ) ) != 0 )
259 return rc;
260
261 /* Reinitiate contact using the oldest known protocol version */
262 if ( ( rc = vmbus_initiate_contact ( hv, VMBUS_VERSION_WS2008 ) ) != 0 )
263 return rc;
264
265 return 0;
266}
static int vmbus_unload(struct hv_hypervisor *hv)
Terminate contact.
Definition vmbus.c:211
@ VMBUS_VERSION_WIN8_1
Windows 8.1.
Definition vmbus.h:53
@ VMBUS_VERSION_WS2008
Windows Server 2008.
Definition vmbus.h:47

References rc, vmbus_unload(), VMBUS_VERSION_WIN8_1, and VMBUS_VERSION_WS2008.

Referenced by vmbus_probe(), and vmbus_reset().

◆ vmbus_establish_gpadl()

int vmbus_establish_gpadl ( struct vmbus_device * vmdev,
void * data,
size_t len )

Establish GPA descriptor list.

Parameters
vmdevVMBus device
dataData buffer
lenLength of data buffer
Return values
gpadlGPADL ID, or negative error

Definition at line 276 of file vmbus.c.

277 {
278 struct hv_hypervisor *hv = vmdev->hv;
279 struct vmbus *vmbus = hv->vmbus;
280 physaddr_t addr = virt_to_phys ( data );
281 unsigned int pfn_count = hv_pfn_count ( addr, len );
282 struct {
283 struct vmbus_gpadl_header gpadlhdr;
284 struct vmbus_gpa_range range;
285 uint64_t pfn[pfn_count];
286 } __attribute__ (( packed )) gpadlhdr;
287 const struct vmbus_gpadl_created *created = &vmbus->message->created;
288 unsigned int gpadl;
289 unsigned int i;
290 int rc;
291
292 /* Allocate GPADL ID */
293 gpadl = ++vmbus_gpadl;
294
295 /* Construct message */
296 memset ( &gpadlhdr, 0, sizeof ( gpadlhdr ) );
297 gpadlhdr.gpadlhdr.header.type = cpu_to_le32 ( VMBUS_GPADL_HEADER );
298 gpadlhdr.gpadlhdr.channel = cpu_to_le32 ( vmdev->channel );
299 gpadlhdr.gpadlhdr.gpadl = cpu_to_le32 ( gpadl );
300 gpadlhdr.gpadlhdr.range_len =
301 cpu_to_le16 ( ( sizeof ( gpadlhdr.range ) +
302 sizeof ( gpadlhdr.pfn ) ) );
303 gpadlhdr.gpadlhdr.range_count = cpu_to_le16 ( 1 );
304 gpadlhdr.range.len = cpu_to_le32 ( len );
305 gpadlhdr.range.offset = cpu_to_le32 ( addr & ( PAGE_SIZE - 1 ) );
306 for ( i = 0 ; i < pfn_count ; i++ )
307 gpadlhdr.pfn[i] = ( ( addr / PAGE_SIZE ) + i );
308
309 /* Post message */
310 if ( ( rc = vmbus_post_message ( hv, &gpadlhdr.gpadlhdr.header,
311 sizeof ( gpadlhdr ) ) ) != 0 )
312 return rc;
313
314 /* Wait for response */
315 if ( ( rc = vmbus_wait_for_message ( hv, VMBUS_GPADL_CREATED ) ) != 0 )
316 return rc;
317
318 /* Check response */
319 if ( created->channel != cpu_to_le32 ( vmdev->channel ) ) {
320 DBGC ( vmdev, "VMBUS %s unexpected GPADL channel %d\n",
321 vmdev->dev.name, le32_to_cpu ( created->channel ) );
322 return -EPROTO;
323 }
324 if ( created->gpadl != cpu_to_le32 ( gpadl ) ) {
325 DBGC ( vmdev, "VMBUS %s unexpected GPADL ID %#08x\n",
326 vmdev->dev.name, le32_to_cpu ( created->gpadl ) );
327 return -EPROTO;
328 }
329 if ( created->status != 0 ) {
330 DBGC ( vmdev, "VMBUS %s GPADL creation failed: %#08x\n",
331 vmdev->dev.name, le32_to_cpu ( created->status ) );
332 return -EPROTO;
333 }
334
335 DBGC ( vmdev, "VMBUS %s GPADL %#08x is [%08lx,%08lx)\n",
336 vmdev->dev.name, gpadl, addr, ( addr + len ) );
337 return gpadl;
338}
unsigned long physaddr_t
Definition stdint.h:20
unsigned long long uint64_t
Definition stdint.h:13
uint32_t addr
Buffer address.
Definition dwmac.h:9
uint8_t data[48]
Additional event data.
Definition ena.h:11
#define EPROTO
Protocol error.
Definition errno.h:625
#define cpu_to_le16(value)
Definition byteswap.h:107
#define __attribute__(x)
Definition compiler.h:10
static unsigned int hv_pfn_count(physaddr_t data, size_t len)
Calculate the number of pages covering an address range.
Definition hyperv.h:223
#define PAGE_SIZE
Page size.
Definition io.h:28
uint32_t gpadl
GPADL ID.
Definition netvsc.h:3
struct pci_range range
PCI bus:dev.fn address range.
Definition pcicloud.c:40
char name[40]
Name.
Definition device.h:79
A Hyper-V hypervisor.
Definition hyperv.h:203
struct hv_hypervisor * hv
Hyper-V hypervisor.
Definition vmbus.h:479
unsigned int channel
Channel ID.
Definition vmbus.h:484
struct device dev
Generic iPXE device.
Definition vmbus.h:477
VMBus "GPADL created" message.
Definition vmbus.h:181
uint32_t channel
Channel ID.
Definition vmbus.h:185
uint32_t gpadl
GPADL ID.
Definition vmbus.h:187
uint32_t status
Creation status.
Definition vmbus.h:189
struct vmbus_gpadl_created created
"GPADL created" message
Definition vmbus.h:253
static unsigned int vmbus_gpadl
Current (i.e.
Definition vmbus.c:54
@ VMBUS_GPADL_CREATED
Definition vmbus.h:87
@ VMBUS_GPADL_HEADER
Definition vmbus.h:86

References __attribute__, addr, vmbus_device::channel, vmbus_gpadl_created::channel, cpu_to_le16, cpu_to_le32, vmbus_message::created, data, DBGC, vmbus_device::dev, EPROTO, gpadl, vmbus_gpadl_created::gpadl, vmbus_device::hv, hv_pfn_count(), le32_to_cpu, len, memset(), vmbus::message, device::name, PAGE_SIZE, range, rc, vmbus_gpadl_created::status, hv_hypervisor::vmbus, vmbus_gpadl, VMBUS_GPADL_CREATED, VMBUS_GPADL_HEADER, vmbus_post_message(), and vmbus_wait_for_message().

Referenced by netvsc_create_buffer(), and vmbus_open().

◆ vmbus_gpadl_teardown()

int vmbus_gpadl_teardown ( struct vmbus_device * vmdev,
unsigned int gpadl )

Tear down GPA descriptor list.

Parameters
vmdevVMBus device
gpadlGPADL ID
Return values
rcReturn status code

Definition at line 347 of file vmbus.c.

347 {
348 struct hv_hypervisor *hv = vmdev->hv;
349 struct vmbus *vmbus = hv->vmbus;
350 struct vmbus_gpadl_teardown teardown;
351 const struct vmbus_gpadl_torndown *torndown = &vmbus->message->torndown;
352 int rc;
353
354 /* If GPADL is obsolete (i.e. was created before the most
355 * recent Hyper-V reset), then we will never receive a
356 * response to the teardown message. Since the GPADL is
357 * already destroyed as far as the hypervisor is concerned, no
358 * further action is required.
359 */
361 return 0;
362
363 /* Construct message */
364 memset ( &teardown, 0, sizeof ( teardown ) );
365 teardown.header.type = cpu_to_le32 ( VMBUS_GPADL_TEARDOWN );
366 teardown.channel = cpu_to_le32 ( vmdev->channel );
367 teardown.gpadl = cpu_to_le32 ( gpadl );
368
369 /* Post message */
370 if ( ( rc = vmbus_post_message ( hv, &teardown.header,
371 sizeof ( teardown ) ) ) != 0 )
372 return rc;
373
374 /* Wait for response */
375 if ( ( rc = vmbus_wait_for_message ( hv, VMBUS_GPADL_TORNDOWN ) ) != 0 )
376 return rc;
377
378 /* Check response */
379 if ( torndown->gpadl != cpu_to_le32 ( gpadl ) ) {
380 DBGC ( vmdev, "VMBUS %s unexpected GPADL ID %#08x\n",
381 vmdev->dev.name, le32_to_cpu ( torndown->gpadl ) );
382 return -EPROTO;
383 }
384
385 return 0;
386}
VMBus "GPADL teardown" message.
Definition vmbus.h:193
VMBus "GPADL torndown" message.
Definition vmbus.h:203
uint32_t gpadl
GPADL ID.
Definition vmbus.h:207
struct vmbus_gpadl_torndown torndown
"GPADL torndown" message
Definition vmbus.h:257
@ VMBUS_GPADL_TORNDOWN
Definition vmbus.h:89
@ VMBUS_GPADL_TEARDOWN
Definition vmbus.h:88
static int vmbus_gpadl_is_obsolete(unsigned int gpadl)
Check if GPADL is obsolete.
Definition vmbus.h:634

References vmbus_device::channel, vmbus_gpadl_teardown::channel, cpu_to_le32, DBGC, vmbus_device::dev, EPROTO, gpadl, vmbus_gpadl_teardown::gpadl, vmbus_gpadl_torndown::gpadl, vmbus_gpadl_teardown::header, vmbus_device::hv, le32_to_cpu, memset(), vmbus::message, device::name, rc, vmbus_message::torndown, vmbus_message_header::type, hv_hypervisor::vmbus, vmbus_gpadl_is_obsolete(), VMBUS_GPADL_TEARDOWN, VMBUS_GPADL_TORNDOWN, vmbus_post_message(), and vmbus_wait_for_message().

Referenced by netvsc_create_buffer(), and vmbus_open().

◆ vmbus_open()

int vmbus_open ( struct vmbus_device * vmdev,
struct vmbus_channel_operations * op,
size_t out_len,
size_t in_len,
size_t mtu )

Open VMBus channel.

Parameters
vmdevVMBus device
opChannel operations
out_lenOutbound ring buffer length
in_lenInbound ring buffer length
mtuMaximum expected data packet length (including headers)
Return values
rcReturn status code

Both outbound and inbound ring buffer lengths must be a power of two and a multiple of PAGE_SIZE. The requirement to be a power of two is a policy decision taken to simplify the ring buffer indexing logic.

Definition at line 403 of file vmbus.c.

405 {
406 struct hv_hypervisor *hv = vmdev->hv;
407 struct vmbus *vmbus = hv->vmbus;
409 const struct vmbus_open_channel_result *opened =
411 size_t len;
412 void *ring;
413 void *packet;
414 int gpadl;
415 uint32_t open_id;
416 int rc;
417
418 /* Sanity checks */
419 assert ( ( out_len % PAGE_SIZE ) == 0 );
420 assert ( ( out_len & ( out_len - 1 ) ) == 0 );
421 assert ( ( in_len % PAGE_SIZE ) == 0 );
422 assert ( ( in_len & ( in_len - 1 ) ) == 0 );
423 assert ( mtu >= ( sizeof ( struct vmbus_packet_header ) +
424 sizeof ( struct vmbus_packet_footer ) ) );
425
426 /* Allocate packet buffer */
427 packet = malloc ( mtu );
428 if ( ! packet ) {
429 rc = -ENOMEM;
430 goto err_alloc_packet;
431 }
432
433 /* Allocate ring buffer */
434 len = ( sizeof ( *vmdev->out ) + out_len +
435 sizeof ( *vmdev->in ) + in_len );
436 assert ( ( len % PAGE_SIZE ) == 0 );
437 ring = malloc_phys ( len, PAGE_SIZE );
438 if ( ! ring ) {
439 rc = -ENOMEM;
440 goto err_alloc_ring;
441 }
442 memset ( ring, 0, len );
443
444 /* Establish GPADL for ring buffer */
445 gpadl = vmbus_establish_gpadl ( vmdev, ring, len );
446 if ( gpadl < 0 ) {
447 rc = gpadl;
448 goto err_establish;
449 }
450
451 /* Construct message */
452 memset ( &open, 0, sizeof ( open ) );
453 open.header.type = cpu_to_le32 ( VMBUS_OPEN_CHANNEL );
454 open.channel = cpu_to_le32 ( vmdev->channel );
455 open_id = random();
456 open.id = open_id; /* Opaque random value: endianness irrelevant */
457 open.gpadl = cpu_to_le32 ( gpadl );
458 open.out_pages = ( ( sizeof ( *vmdev->out ) / PAGE_SIZE ) +
459 ( out_len / PAGE_SIZE ) );
460
461 /* Post message */
462 if ( ( rc = vmbus_post_message ( hv, &open.header,
463 sizeof ( open ) ) ) != 0 )
464 goto err_post_message;
465
466 /* Wait for response */
467 if ( ( rc = vmbus_wait_for_message ( hv,
469 goto err_wait_for_message;
470
471 /* Check response */
472 if ( opened->channel != cpu_to_le32 ( vmdev->channel ) ) {
473 DBGC ( vmdev, "VMBUS %s unexpected opened channel %#08x\n",
474 vmdev->dev.name, le32_to_cpu ( opened->channel ) );
475 rc = -EPROTO;
476 goto err_check_response;
477 }
478 if ( opened->id != open_id /* Non-endian */ ) {
479 DBGC ( vmdev, "VMBUS %s unexpected open ID %#08x\n",
480 vmdev->dev.name, le32_to_cpu ( opened->id ) );
481 rc = -EPROTO;
482 goto err_check_response;
483 }
484 if ( opened->status != 0 ) {
485 DBGC ( vmdev, "VMBUS %s open failed: %#08x\n",
486 vmdev->dev.name, le32_to_cpu ( opened->status ) );
487 rc = -EPROTO;
488 goto err_check_response;
489 }
490
491 /* Store channel parameters */
492 vmdev->out_len = out_len;
493 vmdev->in_len = in_len;
494 vmdev->out = ring;
495 vmdev->in = ( ring + sizeof ( *vmdev->out ) + out_len );
496 vmdev->gpadl = gpadl;
497 vmdev->op = op;
498 vmdev->mtu = mtu;
499 vmdev->packet = packet;
500
501 DBGC ( vmdev, "VMBUS %s channel GPADL %#08x ring "
502 "[%#08lx,%#08lx,%#08lx)\n", vmdev->dev.name, vmdev->gpadl,
503 virt_to_phys ( vmdev->out ), virt_to_phys ( vmdev->in ),
504 ( virt_to_phys ( vmdev->out ) + len ) );
505 return 0;
506
507 err_check_response:
508 err_wait_for_message:
509 err_post_message:
510 vmbus_gpadl_teardown ( vmdev, vmdev->gpadl );
511 err_establish:
512 free_phys ( ring, len );
513 err_alloc_ring:
514 free ( packet );
515 err_alloc_packet:
516 return rc;
517}
unsigned int uint32_t
Definition stdint.h:12
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
uint32_t mtu
Maximum MTU.
Definition ena.h:17
#define ENOMEM
Not enough space.
Definition errno.h:535
void * malloc_phys(size_t size, size_t phys_align)
Allocate memory with specified physical alignment.
Definition malloc.c:707
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
void free_phys(void *ptr, size_t size)
Free memory allocated with malloc_phys()
Definition malloc.c:723
static uint16_t struct vmbus_xfer_pages_operations * op
Definition netvsc.h:327
int open(const char *uri_string)
Open file.
Definition posix_io.c:176
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition random.c:32
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
void * packet
Packet buffer.
Definition vmbus.h:509
struct vmbus_ring * in
Inbound ring buffer.
Definition vmbus.h:500
unsigned int gpadl
Ring buffer GPADL ID.
Definition vmbus.h:502
struct vmbus_channel_operations * op
Channel operations.
Definition vmbus.h:505
uint32_t out_len
Outbound ring buffer length.
Definition vmbus.h:494
struct vmbus_ring * out
Outbound ring buffer.
Definition vmbus.h:498
size_t mtu
Maximum expected data packet length.
Definition vmbus.h:507
uint32_t in_len
Inbound ring buffer length.
Definition vmbus.h:496
VMBus "open channel result" message.
Definition vmbus.h:145
uint32_t status
Status.
Definition vmbus.h:153
uint32_t channel
Channel ID.
Definition vmbus.h:149
uint32_t id
Open ID.
Definition vmbus.h:151
VMBus "open channel" message.
Definition vmbus.h:127
VMBus packet header.
Definition vmbus.h:265
struct vmbus_open_channel_result opened
"Open channel result" message
Definition vmbus.h:247
int vmbus_establish_gpadl(struct vmbus_device *vmdev, void *data, size_t len)
Establish GPA descriptor list.
Definition vmbus.c:276
int vmbus_gpadl_teardown(struct vmbus_device *vmdev, unsigned int gpadl)
Tear down GPA descriptor list.
Definition vmbus.c:347
@ VMBUS_OPEN_CHANNEL_RESULT
Definition vmbus.h:84
@ VMBUS_OPEN_CHANNEL
Definition vmbus.h:83

References assert, vmbus_device::channel, vmbus_open_channel_result::channel, cpu_to_le32, DBGC, vmbus_device::dev, ENOMEM, EPROTO, free, free_phys(), gpadl, vmbus_device::gpadl, vmbus_device::hv, vmbus_open_channel_result::id, vmbus_device::in, vmbus_device::in_len, le32_to_cpu, len, malloc(), malloc_phys(), memset(), vmbus::message, mtu, vmbus_device::mtu, device::name, op, vmbus_device::op, open(), vmbus_message::opened, vmbus_device::out, vmbus_device::out_len, vmbus_device::packet, PAGE_SIZE, random(), rc, vmbus_open_channel_result::status, hv_hypervisor::vmbus, vmbus_establish_gpadl(), vmbus_gpadl_teardown(), VMBUS_OPEN_CHANNEL, VMBUS_OPEN_CHANNEL_RESULT, vmbus_post_message(), and vmbus_wait_for_message().

Referenced by netvsc_open().

◆ vmbus_close()

void vmbus_close ( struct vmbus_device * vmdev)

Close VMBus channel.

Parameters
vmdevVMBus device

Definition at line 524 of file vmbus.c.

524 {
525 struct hv_hypervisor *hv = vmdev->hv;
527 size_t len;
528 int rc;
529
530 /* Construct message */
531 memset ( &close, 0, sizeof ( close ) );
532 close.header.type = cpu_to_le32 ( VMBUS_CLOSE_CHANNEL );
533 close.channel = cpu_to_le32 ( vmdev->channel );
534
535 /* Post message */
536 if ( ( rc = vmbus_post_message ( hv, &close.header,
537 sizeof ( close ) ) ) != 0 ) {
538 DBGC ( vmdev, "VMBUS %s failed to close: %s\n",
539 vmdev->dev.name, strerror ( rc ) );
540 /* Continue to attempt to tear down GPADL, so that our
541 * memory is no longer accessible by the remote VM.
542 */
543 }
544
545 /* Tear down GPADL */
546 if ( ( rc = vmbus_gpadl_teardown ( vmdev, vmdev->gpadl ) ) != 0 ) {
547 DBGC ( vmdev, "VMBUS %s failed to tear down channel GPADL: "
548 "%s\n", vmdev->dev.name, strerror ( rc ) );
549 /* We can't prevent the remote VM from continuing to
550 * access this memory, so leak it.
551 */
552 return;
553 }
554
555 /* Free ring buffer */
556 len = ( sizeof ( *vmdev->out ) + vmdev->out_len +
557 sizeof ( *vmdev->in ) + vmdev->in_len );
558 free_phys ( vmdev->out, len );
559 vmdev->out = NULL;
560 vmdev->in = NULL;
561
562 /* Free packet buffer */
563 free ( vmdev->packet );
564 vmdev->packet = NULL;
565
566 DBGC ( vmdev, "VMBUS %s closed\n", vmdev->dev.name );
567}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
VMBus "close channel" message.
Definition vmbus.h:157
@ VMBUS_CLOSE_CHANNEL
Definition vmbus.h:85
static struct evtchn_close * close
Definition xenevent.h:24

References vmbus_device::channel, close, cpu_to_le32, DBGC, vmbus_device::dev, free, free_phys(), vmbus_device::gpadl, vmbus_device::hv, vmbus_device::in, vmbus_device::in_len, len, memset(), device::name, NULL, vmbus_device::out, vmbus_device::out_len, vmbus_device::packet, rc, strerror(), VMBUS_CLOSE_CHANNEL, and vmbus_post_message().

Referenced by netvsc_close(), and netvsc_open().

◆ vmbus_signal_monitor()

void vmbus_signal_monitor ( struct vmbus_device * vmdev)
static

Signal channel via monitor page.

Parameters
vmdevVMBus device

Definition at line 574 of file vmbus.c.

574 {
575 struct hv_hypervisor *hv = vmdev->hv;
576 struct vmbus *vmbus = hv->vmbus;
578 unsigned int group;
579 unsigned int bit;
580
581 /* Set bit in monitor trigger group */
582 group = ( vmdev->monitor / ( 8 * sizeof ( trigger->pending ) ));
583 bit = ( vmdev->monitor % ( 8 * sizeof ( trigger->pending ) ) );
585 set_bit ( bit, trigger );
586}
uint16_t group
Type of event.
Definition ena.h:1
static unsigned int unsigned int bit
Definition bigint.h:392
struct hv_monitor_trigger trigger[4]
Trigger groups.
Definition hyperv.h:5
A monitor trigger group.
Definition hyperv.h:139
struct hv_monitor_trigger trigger[4]
Trigger groups.
Definition hyperv.h:171
unsigned int monitor
Monitor ID.
Definition vmbus.h:486
#define set_bit(bit, loc)
Definition vxge_main.h:166

References bit, group, vmbus_device::hv, vmbus_device::monitor, vmbus::monitor_out, set_bit, hv_monitor::trigger, trigger, and hv_hypervisor::vmbus.

Referenced by vmbus_probe_channels().

◆ vmbus_signal_event()

void vmbus_signal_event ( struct vmbus_device * vmdev)
static

Signal channel via hypervisor event.

Parameters
vmdevVMBus device

Definition at line 593 of file vmbus.c.

593 {
594 struct hv_hypervisor *hv = vmdev->hv;
595 int rc;
596
597 /* Signal hypervisor event */
598 if ( ( rc = hv_signal_event ( hv, VMBUS_EVENT_ID, 0 ) ) != 0 ) {
599 DBGC ( vmdev, "VMBUS %s could not signal event: %s\n",
600 vmdev->dev.name, strerror ( rc ) );
601 return;
602 }
603}
A signalled event.
Definition hyperv.h:119
#define VMBUS_EVENT_ID
VMBus event connection ID.
Definition vmbus.h:23

References DBGC, vmbus_device::dev, vmbus_device::hv, device::name, rc, strerror(), and VMBUS_EVENT_ID.

Referenced by vmbus_probe_channels().

◆ vmbus_produce()

size_t vmbus_produce ( struct vmbus_device * vmdev,
size_t prod,
const void * data,
size_t len )
static

Fill outbound ring buffer.

Parameters
vmdevVMBus device
prodProducer index
dataData
lenLength
Return values
prodNew producer index

The caller must ensure that there is sufficient space in the ring buffer.

Definition at line 617 of file vmbus.c.

618 {
619 size_t first;
620 size_t second;
621
622 /* Determine fragment lengths */
623 first = ( vmdev->out_len - prod );
624 if ( first > len )
625 first = len;
626 second = ( len - first );
627
628 /* Copy fragment(s) */
629 memcpy ( &vmdev->out->data[prod], data, first );
630 if ( second )
631 memcpy ( &vmdev->out->data[0], ( data + first ), second );
632
633 return ( ( prod + len ) & ( vmdev->out_len - 1 ) );
634}
void * memcpy(void *dest, const void *src, size_t len) __nonnull
uint32_t first
First block in range.
Definition pccrr.h:1
uint8_t data[0]
Ring buffer contents.
Definition vmbus.h:370

References data, vmbus_ring::data, first, len, memcpy(), vmbus_device::out, and vmbus_device::out_len.

Referenced by vmbus_send().

◆ vmbus_consume()

size_t vmbus_consume ( struct vmbus_device * vmdev,
size_t cons,
void * data,
size_t len )
static

Consume inbound ring buffer.

Parameters
vmdevVMBus device
consConsumer index
dataData buffer, or NULL
lenLength to consume
Return values
consNew consumer index

Definition at line 645 of file vmbus.c.

646 {
647 size_t first;
648 size_t second;
649
650 /* Determine fragment lengths */
651 first = ( vmdev->in_len - cons );
652 if ( first > len )
653 first = len;
654 second = ( len - first );
655
656 /* Copy fragment(s) */
657 memcpy ( data, &vmdev->in->data[cons], first );
658 if ( second )
659 memcpy ( ( data + first ), &vmdev->in->data[0], second );
660
661 return ( ( cons + len ) & ( vmdev->in_len - 1 ) );
662}
uint16_t cons
Consumer index.
Definition ena.h:11

References cons, data, vmbus_ring::data, first, vmbus_device::in, vmbus_device::in_len, len, and memcpy().

Referenced by vmbus_poll().

◆ vmbus_send()

int vmbus_send ( struct vmbus_device * vmdev,
struct vmbus_packet_header * header,
const void * data,
size_t len )
static

Send packet via ring buffer.

Parameters
vmdevVMBus device
headerPacket header
dataData
lenLength of data
Return values
rcReturn status code

Send a packet via the outbound ring buffer. All fields in the packet header must be filled in, with the exception of the total packet length.

Definition at line 677 of file vmbus.c.

679 {
680 struct hv_hypervisor *hv = vmdev->hv;
681 struct vmbus *vmbus = hv->vmbus;
682 static uint8_t padding[ 8 - 1 ];
683 struct vmbus_packet_footer footer;
684 size_t header_len;
685 size_t pad_len;
686 size_t footer_len;
687 size_t ring_len;
688 size_t cons;
689 size_t prod;
690 size_t old_prod;
691 size_t fill;
692
693 /* Sanity check */
694 assert ( vmdev->out != NULL );
695
696 /* Calculate lengths */
697 header_len = ( le16_to_cpu ( header->hdr_qlen ) * 8 );
698 pad_len = ( ( -len ) & ( 8 - 1 ) );
699 footer_len = sizeof ( footer );
700 ring_len = ( header_len + len + pad_len + footer_len );
701
702 /* Check that we have enough room in the outbound ring buffer */
703 cons = le32_to_cpu ( vmdev->out->cons );
704 prod = le32_to_cpu ( vmdev->out->prod );
705 old_prod = prod;
706 fill = ( ( prod - cons ) & ( vmdev->out_len - 1 ) );
707 if ( ( fill + ring_len ) >= vmdev->out_len ) {
708 DBGC ( vmdev, "VMBUS %s ring buffer full\n", vmdev->dev.name );
709 return -ENOBUFS;
710 }
711
712 /* Complete header */
713 header->qlen = cpu_to_le16 ( ( ring_len - footer_len ) / 8 );
714
715 /* Construct footer */
716 footer.reserved = 0;
717 footer.prod = vmdev->out->prod;
718
719 /* Copy packet to buffer */
720 DBGC2 ( vmdev, "VMBUS %s sending:\n", vmdev->dev.name );
721 DBGC2_HDA ( vmdev, prod, header, header_len );
722 prod = vmbus_produce ( vmdev, prod, header, header_len );
723 DBGC2_HDA ( vmdev, prod, data, len );
724 prod = vmbus_produce ( vmdev, prod, data, len );
725 prod = vmbus_produce ( vmdev, prod, padding, pad_len );
726 DBGC2_HDA ( vmdev, prod, &footer, sizeof ( footer ) );
727 prod = vmbus_produce ( vmdev, prod, &footer, sizeof ( footer ) );
728 assert ( ( ( prod - old_prod ) & ( vmdev->out_len - 1 ) ) == ring_len );
729
730 /* Update producer index */
731 wmb();
732 vmdev->out->prod = cpu_to_le32 ( prod );
733
734 /* Return if we do not need to signal the host. This follows
735 * the logic of hv_need_to_signal() in the Linux driver.
736 */
737 mb();
738 if ( vmdev->out->intr_mask )
739 return 0;
740 rmb();
741 cons = le32_to_cpu ( vmdev->out->cons );
742 if ( cons != old_prod )
743 return 0;
744
745 /* Set channel bit in interrupt page */
746 set_bit ( vmdev->channel, vmbus->intr->out );
747
748 /* Signal the host */
749 vmdev->signal ( vmdev );
750
751 return 0;
752}
unsigned char uint8_t
Definition stdint.h:10
long pad_len
Definition bigint.h:31
static int fill
Definition string.h:209
#define DBGC2(...)
Definition compiler.h:522
#define DBGC2_HDA(...)
Definition compiler.h:523
#define ENOBUFS
No buffer space available.
Definition errno.h:499
#define rmb()
Definition io.h:545
void mb(void)
Memory barrier.
#define wmb()
Definition io.h:546
void(* signal)(struct vmbus_device *vmdev)
Signal channel.
Definition vmbus.h:491
uint8_t out[PAGE_SIZE/2]
Outbound interrupts.
Definition vmbus.h:378
uint32_t intr_mask
Interrupt mask.
Definition vmbus.h:366
uint32_t cons
Consumer index (modulo ring length)
Definition vmbus.h:364
uint32_t prod
Producer index (modulo ring length)
Definition vmbus.h:362
static size_t vmbus_produce(struct vmbus_device *vmdev, size_t prod, const void *data, size_t len)
Fill outbound ring buffer.
Definition vmbus.c:617

References assert, vmbus_device::channel, cons, vmbus_ring::cons, cpu_to_le16, cpu_to_le32, data, DBGC, DBGC2, DBGC2_HDA, vmbus_device::dev, ENOBUFS, fill, header, vmbus_device::hv, vmbus::intr, vmbus_ring::intr_mask, le16_to_cpu, le32_to_cpu, len, mb(), device::name, NULL, vmbus_device::out, vmbus_interrupt::out, vmbus_device::out_len, pad_len, vmbus_packet_footer::prod, vmbus_ring::prod, vmbus_packet_footer::reserved, rmb, set_bit, vmbus_device::signal, hv_hypervisor::vmbus, vmbus_produce(), and wmb.

Referenced by vmbus_send_cancellation(), vmbus_send_completion(), vmbus_send_control(), and vmbus_send_data().

◆ vmbus_send_control()

int vmbus_send_control ( struct vmbus_device * vmdev,
uint64_t xid,
const void * data,
size_t len )

Send control packet via ring buffer.

Parameters
vmdevVMBus device
xidTransaction ID (or zero to not request completion)
dataData
lenLength of data
Return values
rcReturn status code

Send data using a VMBUS_DATA_INBAND packet.

Definition at line 765 of file vmbus.c.

766 {
767 struct vmbus_packet_header *header = vmdev->packet;
768
769 /* Construct header in packet buffer */
770 assert ( header != NULL );
772 header->hdr_qlen = cpu_to_le16 ( sizeof ( *header ) / 8 );
773 header->flags = ( xid ?
775 header->xid = xid; /* Non-endian */
776
777 return vmbus_send ( vmdev, header, data, len );
778}
uint64_t xid
Transaction ID.
Definition vmbus.h:279
static int vmbus_send(struct vmbus_device *vmdev, struct vmbus_packet_header *header, const void *data, size_t len)
Send packet via ring buffer.
Definition vmbus.c:677
@ VMBUS_DATA_INBAND
Definition vmbus.h:284
@ VMBUS_COMPLETION_REQUESTED
Definition vmbus.h:293

References assert, cpu_to_le16, data, header, len, NULL, vmbus_device::packet, VMBUS_COMPLETION_REQUESTED, VMBUS_DATA_INBAND, vmbus_send(), and vmbus_packet_header::xid.

Referenced by netvsc_control().

◆ vmbus_send_data()

int vmbus_send_data ( struct vmbus_device * vmdev,
uint64_t xid,
const void * data,
size_t len,
struct io_buffer * iobuf )

Send data packet via ring buffer.

Parameters
vmdevVMBus device
xidTransaction ID
dataData
lenLength of data
iobufI/O buffer
Return values
rcReturn status code

Send data using a VMBUS_DATA_GPA_DIRECT packet. The caller is responsible for ensuring that the I/O buffer remains untouched until the corresponding completion has been received.

Definition at line 794 of file vmbus.c.

795 {
796 physaddr_t addr = virt_to_phys ( iobuf->data );
797 unsigned int pfn_count = hv_pfn_count ( addr, iob_len ( iobuf ) );
798 struct {
799 struct vmbus_gpa_direct_header gpa;
800 struct vmbus_gpa_range range;
801 uint64_t pfn[pfn_count];
802 } __attribute__ (( packed )) *header = vmdev->packet;
803 unsigned int i;
804
805 /* Sanity check */
806 assert ( header != NULL );
807 assert ( sizeof ( *header ) <= vmdev->mtu );
808
809 /* Construct header in packet buffer */
810 header->gpa.header.type = cpu_to_le16 ( VMBUS_DATA_GPA_DIRECT );
811 header->gpa.header.hdr_qlen = cpu_to_le16 ( sizeof ( *header ) / 8 );
812 header->gpa.header.flags = cpu_to_le16 ( VMBUS_COMPLETION_REQUESTED );
813 header->gpa.header.xid = xid; /* Non-endian */
814 header->gpa.range_count = 1;
815 header->range.len = cpu_to_le32 ( iob_len ( iobuf ) );
816 header->range.offset = cpu_to_le32 ( addr & ( PAGE_SIZE - 1 ) );
817 for ( i = 0 ; i < pfn_count ; i++ )
818 header->pfn[i] = ( ( addr / PAGE_SIZE ) + i );
819
820 return vmbus_send ( vmdev, &header->gpa.header, data, len );
821}
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
void * data
Start of data.
Definition iobuf.h:53
VMBus GPA direct header.
Definition vmbus.h:297
Guest physical address range descriptor.
Definition vmbus.h:57
uint64_t pfn[0]
Page frame numbers.
Definition vmbus.h:67
@ VMBUS_DATA_GPA_DIRECT
Definition vmbus.h:286

References __attribute__, addr, assert, cpu_to_le16, cpu_to_le32, data, io_buffer::data, header, hv_pfn_count(), iob_len(), len, vmbus_device::mtu, NULL, vmbus_device::packet, PAGE_SIZE, range, VMBUS_COMPLETION_REQUESTED, VMBUS_DATA_GPA_DIRECT, and vmbus_send().

Referenced by netvsc_transmit().

◆ vmbus_send_completion()

int vmbus_send_completion ( struct vmbus_device * vmdev,
uint64_t xid,
const void * data,
size_t len )

Send completion packet via ring buffer.

Parameters
vmdevVMBus device
xidTransaction ID
dataData
lenLength of data
Return values
rcReturn status code

Send data using a VMBUS_COMPLETION packet.

Definition at line 834 of file vmbus.c.

835 {
836 struct vmbus_packet_header *header = vmdev->packet;
837
838 /* Construct header in packet buffer */
839 assert ( header != NULL );
841 header->hdr_qlen = cpu_to_le16 ( sizeof ( *header ) / 8 );
842 header->flags = 0;
843 header->xid = xid; /* Non-endian */
844
845 return vmbus_send ( vmdev, header, data, len );
846}
@ VMBUS_COMPLETION
Definition vmbus.h:288

References assert, cpu_to_le16, data, header, len, NULL, vmbus_device::packet, VMBUS_COMPLETION, vmbus_send(), and vmbus_packet_header::xid.

Referenced by netvsc_recv_data().

◆ vmbus_send_cancellation()

int vmbus_send_cancellation ( struct vmbus_device * vmdev,
uint64_t xid )

Send cancellation packet via ring buffer.

Parameters
vmdevVMBus device
xidTransaction ID
Return values
rcReturn status code

Send data using a VMBUS_CANCELLATION packet.

Definition at line 857 of file vmbus.c.

857 {
858 struct vmbus_packet_header *header = vmdev->packet;
859
860 /* Construct header in packet buffer */
861 assert ( header != NULL );
863 header->hdr_qlen = cpu_to_le16 ( sizeof ( *header ) / 8 );
864 header->flags = 0;
865 header->xid = xid; /* Non-endian */
866
867 return vmbus_send ( vmdev, header, NULL, 0 );
868}
@ VMBUS_CANCELLATION
Definition vmbus.h:287

References assert, cpu_to_le16, header, NULL, vmbus_device::packet, VMBUS_CANCELLATION, vmbus_send(), and vmbus_packet_header::xid.

Referenced by netvsc_cancel_transmit().

◆ vmbus_xfer_pages()

struct vmbus_xfer_pages * vmbus_xfer_pages ( struct vmbus_device * vmdev,
uint16_t pageset )
static

Get transfer page set from pageset ID.

Parameters
vmdevVMBus device
pagesetPage set ID (in protocol byte order)
Return values
pagesPage set, or NULL if not found

Definition at line 877 of file vmbus.c.

878 {
879 struct vmbus_xfer_pages *pages;
880
881 /* Locate page set */
882 list_for_each_entry ( pages, &vmdev->pages, list ) {
883 if ( pages->pageset == pageset )
884 return pages;
885 }
886
887 DBGC ( vmdev, "VMBUS %s unrecognised page set ID %#04x\n",
888 vmdev->dev.name, le16_to_cpu ( pageset ) );
889 return NULL;
890}
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition list.h:432
uint16_t pageset
Page set ID.
Definition netvsc.h:5
struct list_head pages
List of transfer page sets.
Definition vmbus.h:511
VMBus transfer page set.
Definition vmbus.h:465
struct list_head list
List of all transfer page sets.
Definition vmbus.h:467
uint16_t pageset
Page set ID (in protocol byte order)
Definition vmbus.h:469

References DBGC, vmbus_device::dev, le16_to_cpu, vmbus_xfer_pages::list, list_for_each_entry, device::name, NULL, vmbus_device::pages, pageset, and vmbus_xfer_pages::pageset.

Referenced by vmbus_xfer_page_iobufs().

◆ vmbus_xfer_page_iobufs()

int vmbus_xfer_page_iobufs ( struct vmbus_device * vmdev,
struct vmbus_packet_header * header,
struct list_head * list )
static

Construct I/O buffer list from transfer pages.

Parameters
vmdevVMBus device
headerTransfer page header
listI/O buffer list to populate
Return values
rcReturn status code

Definition at line 900 of file vmbus.c.

902 {
903 struct vmbus_xfer_page_header *page_header =
905 struct vmbus_xfer_pages *pages;
906 struct io_buffer *iobuf;
907 struct io_buffer *tmp;
908 size_t len;
909 size_t offset;
910 unsigned int range_count;
911 unsigned int i;
912 int rc;
913
914 /* Sanity check */
916
917 /* Locate page set */
918 pages = vmbus_xfer_pages ( vmdev, page_header->pageset );
919 if ( ! pages ) {
920 rc = -ENOENT;
921 goto err_pages;
922 }
923
924 /* Allocate and populate I/O buffers */
925 range_count = le32_to_cpu ( page_header->range_count );
926 for ( i = 0 ; i < range_count ; i++ ) {
927
928 /* Parse header */
929 len = le32_to_cpu ( page_header->range[i].len );
930 offset = le32_to_cpu ( page_header->range[i].offset );
931
932 /* Allocate I/O buffer */
933 iobuf = alloc_iob ( len );
934 if ( ! iobuf ) {
935 DBGC ( vmdev, "VMBUS %s could not allocate %zd-byte "
936 "I/O buffer\n", vmdev->dev.name, len );
937 rc = -ENOMEM;
938 goto err_alloc;
939 }
940
941 /* Add I/O buffer to list */
942 list_add ( &iobuf->list, list );
943
944 /* Populate I/O buffer */
945 if ( ( rc = pages->op->copy ( pages, iob_put ( iobuf, len ),
946 offset, len ) ) != 0 ) {
947 DBGC ( vmdev, "VMBUS %s could not populate I/O buffer "
948 "range [%zd,%zd): %s\n",
949 vmdev->dev.name, offset, len, strerror ( rc ) );
950 goto err_copy;
951 }
952 }
953
954 return 0;
955
956 err_copy:
957 err_alloc:
959 list_del ( &iobuf->list );
960 free_iob ( iobuf );
961 }
962 err_pages:
963 return rc;
964}
uint16_t offset
Offset to command line.
Definition bzimage.h:3
#define ENOENT
No such file or directory.
Definition errno.h:515
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
#define iob_put(iobuf, len)
Definition iobuf.h:125
unsigned long tmp
Definition linux_pci.h:65
#define list_for_each_entry_safe(pos, tmp, head, member)
Iterate over entries in a list, safe against deletion of the current entry.
Definition list.h:459
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define list_add(new, head)
Add a new entry to the head of a list.
Definition list.h:70
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
A persistent I/O buffer.
Definition iobuf.h:38
struct list_head list
List of which this buffer is a member.
Definition iobuf.h:45
VMBus transfer page header.
Definition vmbus.h:317
uint32_t range_count
Number of range descriptors.
Definition vmbus.h:327
uint16_t pageset
Page set ID.
Definition vmbus.h:321
struct vmbus_xfer_page_range range[0]
Range descriptors.
Definition vmbus.h:329
uint32_t len
Length.
Definition vmbus.h:311
uint32_t offset
Offset.
Definition vmbus.h:313
int(* copy)(struct vmbus_xfer_pages *pages, void *data, size_t offset, size_t len)
Copy data from transfer page.
Definition vmbus.h:460
struct vmbus_xfer_pages_operations * op
Page set operations.
Definition vmbus.h:471
static struct vmbus_xfer_pages * vmbus_xfer_pages(struct vmbus_device *vmdev, uint16_t pageset)
Get transfer page set from pageset ID.
Definition vmbus.c:877
@ VMBUS_DATA_XFER_PAGES
Definition vmbus.h:285

References alloc_iob(), assert, container_of, vmbus_xfer_pages_operations::copy, cpu_to_le16, DBGC, vmbus_device::dev, ENOENT, ENOMEM, free_iob(), header, iob_put, le32_to_cpu, len, vmbus_xfer_page_range::len, io_buffer::list, list_add, list_del, list_for_each_entry_safe, device::name, offset, vmbus_xfer_page_range::offset, vmbus_xfer_pages::op, vmbus_xfer_page_header::pageset, vmbus_xfer_page_header::range, vmbus_xfer_page_header::range_count, rc, strerror(), tmp, VMBUS_DATA_XFER_PAGES, and vmbus_xfer_pages().

Referenced by vmbus_poll().

◆ vmbus_poll()

int vmbus_poll ( struct vmbus_device * vmdev)

Poll ring buffer.

Parameters
vmdevVMBus device
Return values
rcReturn status code

Definition at line 972 of file vmbus.c.

972 {
973 struct vmbus_packet_header *header = vmdev->packet;
974 struct list_head list;
975 void *data;
976 size_t header_len;
977 size_t len;
978 size_t footer_len;
979 size_t ring_len;
980 size_t cons;
981 size_t old_cons;
982 uint64_t xid;
983 int rc;
984
985 /* Sanity checks */
986 assert ( vmdev->packet != NULL );
987 assert ( vmdev->in != NULL );
988
989 /* Return immediately if buffer is empty */
990 if ( ! vmbus_has_data ( vmdev ) )
991 return 0;
992 cons = le32_to_cpu ( vmdev->in->cons );
993 old_cons = cons;
994
995 /* Consume (start of) header */
996 cons = vmbus_consume ( vmdev, cons, header, sizeof ( *header ) );
997
998 /* Parse and sanity check header */
999 header_len = ( le16_to_cpu ( header->hdr_qlen ) * 8 );
1000 if ( header_len < sizeof ( *header ) ) {
1001 DBGC ( vmdev, "VMBUS %s received underlength header (%zd "
1002 "bytes)\n", vmdev->dev.name, header_len );
1003 return -EINVAL;
1004 }
1005 len = ( ( le16_to_cpu ( header->qlen ) * 8 ) - header_len );
1006 footer_len = sizeof ( struct vmbus_packet_footer );
1007 ring_len = ( header_len + len + footer_len );
1008 if ( ring_len > vmdev->mtu ) {
1009 DBGC ( vmdev, "VMBUS %s received overlength packet (%zd "
1010 "bytes)\n", vmdev->dev.name, ring_len );
1011 return -ERANGE;
1012 }
1013 xid = le64_to_cpu ( header->xid );
1014
1015 /* Consume remainder of packet */
1016 cons = vmbus_consume ( vmdev, cons,
1017 ( ( ( void * ) header ) + sizeof ( *header ) ),
1018 ( ring_len - sizeof ( *header ) ) );
1019 DBGC2 ( vmdev, "VMBUS %s received:\n", vmdev->dev.name );
1020 DBGC2_HDA ( vmdev, old_cons, header, ring_len );
1021 assert ( ( ( cons - old_cons ) & ( vmdev->in_len - 1 ) ) == ring_len );
1022
1023 /* Allocate I/O buffers, if applicable */
1024 INIT_LIST_HEAD ( &list );
1025 if ( header->type == cpu_to_le16 ( VMBUS_DATA_XFER_PAGES ) ) {
1026 if ( ( rc = vmbus_xfer_page_iobufs ( vmdev, header,
1027 &list ) ) != 0 )
1028 return rc;
1029 }
1030
1031 /* Update producer index */
1032 rmb();
1033 vmdev->in->cons = cpu_to_le32 ( cons );
1034
1035 /* Handle packet */
1036 data = ( ( ( void * ) header ) + header_len );
1037 switch ( header->type ) {
1038
1040 if ( ( rc = vmdev->op->recv_control ( vmdev, xid, data,
1041 len ) ) != 0 ) {
1042 DBGC ( vmdev, "VMBUS %s could not handle control "
1043 "packet: %s\n",
1044 vmdev->dev.name, strerror ( rc ) );
1045 return rc;
1046 }
1047 break;
1048
1050 if ( ( rc = vmdev->op->recv_data ( vmdev, xid, data, len,
1051 &list ) ) != 0 ) {
1052 DBGC ( vmdev, "VMBUS %s could not handle data packet: "
1053 "%s\n", vmdev->dev.name, strerror ( rc ) );
1054 return rc;
1055 }
1056 break;
1057
1058 case cpu_to_le16 ( VMBUS_COMPLETION ) :
1059 if ( ( rc = vmdev->op->recv_completion ( vmdev, xid, data,
1060 len ) ) != 0 ) {
1061 DBGC ( vmdev, "VMBUS %s could not handle completion: "
1062 "%s\n", vmdev->dev.name, strerror ( rc ) );
1063 return rc;
1064 }
1065 break;
1066
1068 if ( ( rc = vmdev->op->recv_cancellation ( vmdev, xid ) ) != 0){
1069 DBGC ( vmdev, "VMBUS %s could not handle cancellation: "
1070 "%s\n", vmdev->dev.name, strerror ( rc ) );
1071 return rc;
1072 }
1073 break;
1074
1075 default:
1076 DBGC ( vmdev, "VMBUS %s unknown packet type %d\n",
1077 vmdev->dev.name, le16_to_cpu ( header->type ) );
1078 return -ENOTSUP;
1079 }
1080
1081 return 0;
1082}
#define le64_to_cpu(value)
Definition byteswap.h:115
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition list.h:46
if(natsemi->flags &NATSEMI_64BIT) return 1
A doubly-linked list entry (or list head)
Definition list.h:19
static size_t vmbus_consume(struct vmbus_device *vmdev, size_t cons, void *data, size_t len)
Consume inbound ring buffer.
Definition vmbus.c:645
static int vmbus_xfer_page_iobufs(struct vmbus_device *vmdev, struct vmbus_packet_header *header, struct list_head *list)
Construct I/O buffer list from transfer pages.
Definition vmbus.c:900
static int vmbus_has_data(struct vmbus_device *vmdev)
Check if data is present in ring buffer.
Definition vmbus.h:588

References assert, cons, vmbus_ring::cons, cpu_to_le16, cpu_to_le32, data, DBGC, DBGC2, DBGC2_HDA, vmbus_device::dev, EINVAL, ENOTSUP, header, vmbus_device::in, vmbus_device::in_len, INIT_LIST_HEAD, le16_to_cpu, le32_to_cpu, le64_to_cpu, len, vmbus_device::mtu, device::name, NULL, vmbus_device::op, vmbus_device::packet, rc, vmbus_channel_operations::recv_cancellation, vmbus_channel_operations::recv_completion, vmbus_channel_operations::recv_control, vmbus_channel_operations::recv_data, rmb, strerror(), VMBUS_CANCELLATION, VMBUS_COMPLETION, vmbus_consume(), VMBUS_DATA_INBAND, VMBUS_DATA_XFER_PAGES, vmbus_has_data(), and vmbus_xfer_page_iobufs().

Referenced by netvsc_control(), and netvsc_poll().

◆ vmbus_dump_channel()

void vmbus_dump_channel ( struct vmbus_device * vmdev)

Dump channel status (for debugging)

Parameters
vmdevVMBus device

Definition at line 1089 of file vmbus.c.

1089 {
1090 size_t out_prod = le32_to_cpu ( vmdev->out->prod );
1091 size_t out_cons = le32_to_cpu ( vmdev->out->cons );
1092 size_t in_prod = le32_to_cpu ( vmdev->in->prod );
1093 size_t in_cons = le32_to_cpu ( vmdev->in->cons );
1094 size_t in_len;
1095 size_t first;
1096 size_t second;
1097
1098 /* Dump ring status */
1099 DBGC ( vmdev, "VMBUS %s out %03zx:%03zx%s in %03zx:%03zx%s\n",
1100 vmdev->dev.name, out_prod, out_cons,
1101 ( vmdev->out->intr_mask ? "(m)" : "" ), in_prod, in_cons,
1102 ( vmdev->in->intr_mask ? "(m)" : "" ) );
1103
1104 /* Dump inbound ring contents, if any */
1105 if ( in_prod != in_cons ) {
1106 in_len = ( ( in_prod - in_cons ) &
1107 ( vmdev->in_len - 1 ) );
1108 first = ( vmdev->in_len - in_cons );
1109 if ( first > in_len )
1110 first = in_len;
1111 second = ( in_len - first );
1112 DBGC_HDA ( vmdev, in_cons, &vmdev->in->data[in_cons], first );
1113 DBGC_HDA ( vmdev, 0, &vmdev->in->data[0], second );
1114 }
1115}
#define DBGC_HDA(...)
Definition compiler.h:506

References vmbus_ring::cons, vmbus_ring::data, DBGC, DBGC_HDA, vmbus_device::dev, first, vmbus_device::in, vmbus_device::in_len, vmbus_ring::intr_mask, le32_to_cpu, device::name, vmbus_device::out, and vmbus_ring::prod.

Referenced by netvsc_control().

◆ vmbus_find_driver()

struct vmbus_driver * vmbus_find_driver ( const union uuid * type)
static

Find driver for VMBus device.

Parameters
vmdevVMBus device
Return values
driverDriver, or NULL

Definition at line 1123 of file vmbus.c.

1123 {
1124 struct vmbus_driver *vmdrv;
1125
1127 if ( memcmp ( &vmdrv->type, type, sizeof ( *type ) ) == 0 )
1128 return vmdrv;
1129 }
1130 return NULL;
1131}
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
A VMBus device driver.
Definition vmbus.h:520
union uuid type
Device type.
Definition vmbus.h:524
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386
#define VMBUS_DRIVERS
VMBus device driver table.
Definition vmbus.h:545

References for_each_table_entry, memcmp(), NULL, type, vmbus_driver::type, and VMBUS_DRIVERS.

Referenced by vmbus_probe_channels().

◆ vmbus_probe_channels()

int vmbus_probe_channels ( struct hv_hypervisor * hv,
struct device * parent )
static

Probe channels.

Parameters
hvHyper-V hypervisor
parentParent device
Return values
rcReturn status code

Definition at line 1140 of file vmbus.c.

1141 {
1142 struct vmbus *vmbus = hv->vmbus;
1143 const struct vmbus_message_header *header = &vmbus->message->header;
1144 const struct vmbus_offer_channel *offer = &vmbus->message->offer;
1145 const union uuid *type;
1146 union uuid instance;
1147 struct vmbus_driver *driver;
1148 struct vmbus_device *vmdev;
1149 struct vmbus_device *tmp;
1150 unsigned int channel;
1151 int rc;
1152
1153 /* Post message */
1155 goto err_post_message;
1156
1157 /* Collect responses */
1158 while ( 1 ) {
1159
1160 /* Wait for response */
1161 if ( ( rc = vmbus_wait_for_any_message ( hv ) ) != 0 )
1162 goto err_wait_for_any_message;
1163
1164 /* Handle response */
1165 if ( header->type == cpu_to_le32 ( VMBUS_OFFER_CHANNEL ) ) {
1166
1167 /* Parse offer */
1168 type = &offer->type;
1169 channel = le32_to_cpu ( offer->channel );
1170 DBGC2 ( vmbus, "VMBUS %p offer %d type %s",
1171 vmbus, channel, uuid_ntoa ( type ) );
1172 if ( offer->monitored )
1173 DBGC2 ( vmbus, " monitor %d", offer->monitor );
1174 DBGC2 ( vmbus, "\n" );
1175
1176 /* Look for a driver */
1178 if ( ! driver ) {
1179 DBGC2 ( vmbus, "VMBUS %p has no driver for "
1180 "type %s\n", vmbus, uuid_ntoa ( type ));
1181 /* Not a fatal error */
1182 continue;
1183 }
1184
1185 /* Allocate and initialise device */
1186 vmdev = zalloc ( sizeof ( *vmdev ) );
1187 if ( ! vmdev ) {
1188 rc = -ENOMEM;
1189 goto err_alloc_vmdev;
1190 }
1191 memcpy ( &instance, &offer->instance,
1192 sizeof ( instance ) );
1193 uuid_mangle ( &instance );
1194 snprintf ( vmdev->dev.name, sizeof ( vmdev->dev.name ),
1195 "{%s}", uuid_ntoa ( &instance ) );
1196 vmdev->dev.desc.bus_type = BUS_TYPE_HV;
1197 INIT_LIST_HEAD ( &vmdev->dev.children );
1198 list_add_tail ( &vmdev->dev.siblings,
1199 &parent->children );
1200 vmdev->dev.parent = parent;
1201 vmdev->hv = hv;
1202 memcpy ( &vmdev->instance, &offer->instance,
1203 sizeof ( vmdev->instance ) );
1204 vmdev->channel = channel;
1205 vmdev->monitor = offer->monitor;
1206 vmdev->signal = ( offer->monitored ?
1209 INIT_LIST_HEAD ( &vmdev->pages );
1210 vmdev->driver = driver;
1211 vmdev->dev.driver_name = driver->name;
1212 DBGC ( vmdev, "VMBUS %s has driver \"%s\"\n",
1213 vmdev->dev.name, vmdev->driver->name );
1214
1215 } else if ( header->type ==
1217
1218 /* End of offer list */
1219 break;
1220
1221 } else {
1222 DBGC ( vmbus, "VMBUS %p unexpected offer response type "
1223 "%d\n", vmbus, le32_to_cpu ( header->type ) );
1224 rc = -EPROTO;
1225 goto err_unexpected_offer;
1226 }
1227 }
1228
1229 /* Probe all devices. We do this only after completing
1230 * enumeration since devices will need to send and receive
1231 * VMBus messages.
1232 */
1233 list_for_each_entry ( vmdev, &parent->children, dev.siblings ) {
1234 if ( ( rc = vmdev->driver->probe ( vmdev ) ) != 0 ) {
1235 DBGC ( vmdev, "VMBUS %s could not probe: %s\n",
1236 vmdev->dev.name, strerror ( rc ) );
1237 goto err_probe;
1238 }
1239 }
1240
1241 return 0;
1242
1243 err_probe:
1244 /* Remove driver from each device that was already probed */
1246 dev.siblings ) {
1247 vmdev->driver->remove ( vmdev );
1248 }
1249 err_unexpected_offer:
1250 err_alloc_vmdev:
1251 err_wait_for_any_message:
1252 /* Free any devices allocated (but potentially not yet probed) */
1253 list_for_each_entry_safe ( vmdev, tmp, &parent->children,
1254 dev.siblings ) {
1255 list_del ( &vmdev->dev.siblings );
1256 free ( vmdev );
1257 }
1258 err_post_message:
1259 return rc;
1260}
#define BUS_TYPE_HV
Hyper-V bus type.
Definition device.h:68
#define list_for_each_entry_continue_reverse(pos, head, member)
Iterate over entries in a list in reverse, starting after current position.
Definition list.h:487
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition list.h:94
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
uint32_t channel
RNDIS channel.
Definition netvsc.h:3
unsigned int bus_type
Bus type.
Definition device.h:25
struct device_description desc
Device description.
Definition device.h:83
struct device * parent
Bus device.
Definition device.h:89
struct list_head children
Devices attached to this device.
Definition device.h:87
struct list_head siblings
Devices on the same bus.
Definition device.h:85
const char * driver_name
Driver name.
Definition device.h:81
A VMBus device.
Definition vmbus.h:475
struct vmbus_driver * driver
Driver.
Definition vmbus.h:514
union uuid instance
Channel instance.
Definition vmbus.h:482
int(* probe)(struct vmbus_device *vmdev)
Probe device.
Definition vmbus.h:530
void(* remove)(struct vmbus_device *vmdev)
Remove device.
Definition vmbus.h:541
const char * name
Name.
Definition vmbus.h:522
VMBus "offer channel" message.
Definition vmbus.h:97
union uuid type
Channel type.
Definition vmbus.h:101
union uuid instance
Channel instance.
Definition vmbus.h:103
uint8_t monitor
Monitor ID.
Definition vmbus.h:117
uint8_t monitored
Monitor exists.
Definition vmbus.h:119
uint32_t channel
Channel ID.
Definition vmbus.h:115
A universally unique ID.
Definition uuid.h:16
struct vmbus_offer_channel offer
"Offer channel" message
Definition vmbus.h:243
const char * uuid_ntoa(const union uuid *uuid)
Convert UUID to printable string.
Definition uuid.c:46
static void uuid_mangle(union uuid *uuid)
Change UUID endianness.
Definition uuid.h:44
static void vmbus_signal_monitor(struct vmbus_device *vmdev)
Signal channel via monitor page.
Definition vmbus.c:574
static void vmbus_signal_event(struct vmbus_device *vmdev)
Signal channel via hypervisor event.
Definition vmbus.c:593
static struct vmbus_driver * vmbus_find_driver(const union uuid *type)
Find driver for VMBus device.
Definition vmbus.c:1123
@ VMBUS_REQUEST_OFFERS
Definition vmbus.h:81
@ VMBUS_OFFER_CHANNEL
Definition vmbus.h:80
@ VMBUS_ALL_OFFERS_DELIVERED
Definition vmbus.h:82
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383

References device_description::bus_type, BUS_TYPE_HV, channel, vmbus_device::channel, vmbus_offer_channel::channel, device::children, cpu_to_le32, DBGC, DBGC2, device::desc, vmbus_device::dev, vmbus_device::driver, device::driver_name, ENOMEM, EPROTO, free, header, vmbus_message::header, vmbus_device::hv, INIT_LIST_HEAD, vmbus_device::instance, vmbus_offer_channel::instance, le32_to_cpu, list_add_tail, list_del, list_for_each_entry, list_for_each_entry_continue_reverse, list_for_each_entry_safe, memcpy(), vmbus::message, vmbus_device::monitor, vmbus_offer_channel::monitor, vmbus_offer_channel::monitored, device::name, vmbus_driver::name, vmbus_message::offer, vmbus_device::pages, device::parent, vmbus_driver::probe, rc, vmbus_driver::remove, device::siblings, vmbus_device::signal, snprintf(), strerror(), tmp, type, vmbus_offer_channel::type, uuid_mangle(), uuid_ntoa(), hv_hypervisor::vmbus, VMBUS_ALL_OFFERS_DELIVERED, vmbus_find_driver(), VMBUS_OFFER_CHANNEL, vmbus_post_empty_message(), VMBUS_REQUEST_OFFERS, vmbus_signal_event(), vmbus_signal_monitor(), vmbus_wait_for_any_message(), and zalloc().

Referenced by vmbus_probe().

◆ vmbus_reset_channels()

int vmbus_reset_channels ( struct hv_hypervisor * hv,
struct device * parent )
static

Reset channels.

Parameters
hvHyper-V hypervisor
parentParent device
Return values
rcReturn status code

Definition at line 1270 of file vmbus.c.

1271 {
1272 struct vmbus *vmbus = hv->vmbus;
1273 const struct vmbus_message_header *header = &vmbus->message->header;
1274 const struct vmbus_offer_channel *offer = &vmbus->message->offer;
1275 const union uuid *type;
1276 struct vmbus_device *vmdev;
1277 unsigned int channel;
1278 int rc;
1279
1280 /* Post message */
1282 return rc;
1283
1284 /* Collect responses */
1285 while ( 1 ) {
1286
1287 /* Wait for response */
1288 if ( ( rc = vmbus_wait_for_any_message ( hv ) ) != 0 )
1289 return rc;
1290
1291 /* Handle response */
1292 if ( header->type == cpu_to_le32 ( VMBUS_OFFER_CHANNEL ) ) {
1293
1294 /* Parse offer */
1295 type = &offer->type;
1296 channel = le32_to_cpu ( offer->channel );
1297 DBGC2 ( vmbus, "VMBUS %p offer %d type %s",
1298 vmbus, channel, uuid_ntoa ( type ) );
1299 if ( offer->monitored )
1300 DBGC2 ( vmbus, " monitor %d", offer->monitor );
1301 DBGC2 ( vmbus, "\n" );
1302
1303 /* Do nothing with the offer; we already have all
1304 * of the relevant state from the initial probe.
1305 */
1306
1307 } else if ( header->type ==
1309
1310 /* End of offer list */
1311 break;
1312
1313 } else {
1314 DBGC ( vmbus, "VMBUS %p unexpected offer response type "
1315 "%d\n", vmbus, le32_to_cpu ( header->type ) );
1316 return -EPROTO;
1317 }
1318 }
1319
1320 /* Reset all devices */
1321 list_for_each_entry ( vmdev, &parent->children, dev.siblings ) {
1322 if ( ( rc = vmdev->driver->reset ( vmdev ) ) != 0 ) {
1323 DBGC ( vmdev, "VMBUS %s could not reset: %s\n",
1324 vmdev->dev.name, strerror ( rc ) );
1325 /* Continue attempting to reset other devices */
1326 continue;
1327 }
1328 }
1329
1330 return 0;
1331}
int(* reset)(struct vmbus_device *vmdev)
Reset device.
Definition vmbus.h:536

References channel, vmbus_offer_channel::channel, device::children, cpu_to_le32, DBGC, DBGC2, vmbus_device::dev, vmbus_device::driver, EPROTO, header, vmbus_message::header, vmbus_device::hv, le32_to_cpu, list_for_each_entry, vmbus::message, vmbus_offer_channel::monitor, vmbus_offer_channel::monitored, device::name, vmbus_message::offer, rc, vmbus_driver::reset, device::siblings, strerror(), type, vmbus_offer_channel::type, uuid_ntoa(), hv_hypervisor::vmbus, VMBUS_ALL_OFFERS_DELIVERED, VMBUS_OFFER_CHANNEL, vmbus_post_empty_message(), VMBUS_REQUEST_OFFERS, and vmbus_wait_for_any_message().

Referenced by vmbus_reset().

◆ vmbus_remove_channels()

void vmbus_remove_channels ( struct hv_hypervisor *hv __unused,
struct device * parent )
static

Remove channels.

Parameters
hvHyper-V hypervisor
parentParent device

Definition at line 1339 of file vmbus.c.

1340 {
1341 struct vmbus_device *vmdev;
1342 struct vmbus_device *tmp;
1343
1344 /* Remove devices */
1345 list_for_each_entry_safe ( vmdev, tmp, &parent->children,
1346 dev.siblings ) {
1347 vmdev->driver->remove ( vmdev );
1348 assert ( list_empty ( &vmdev->dev.children ) );
1349 assert ( vmdev->out == NULL );
1350 assert ( vmdev->in == NULL );
1351 assert ( vmdev->packet == NULL );
1352 assert ( list_empty ( &vmdev->pages ) );
1353 list_del ( &vmdev->dev.siblings );
1354 free ( vmdev );
1355 }
1356}
#define list_empty(list)
Test whether a list is empty.
Definition list.h:137

References __unused, assert, device::children, vmbus_device::dev, vmbus_device::driver, free, vmbus_device::in, list_del, list_empty, list_for_each_entry_safe, NULL, vmbus_device::out, vmbus_device::packet, vmbus_device::pages, vmbus_driver::remove, device::siblings, and tmp.

Referenced by vmbus_probe(), and vmbus_remove().

◆ vmbus_probe()

int vmbus_probe ( struct hv_hypervisor * hv,
struct device * parent )

Probe Hyper-V virtual machine bus.

Parameters
hvHyper-V hypervisor
parentParent device
Return values
rcReturn status code

Definition at line 1365 of file vmbus.c.

1365 {
1366 struct vmbus *vmbus;
1367 int rc;
1368
1369 /* Allocate and initialise structure */
1370 vmbus = zalloc ( sizeof ( *vmbus ) );
1371 if ( ! vmbus ) {
1372 rc = -ENOMEM;
1373 goto err_alloc;
1374 }
1375 hv->vmbus = vmbus;
1376
1377 /* Initialise message buffer pointer
1378 *
1379 * We use a pointer to the fixed-size Hyper-V received message
1380 * buffer. This allows us to access fields within received
1381 * messages without first checking the message size: any
1382 * fields beyond the end of the message will read as zero.
1383 */
1384 vmbus->message = ( ( void * ) hv->message->received.data );
1385 assert ( sizeof ( *vmbus->message ) <=
1386 sizeof ( hv->message->received.data ) );
1387
1388 /* Allocate interrupt and monitor pages */
1389 if ( ( rc = hv_alloc_pages ( hv, &vmbus->intr, &vmbus->monitor_in,
1390 &vmbus->monitor_out, NULL ) ) != 0 )
1391 goto err_alloc_pages;
1392
1393 /* Enable message interrupt */
1395
1396 /* Negotiate protocol version */
1397 if ( ( rc = vmbus_negotiate_version ( hv ) ) != 0 )
1398 goto err_negotiate_version;
1399
1400 /* Enumerate channels */
1401 if ( ( rc = vmbus_probe_channels ( hv, parent ) ) != 0 )
1402 goto err_probe_channels;
1403
1404 return 0;
1405
1406 vmbus_remove_channels ( hv, parent );
1407 err_probe_channels:
1408 vmbus_unload ( hv );
1409 err_negotiate_version:
1412 NULL );
1413 err_alloc_pages:
1414 free ( vmbus );
1415 err_alloc:
1416 return rc;
1417}
void hv_disable_sint(struct hv_hypervisor *hv, unsigned int sintx)
Disable synthetic interrupt.
Definition hyperv.c:423
void hv_free_pages(struct hv_hypervisor *hv,...)
Free pages.
Definition hyperv.c:113
int hv_alloc_pages(struct hv_hypervisor *hv,...)
Allocate zeroed pages.
Definition hyperv.c:78
void hv_enable_sint(struct hv_hypervisor *hv, unsigned int sintx)
Enable synthetic interrupt.
Definition hyperv.c:397
uint8_t data[240]
Message.
Definition hyperv.h:112
static void vmbus_remove_channels(struct hv_hypervisor *hv __unused, struct device *parent)
Remove channels.
Definition vmbus.c:1339
static int vmbus_probe_channels(struct hv_hypervisor *hv, struct device *parent)
Probe channels.
Definition vmbus.c:1140
static int vmbus_negotiate_version(struct hv_hypervisor *hv)
Negotiate protocol version.
Definition vmbus.c:231

References assert, hv_message::data, ENOMEM, free, hv_alloc_pages(), hv_disable_sint(), hv_enable_sint(), hv_free_pages(), vmbus::intr, hv_hypervisor::message, vmbus::message, vmbus::monitor_in, vmbus::monitor_out, NULL, rc, hv_message_buffer::received, hv_hypervisor::vmbus, VMBUS_MESSAGE_SINT, vmbus_negotiate_version(), vmbus_probe_channels(), vmbus_remove_channels(), vmbus_unload(), and zalloc().

Referenced by hv_probe().

◆ vmbus_reset()

int vmbus_reset ( struct hv_hypervisor * hv,
struct device * parent )

Reset Hyper-V virtual machine bus.

Parameters
hvHyper-V hypervisor
parentParent device
Return values
rcReturn status code

Definition at line 1426 of file vmbus.c.

1426 {
1427 struct vmbus *vmbus = hv->vmbus;
1428 int rc;
1429
1430 /* Mark all existent GPADLs as obsolete */
1432
1433 /* Clear interrupt and monitor pages */
1434 memset ( vmbus->intr, 0, PAGE_SIZE );
1437
1438 /* Enable message interrupt */
1440
1441 /* Renegotiate protocol version */
1442 if ( ( rc = vmbus_negotiate_version ( hv ) ) != 0 )
1443 return rc;
1444
1445 /* Reenumerate channels */
1446 if ( ( rc = vmbus_reset_channels ( hv, parent ) ) != 0 )
1447 return rc;
1448
1449 return 0;
1450}
unsigned int vmbus_obsolete_gpadl
Obsolete GPADL ID threshold.
Definition vmbus.c:61
static int vmbus_reset_channels(struct hv_hypervisor *hv, struct device *parent)
Reset channels.
Definition vmbus.c:1270

References hv_enable_sint(), vmbus::intr, memset(), vmbus::monitor_in, vmbus::monitor_out, PAGE_SIZE, rc, hv_hypervisor::vmbus, vmbus_gpadl, VMBUS_MESSAGE_SINT, vmbus_negotiate_version(), vmbus_obsolete_gpadl, and vmbus_reset_channels().

Referenced by hv_unquiesce().

◆ vmbus_remove()

void vmbus_remove ( struct hv_hypervisor * hv,
struct device * parent )

Remove Hyper-V virtual machine bus.

Parameters
hvHyper-V hypervisor
parentParent device

Definition at line 1458 of file vmbus.c.

1458 {
1459 struct vmbus *vmbus = hv->vmbus;
1460
1461 vmbus_remove_channels ( hv, parent );
1462 vmbus_unload ( hv );
1465 NULL );
1466 free ( vmbus );
1467}

References free, hv_disable_sint(), hv_free_pages(), vmbus::intr, vmbus::monitor_in, vmbus::monitor_out, NULL, hv_hypervisor::vmbus, VMBUS_MESSAGE_SINT, vmbus_remove_channels(), and vmbus_unload().

Referenced by hv_probe(), and hv_remove().

Variable Documentation

◆ vmbus_gpadl

unsigned int vmbus_gpadl = VMBUS_GPADL_MAGIC
static

Current (i.e.

most recently issued) GPADL ID

Definition at line 54 of file vmbus.c.

Referenced by vmbus_establish_gpadl(), and vmbus_reset().

◆ vmbus_obsolete_gpadl

unsigned int vmbus_obsolete_gpadl

Obsolete GPADL ID threshold.

When the Hyper-V connection is reset, any previous GPADLs are automatically rendered obsolete.

Definition at line 61 of file vmbus.c.

Referenced by vmbus_gpadl_is_obsolete(), and vmbus_reset().