View | Details | Raw Unified | Return to bug 195238
Collapse All | Expand All

(-)sys/dev/hyperv/include/hyperv.h (-7 / +170 lines)
Lines 46-51 Link Here
46
#include <sys/systm.h>
46
#include <sys/systm.h>
47
#include <sys/lock.h>
47
#include <sys/lock.h>
48
#include <sys/sema.h>
48
#include <sys/sema.h>
49
#include <sys/smp.h>
49
#include <sys/mutex.h>
50
#include <sys/mutex.h>
50
#include <sys/bus.h>
51
#include <sys/bus.h>
51
#include <vm/vm.h>
52
#include <vm/vm.h>
Lines 63-74 Link Here
63
#define HV_ERROR_MACHINE_LOCKED	0x800704F7
64
#define HV_ERROR_MACHINE_LOCKED	0x800704F7
64
65
65
/*
66
/*
66
 * A revision number of vmbus that is used for ensuring both ends on a
67
 * VMBUS version is 32 bit, upper 16 bit for major_number and lower
67
 * partition are using compatible versions.
68
 * 16 bit for minor_number.
69
 *
70
 * 0.13  --  Windows Server 2008
71
 * 1.1   --  Windows 7
72
 * 2.4   --  Windows 8
73
 * 3.0   --  Windows 8.1
68
 */
74
 */
75
#define HV_VMBUS_VERSION_WS2008		((0 << 16) | (13))
76
#define HV_VMBUS_VERSION_WIN7		((1 << 16) | (1))
77
#define HV_VMBUS_VERSION_WIN8		((2 << 16) | (4))
78
#define HV_VMBUS_VERSION_WIN8_1		((3 << 16) | (0))
69
79
70
#define HV_VMBUS_REVISION_NUMBER	13
80
#define HV_VMBUS_VERSION_INVALID	-1
71
81
82
#define HV_VMBUS_VERSION_CURRENT	HV_VMBUS_VERSION_WIN8_1
83
72
/*
84
/*
73
 * Make maximum size of pipe payload of 16K
85
 * Make maximum size of pipe payload of 16K
74
 */
86
 */
Lines 112-117 Link Here
112
	 unsigned char data[16];
124
	 unsigned char data[16];
113
} __packed hv_guid;
125
} __packed hv_guid;
114
126
127
#define HV_NIC_GUID							\
128
	.data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,	\
129
		0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
130
131
#define HV_IDE_GUID							\
132
	.data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,	\
133
		 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5}
134
135
#define HV_SCSI_GUID							\
136
	.data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,	\
137
		 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f}
138
115
/*
139
/*
116
 * At the center of the Channel Management library is
140
 * At the center of the Channel Management library is
117
 * the Channel Offer. This struct contains the
141
 * the Channel Offer. This struct contains the
Lines 147-153 Link Here
147
		} __packed pipe;
171
		} __packed pipe;
148
	} u;
172
	} u;
149
173
150
	uint32_t	padding;
174
	/*
175
	 * Sub_channel_index, newly added in Win8.
176
	 */
177
	uint16_t	sub_channel_index;
178
	uint16_t	padding;
151
179
152
} __packed hv_vmbus_channel_offer;
180
} __packed hv_vmbus_channel_offer;
153
181
Lines 344-350 Link Here
344
	hv_vmbus_channel_offer		offer;
372
	hv_vmbus_channel_offer		offer;
345
	uint32_t			child_rel_id;
373
	uint32_t			child_rel_id;
346
	uint8_t				monitor_id;
374
	uint8_t				monitor_id;
347
	hv_bool_uint8_t			monitor_allocated;
375
	/*
376
	 * This field has been splited into a bit field on Win7
377
	 * and higher.
378
	 */
379
	uint8_t				monitor_allocated:1;
380
	uint8_t				reserved:7;
381
	/*
382
	 * Following fields were added in win7 and higher.
383
	 * Make sure to check the version before accessing these fields.
384
	 *
385
	 * If "is_dedicated_interrupt" is set, we must not set the
386
	 * associated bit in the channel bitmap while sending the
387
	 * interrupt to the host.
388
	 *
389
	 * connection_id is used in signaling the host.
390
	 */
391
	uint16_t			is_dedicated_interrupt:1;
392
	uint16_t			reserved1:15;
393
	uint32_t			connection_id;
348
} __packed hv_vmbus_channel_offer_channel;
394
} __packed hv_vmbus_channel_offer_channel;
349
395
350
/*
396
/*
Lines 394-402 Link Here
394
    hv_gpadl_handle	ring_buffer_gpadl_handle;
440
    hv_gpadl_handle	ring_buffer_gpadl_handle;
395
441
396
    /*
442
    /*
397
     * GPADL for the channel's server context save area.
443
     * Starting with win8, this field will be used to specify
444
     * the target virtual processor on which to deliver the interrupt for
445
     * the host to guest.
446
     * Before win8, all incoming channel interrupts are only to
447
     * be delivered on cpu 0. Setting this value to 0 would
448
     * preserve the earlier behavior.
398
     */
449
     */
399
    hv_gpadl_handle	server_context_area_gpadl_handle;
450
    uint32_t		target_vcpu;
400
451
401
    /*
452
    /*
402
     * The upstream ring buffer begins at offset zero in the memory described
453
     * The upstream ring buffer begins at offset zero in the memory described
Lines 646-659 Link Here
646
} hv_vmbus_ring_buffer_info;
697
} hv_vmbus_ring_buffer_info;
647
698
648
typedef void (*hv_vmbus_pfn_channel_callback)(void *context);
699
typedef void (*hv_vmbus_pfn_channel_callback)(void *context);
700
typedef void (*hv_vmbus_sc_creation_callback)(void *context);
649
701
650
typedef enum {
702
typedef enum {
651
	HV_CHANNEL_OFFER_STATE,
703
	HV_CHANNEL_OFFER_STATE,
652
	HV_CHANNEL_OPENING_STATE,
704
	HV_CHANNEL_OPENING_STATE,
653
	HV_CHANNEL_OPEN_STATE,
705
	HV_CHANNEL_OPEN_STATE,
706
	HV_CHANNEL_OPENED_STATE,
654
	HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE,
707
	HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE,
655
} hv_vmbus_channel_state;
708
} hv_vmbus_channel_state;
656
709
710
/*
711
 *  Connection identifier type
712
 */
713
typedef union {
714
	uint32_t		as_uint32_t;
715
	struct {
716
		uint32_t	id:24;
717
		uint32_t	reserved:8;
718
	} u;
719
720
} __packed hv_vmbus_connection_id;
721
722
/*
723
 * Definition of the hv_vmbus_signal_event hypercall input structure
724
 */
725
typedef struct {
726
	hv_vmbus_connection_id	connection_id;
727
	uint16_t		flag_number;
728
	uint16_t		rsvd_z;
729
} __packed hv_vmbus_input_signal_event;
730
731
typedef struct {
732
	uint64_t			align8;
733
	hv_vmbus_input_signal_event	event;
734
} __packed hv_vmbus_input_signal_event_buffer;
735
657
typedef struct hv_vmbus_channel {
736
typedef struct hv_vmbus_channel {
658
	TAILQ_ENTRY(hv_vmbus_channel)	list_entry;
737
	TAILQ_ENTRY(hv_vmbus_channel)	list_entry;
659
	struct hv_device*		device;
738
	struct hv_device*		device;
Lines 688-695 Link Here
688
	hv_vmbus_pfn_channel_callback	on_channel_callback;
767
	hv_vmbus_pfn_channel_callback	on_channel_callback;
689
	void*				channel_callback_context;
768
	void*				channel_callback_context;
690
769
770
	/*
771
	 * If batched_reading is set to "true", mask the interrupt
772
	 * and read until the channel is empty.
773
	 * If batched_reading is set to "false", the channel is not
774
	 * going to perform batched reading.
775
	 *
776
	 * Batched reading is enabled by default; specific
777
	 * drivers that don't want this behavior can turn it off.
778
	 */
779
	boolean_t			batched_reading;
780
781
	boolean_t			is_dedicated_interrupt;
782
783
	/*
784
	 * Used as an input param for HV_CALL_SIGNAL_EVENT hypercall.
785
	 */
786
	hv_vmbus_input_signal_event_buffer	signal_event_buffer;
787
	/*
788
	 * 8-bytes aligned of the buffer above
789
	 */
790
	hv_vmbus_input_signal_event	*signal_event_param;
791
792
	/*
793
	 * From Win8, this field specifies the target virtual process
794
	 * on which to deliver the interupt from the host to guest.
795
	 * Before Win8, all channel interrupts would only be
796
	 * delivered on cpu 0. Setting this value to 0 would preserve
797
	 * the earlier behavior.
798
	 */
799
	uint32_t			target_vcpu;
800
	/* The corresponding CPUID in the guest */
801
	uint32_t			target_cpu;
802
803
	/*
804
	 * Support for multi-channels.
805
	 * The initial offer is considered the primary channel and this
806
	 * offer message will indicate if the host supports multi-channels.
807
	 * The guest is free to ask for multi-channels to be offerred and can
808
	 * open these multi-channels as a normal "primary" channel. However,
809
	 * all multi-channels will have the same type and instance guids as the
810
	 * primary channel. Requests sent on a given channel will result in a
811
	 * response on the same channel.
812
	 */
813
814
	/*
815
	 * Multi-channel creation callback. This callback will be called in
816
	 * process context when a Multi-channel offer is received from the host.
817
	 * The guest can open the Multi-channel in the context of this callback.
818
	 */
819
	hv_vmbus_sc_creation_callback	sc_creation_callback;
820
821
	struct mtx			sc_lock;
822
823
	/*
824
	 * Link list of all the multi-channels if this is a primary channel
825
	 */
826
	TAILQ_HEAD(, hv_vmbus_channel)	sc_list_anchor;
827
	TAILQ_ENTRY(hv_vmbus_channel)	sc_list_entry;
828
829
	/*
830
	 * The primary channel this sub-channle belongs to.
831
	 * This will be NULL for the primary channel.
832
	 */
833
	struct hv_vmbus_channel		*primary_channel;
834
	/*
835
	 * Support per channel state for use by vmbus drivers.
836
	 */
837
	void				*per_channel_state;
838
	/*
839
	 * To support per-cpu lookup mapping of relid to channel, link up
840
	 * channels based on their CPU affinity.
841
	 */
842
	/*XXX TAILQ_HEAD(, uint32_t)		percpu_list; */
691
} hv_vmbus_channel;
843
} hv_vmbus_channel;
692
844
845
static inline void
846
hv_set_channel_read_state(hv_vmbus_channel* channel, boolean_t state)
847
{
848
	channel->batched_reading = state;
849
}
850
693
typedef struct hv_device {
851
typedef struct hv_device {
694
	hv_guid		    class_id;
852
	hv_guid		    class_id;
695
	hv_guid		    device_id;
853
	hv_guid		    device_id;
Lines 760-765 Link Here
760
				hv_vmbus_channel*	channel,
918
				hv_vmbus_channel*	channel,
761
				uint32_t		gpadl_handle);
919
				uint32_t		gpadl_handle);
762
920
921
struct hv_vmbus_channel* vmbus_select_outgoing_channel(struct hv_vmbus_channel *promary);
922
763
/*
923
/*
764
 * Work abstraction defines
924
 * Work abstraction defines
765
 */
925
 */
Lines 819-824 Link Here
819
979
820
extern uint8_t* receive_buffer[];
980
extern uint8_t* receive_buffer[];
821
extern hv_vmbus_service service_table[];
981
extern hv_vmbus_service service_table[];
982
extern uint32_t hv_vmbus_protocal_version;
983
extern int mp_ncpus;
984
extern volatile int smp_started;
822
985
823
void hv_kvp_callback(void *context);
986
void hv_kvp_callback(void *context);
824
int hv_kvp_init(hv_vmbus_service *serv);
987
int hv_kvp_init(hv_vmbus_service *serv);
(-)sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c (-73 / +678 lines)
Lines 38-43 Link Here
38
#include <sys/param.h>
38
#include <sys/param.h>
39
#include <sys/proc.h>
39
#include <sys/proc.h>
40
#include <sys/condvar.h>
40
#include <sys/condvar.h>
41
#include <sys/time.h>
41
#include <sys/systm.h>
42
#include <sys/systm.h>
42
#include <sys/sockio.h>
43
#include <sys/sockio.h>
43
#include <sys/mbuf.h>
44
#include <sys/mbuf.h>
Lines 53-60 Link Here
53
#include <sys/callout.h>
54
#include <sys/callout.h>
54
#include <vm/vm.h>
55
#include <vm/vm.h>
55
#include <vm/pmap.h>
56
#include <vm/pmap.h>
57
#include <vm/uma.h>
56
#include <sys/lock.h>
58
#include <sys/lock.h>
57
#include <sys/sema.h>
59
#include <sys/sema.h>
60
#include <sys/sglist.h>
61
#include <machine/bus.h>
62
#include <sys/bus_dma.h>
58
63
59
#include <cam/cam.h>
64
#include <cam/cam.h>
60
#include <cam/cam_ccb.h>
65
#include <cam/cam_ccb.h>
Lines 66-72 Link Here
66
#include <cam/scsi/scsi_all.h>
71
#include <cam/scsi/scsi_all.h>
67
#include <cam/scsi/scsi_message.h>
72
#include <cam/scsi/scsi_message.h>
68
73
69
70
#include <dev/hyperv/include/hyperv.h>
74
#include <dev/hyperv/include/hyperv.h>
71
#include "hv_vstorage.h"
75
#include "hv_vstorage.h"
72
76
Lines 77-84 Link Here
77
#define BLKVSC_MAX_IO_REQUESTS		STORVSC_MAX_IO_REQUESTS
81
#define BLKVSC_MAX_IO_REQUESTS		STORVSC_MAX_IO_REQUESTS
78
#define STORVSC_MAX_TARGETS		(2)
82
#define STORVSC_MAX_TARGETS		(2)
79
83
84
#define STORVSC_WIN7_MAJOR 4
85
#define STORVSC_WIN7_MINOR 2
86
87
#define STORVSC_WIN8_MAJOR 5
88
#define STORVSC_WIN8_MINOR 1
89
90
#define HV_ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
91
80
struct storvsc_softc;
92
struct storvsc_softc;
81
93
94
struct hv_sgl_node {
95
	LIST_ENTRY(hv_sgl_node) link;
96
	struct sglist *sgl_data;
97
};
98
99
struct hv_sgl_page_pool{
100
	LIST_HEAD(, hv_sgl_node) in_use_sgl_list;
101
	LIST_HEAD(, hv_sgl_node) free_sgl_list;
102
	boolean_t                is_init;
103
} g_hv_sgl_page_pool;
104
105
#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * HV_MAX_MULTIPAGE_BUFFER_COUNT
106
82
enum storvsc_request_type {
107
enum storvsc_request_type {
83
	WRITE_TYPE,
108
	WRITE_TYPE,
84
	READ_TYPE,
109
	READ_TYPE,
Lines 96-115 Link Here
96
	struct storvsc_softc *softc;
121
	struct storvsc_softc *softc;
97
	struct callout callout;
122
	struct callout callout;
98
	struct sema synch_sema; /*Synchronize the request/response if needed */
123
	struct sema synch_sema; /*Synchronize the request/response if needed */
124
	struct sglist *bounce_sgl;
125
	unsigned int bounce_sgl_count;
126
	uint64_t not_aligned_seg_bits;
99
};
127
};
100
128
101
struct storvsc_softc {
129
struct storvsc_softc {
102
	struct hv_device		*hs_dev;
130
	struct hv_device		*hs_dev;
103
        LIST_HEAD(, hv_storvsc_request) hs_free_list;
131
	LIST_HEAD(, hv_storvsc_request) hs_free_list;
104
        struct mtx      		hs_lock;
132
	struct mtx      		hs_lock;
105
        struct storvsc_driver_props     *hs_drv_props;
133
	struct storvsc_driver_props     *hs_drv_props;
106
        int 				hs_unit;
134
	int 				hs_unit;
107
        uint32_t         		hs_frozen;
135
	uint32_t         		hs_frozen;
108
        struct cam_sim  		*hs_sim;
136
	struct cam_sim  		*hs_sim;
109
        struct cam_path 		*hs_path;
137
	struct cam_path 		*hs_path;
110
	uint32_t			hs_num_out_reqs;
138
	uint32_t			hs_num_out_reqs;
111
	boolean_t			hs_destroy;
139
	boolean_t			hs_destroy;
112
	boolean_t			hs_drain_notify;
140
	boolean_t			hs_drain_notify;
141
	boolean_t			hs_open_multi_channel;
113
	struct sema 			hs_drain_sema;	
142
	struct sema 			hs_drain_sema;	
114
	struct hv_storvsc_request	hs_init_req;
143
	struct hv_storvsc_request	hs_init_req;
115
	struct hv_storvsc_request	hs_reset_req;
144
	struct hv_storvsc_request	hs_reset_req;
Lines 124-130 Link Here
124
 * The first can be tested by "sg_senddiag -vv /dev/daX",
153
 * The first can be tested by "sg_senddiag -vv /dev/daX",
125
 * and the second and third can be done by
154
 * and the second and third can be done by
126
 * "sg_wr_mode -v -p 08 -c 0,1a -m 0,ff /dev/daX".
155
 * "sg_wr_mode -v -p 08 -c 0,1a -m 0,ff /dev/daX".
127
 */ 
156
 */
128
#define HVS_TIMEOUT_TEST 0
157
#define HVS_TIMEOUT_TEST 0
129
158
130
/*
159
/*
Lines 138-144 Link Here
138
	char		*drv_name;
167
	char		*drv_name;
139
	char		*drv_desc;
168
	char		*drv_desc;
140
	uint8_t		drv_max_luns_per_target;
169
	uint8_t		drv_max_luns_per_target;
141
	uint8_t		drv_max_ios_per_target; 
170
	uint8_t		drv_max_ios_per_target;
142
	uint32_t	drv_ringbuffer_size;
171
	uint32_t	drv_ringbuffer_size;
143
};
172
};
144
173
Lines 150-155 Link Here
150
179
151
#define HS_MAX_ADAPTERS 10
180
#define HS_MAX_ADAPTERS 10
152
181
182
#define HV_STORAGE_SUPPORTS_MULTI_CHANNEL 0x1
183
153
/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
184
/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
154
static const hv_guid gStorVscDeviceType={
185
static const hv_guid gStorVscDeviceType={
155
	.data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
186
	.data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
Lines 171-176 Link Here
171
	 STORVSC_RINGBUFFER_SIZE}
202
	 STORVSC_RINGBUFFER_SIZE}
172
};
203
};
173
204
205
static int storvsc_current_major;
206
static int storvsc_current_minor;
207
174
/* static functions */
208
/* static functions */
175
static int storvsc_probe(device_t dev);
209
static int storvsc_probe(device_t dev);
176
static int storvsc_attach(device_t dev);
210
static int storvsc_attach(device_t dev);
Lines 177-183 Link Here
177
static int storvsc_detach(device_t dev);
211
static int storvsc_detach(device_t dev);
178
static void storvsc_poll(struct cam_sim * sim);
212
static void storvsc_poll(struct cam_sim * sim);
179
static void storvsc_action(struct cam_sim * sim, union ccb * ccb);
213
static void storvsc_action(struct cam_sim * sim, union ccb * ccb);
180
static void create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp);
214
static int create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp);
181
static void storvsc_free_request(struct storvsc_softc *sc, struct hv_storvsc_request *reqp);
215
static void storvsc_free_request(struct storvsc_softc *sc, struct hv_storvsc_request *reqp);
182
static enum hv_storage_type storvsc_get_storage_type(device_t dev);
216
static enum hv_storage_type storvsc_get_storage_type(device_t dev);
183
static void hv_storvsc_on_channel_callback(void *context);
217
static void hv_storvsc_on_channel_callback(void *context);
Lines 186-191 Link Here
186
					struct hv_storvsc_request *request);
220
					struct hv_storvsc_request *request);
187
static int hv_storvsc_connect_vsp(struct hv_device *device);
221
static int hv_storvsc_connect_vsp(struct hv_device *device);
188
static void storvsc_io_done(struct hv_storvsc_request *reqp);
222
static void storvsc_io_done(struct hv_storvsc_request *reqp);
223
void storvsc_copy_sgl_to_bounce_buf(struct sglist *bounce_sgl,
224
				bus_dma_segment_t *orig_sgl,
225
				unsigned int orig_sgl_count,
226
				uint64_t seg_bits);
227
void storvsc_copy_from_bounce_buf_to_sgl(bus_dma_segment_t *dest_sgl,
228
	                unsigned int dest_sgl_count,
229
				    struct sglist* src_sgl,
230
				    uint64_t seg_bits);
189
231
190
static device_method_t storvsc_methods[] = {
232
static device_method_t storvsc_methods[] = {
191
	/* Device interface */
233
	/* Device interface */
Lines 207-213 Link Here
207
249
208
250
209
/**
251
/**
210
 * The host is capable of sending messages to us that are 
252
 * The host is capable of sending messages to us that are
211
 * completely unsolicited. So, we need to address the race
253
 * completely unsolicited. So, we need to address the race
212
 * condition where we may be in the process of unloading the
254
 * condition where we may be in the process of unloading the
213
 * driver when the host may send us an unsolicited message.
255
 * driver when the host may send us an unsolicited message.
Lines 223-229 Link Here
223
 *    destroyed.
265
 *    destroyed.
224
 *
266
 *
225
 * 3. Once the device is marked as being destroyed, we only
267
 * 3. Once the device is marked as being destroyed, we only
226
 *    permit incoming traffic to properly account for 
268
 *    permit incoming traffic to properly account for
227
 *    packets already sent out.
269
 *    packets already sent out.
228
 */
270
 */
229
static inline struct storvsc_softc *
271
static inline struct storvsc_softc *
Lines 260-265 Link Here
260
}
302
}
261
303
262
/**
304
/**
305
 * @brief Callback handler, will be invoked when receive mutil-channel offer
306
 *
307
 * @param context  new multi-channel
308
 */
309
static void
310
storvsc_handle_sc_creation(void *context)
311
{
312
	hv_vmbus_channel *new_channel = NULL;
313
	struct hv_device *device = NULL;
314
	struct storvsc_softc *sc = NULL;
315
	struct vmstor_chan_props props;
316
	int ret = 0;
317
318
	new_channel = (hv_vmbus_channel *)context;
319
	device = new_channel->primary_channel->device;
320
	sc = get_stor_device(device, TRUE);
321
	if (NULL == sc){
322
		return;
323
	}
324
325
	if (FALSE == sc->hs_open_multi_channel){
326
		return;
327
	}
328
	
329
	memset(&props, 0, sizeof(struct vmstor_chan_props));
330
331
	ret = hv_vmbus_channel_open(new_channel,
332
			sc->hs_drv_props->drv_ringbuffer_size,
333
			sc->hs_drv_props->drv_ringbuffer_size,
334
			(void *)&props,
335
			sizeof(struct vmstor_chan_props),
336
			hv_storvsc_on_channel_callback,
337
			new_channel);
338
339
	return;
340
}
341
342
/**
343
 * @brief Send multi-channel creation request to host
344
 *
345
 * @param device  a Hyper-V device pointer
346
 * @param max_chans  the max channels supported by vmbus
347
 */
348
static void
349
storvsc_send_multichannel_request(struct hv_device *dev, int max_chans)
350
{
351
	struct storvsc_softc *sc = NULL;
352
	struct hv_storvsc_request *request = NULL;
353
	struct vstor_packet *vstor_packet = NULL;	
354
	int request_channels_cnt = 0;
355
	int ret;
356
357
	/* get multichannels count that need to create */
358
	request_channels_cnt = ((max_chans > mp_ncpus) ? mp_ncpus : max_chans);
359
360
	sc = get_stor_device(dev, TRUE);
361
	if (sc == NULL) {
362
		printf("Storvsc_error: get sc failed while send mutilchannel "
363
		    "request\n");
364
		return;
365
	}
366
367
	request = &sc->hs_init_req;
368
369
	/* Establish a handler for multi-channel */
370
	dev->channel->sc_creation_callback = storvsc_handle_sc_creation;
371
372
	/* request the host to create multi-channel */
373
	memset(request, 0, sizeof(struct hv_storvsc_request));
374
	
375
	sema_init(&request->synch_sema, 0, ("stor_synch_sema"));
376
377
	vstor_packet = &request->vstor_packet;
378
	
379
	vstor_packet->operation = VSTOR_OPERATION_CREATE_MULTI_CHANNELS;
380
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
381
	vstor_packet->u.multi_channels_cnt = request_channels_cnt;
382
383
	ret = hv_vmbus_channel_send_packet(
384
				dev->channel,
385
				vstor_packet,
386
				sizeof(struct vstor_packet),
387
				(uint64_t)(uintptr_t)request,
388
				HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
389
				HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
390
391
	/* wait for 500 ticks */
392
	ret = sema_timedwait(&request->synch_sema, 500);
393
	if (ret != 0) {		
394
		printf("Storvsc_error: create multi-channel timeout, %d\n",
395
		    ret);
396
		return;
397
	}
398
399
	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
400
	    vstor_packet->status != 0) {		
401
		printf("Storvsc_error: create multi-channel invalid operation "
402
		    "(%d) or statue (%u)\n",
403
		    vstor_packet->operation, vstor_packet->status);
404
		return;
405
	}
406
407
	sc->hs_open_multi_channel = TRUE;
408
409
	printf("Storvsc create multi-channel success!\n");
410
}
411
412
/**
263
 * @brief initialize channel connection to parent partition
413
 * @brief initialize channel connection to parent partition
264
 *
414
 *
265
 * @param dev  a Hyper-V device pointer
415
 * @param dev  a Hyper-V device pointer
Lines 272-277 Link Here
272
	struct hv_storvsc_request *request;
422
	struct hv_storvsc_request *request;
273
	struct vstor_packet *vstor_packet;
423
	struct vstor_packet *vstor_packet;
274
	struct storvsc_softc *sc;
424
	struct storvsc_softc *sc;
425
	uint16_t max_chans = 0;
426
	boolean_t is_support_multichannel = FALSE;
275
427
276
	sc = get_stor_device(dev, TRUE);
428
	sc = get_stor_device(dev, TRUE);
277
	if (sc == NULL) {
429
	if (sc == NULL) {
Lines 304-310 Link Here
304
		goto cleanup;
456
		goto cleanup;
305
	}
457
	}
306
458
307
	ret = sema_timedwait(&request->synch_sema, 500); /* KYS 5 seconds */
459
	/* wait 500 ticks */
460
	ret = sema_timedwait(&request->synch_sema, 500);
308
461
309
	if (ret != 0) {
462
	if (ret != 0) {
310
		goto cleanup;
463
		goto cleanup;
Lines 321-327 Link Here
321
	vstor_packet->operation = VSTOR_OPERATION_QUERYPROTOCOLVERSION;
474
	vstor_packet->operation = VSTOR_OPERATION_QUERYPROTOCOLVERSION;
322
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
475
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
323
476
324
	vstor_packet->u.version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT;
477
	vstor_packet->u.version.major_minor =
478
	    VMSTOR_PROTOCOL_VERSION(storvsc_current_major, storvsc_current_minor);
325
479
326
	/* revision is only significant for Windows guests */
480
	/* revision is only significant for Windows guests */
327
	vstor_packet->u.version.revision = 0;
481
	vstor_packet->u.version.revision = 0;
Lines 338-344 Link Here
338
		goto cleanup;
492
		goto cleanup;
339
	}
493
	}
340
494
341
	ret = sema_timedwait(&request->synch_sema, 500); /* KYS 5 seconds */
495
	/* wait 500 ticks */
496
	ret = sema_timedwait(&request->synch_sema, 500);
342
497
343
	if (ret) {
498
	if (ret) {
344
		goto cleanup;
499
		goto cleanup;
Lines 369-375 Link Here
369
		goto cleanup;
524
		goto cleanup;
370
	}
525
	}
371
526
372
	ret = sema_timedwait(&request->synch_sema, 500); /* KYS 5 seconds */
527
	/* wait 500 ticks */
528
	ret = sema_timedwait(&request->synch_sema, 500);
373
529
374
	if (ret != 0) {
530
	if (ret != 0) {
375
		goto cleanup;
531
		goto cleanup;
Lines 377-386 Link Here
377
533
378
	/* TODO: Check returned version */
534
	/* TODO: Check returned version */
379
	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
535
	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
380
		vstor_packet->status != 0) {
536
	    vstor_packet->status != 0) {
381
		goto cleanup;
537
		goto cleanup;
382
	}
538
	}
383
539
540
	/* multi-channels feature is supported by WIN8 and above version */
541
	max_chans = vstor_packet->u.chan_props.max_channel_cnt;
542
	if ((hv_vmbus_protocal_version != HV_VMBUS_VERSION_WIN7) &&
543
	    (hv_vmbus_protocal_version != HV_VMBUS_VERSION_WS2008)) {
544
		if (vstor_packet->u.chan_props.flags &
545
		    HV_STORAGE_SUPPORTS_MULTI_CHANNEL) {
546
			is_support_multichannel = TRUE;
547
		}
548
	}
549
384
	memset(vstor_packet, 0, sizeof(struct vstor_packet));
550
	memset(vstor_packet, 0, sizeof(struct vstor_packet));
385
	vstor_packet->operation = VSTOR_OPERATION_ENDINITIALIZATION;
551
	vstor_packet->operation = VSTOR_OPERATION_ENDINITIALIZATION;
386
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
552
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
Lines 397-403 Link Here
397
		goto cleanup;
563
		goto cleanup;
398
	}
564
	}
399
565
400
	ret = sema_timedwait(&request->synch_sema, 500); /* KYS 5 seconds */
566
	/* wait 500 ticks */
567
	ret = sema_timedwait(&request->synch_sema, 500);
401
568
402
	if (ret != 0) {
569
	if (ret != 0) {
403
		goto cleanup;
570
		goto cleanup;
Lines 404-413 Link Here
404
	}
571
	}
405
572
406
	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
573
	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
407
		vstor_packet->status != 0) {
574
	    vstor_packet->status != 0) {
408
		goto cleanup;
575
		goto cleanup;
409
	}
576
	}
410
577
578
	/*
579
	 * If multi-channel is supported, send multichannel create
580
	 * request to host.
581
	 */
582
	if (is_support_multichannel){
583
		storvsc_send_multichannel_request(dev, max_chans);
584
	}
585
411
cleanup:
586
cleanup:
412
	sema_destroy(&request->synch_sema);
587
	sema_destroy(&request->synch_sema);
413
	return (ret);
588
	return (ret);
Lines 443-451 Link Here
443
		(void *)&props,
618
		(void *)&props,
444
		sizeof(struct vmstor_chan_props),
619
		sizeof(struct vmstor_chan_props),
445
		hv_storvsc_on_channel_callback,
620
		hv_storvsc_on_channel_callback,
446
		dev);
621
		dev->channel);
447
622
448
449
	if (ret != 0) {
623
	if (ret != 0) {
450
		return ret;
624
		return ret;
451
	}
625
	}
Lines 498-504 Link Here
498
672
499
673
500
	/*
674
	/*
501
	 * At this point, all outstanding requests in the adapter 
675
	 * At this point, all outstanding requests in the adapter
502
	 * should have been flushed out and return to us
676
	 * should have been flushed out and return to us
503
	 */
677
	 */
504
678
Lines 521-526 Link Here
521
{
695
{
522
	struct storvsc_softc *sc;
696
	struct storvsc_softc *sc;
523
	struct vstor_packet *vstor_packet = &request->vstor_packet;
697
	struct vstor_packet *vstor_packet = &request->vstor_packet;
698
	struct hv_vmbus_channel* outgoing_channel = NULL;
524
	int ret = 0;
699
	int ret = 0;
525
700
526
	sc = get_stor_device(device, TRUE);
701
	sc = get_stor_device(device, TRUE);
Lines 539-557 Link Here
539
714
540
	vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB;
715
	vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB;
541
716
717
	outgoing_channel = vmbus_select_outgoing_channel(device->channel);
542
718
543
	mtx_unlock(&request->softc->hs_lock);
719
	mtx_unlock(&request->softc->hs_lock);
544
	if (request->data_buf.length) {
720
	if (request->data_buf.length) {
545
		ret = hv_vmbus_channel_send_packet_multipagebuffer(
721
		ret = hv_vmbus_channel_send_packet_multipagebuffer(
546
				device->channel,
722
				outgoing_channel,
547
				&request->data_buf,
723
				&request->data_buf,
548
				vstor_packet, 
724
				vstor_packet,
549
				sizeof(struct vstor_packet), 
725
				sizeof(struct vstor_packet),
550
				(uint64_t)(uintptr_t)request);
726
				(uint64_t)(uintptr_t)request);
551
727
552
	} else {
728
	} else {
553
		ret = hv_vmbus_channel_send_packet(
729
		ret = hv_vmbus_channel_send_packet(
554
			device->channel,
730
			outgoing_channel,
555
			vstor_packet,
731
			vstor_packet,
556
			sizeof(struct vstor_packet),
732
			sizeof(struct vstor_packet),
557
			(uint64_t)(uintptr_t)request,
733
			(uint64_t)(uintptr_t)request,
Lines 610-616 Link Here
610
hv_storvsc_on_channel_callback(void *context)
786
hv_storvsc_on_channel_callback(void *context)
611
{
787
{
612
	int ret = 0;
788
	int ret = 0;
613
	struct hv_device *device = (struct hv_device *)context;
789
	hv_vmbus_channel *channel = (hv_vmbus_channel *)context;
790
	struct hv_device *device = NULL;
614
	struct storvsc_softc *sc;
791
	struct storvsc_softc *sc;
615
	uint32_t bytes_recvd;
792
	uint32_t bytes_recvd;
616
	uint64_t request_id;
793
	uint64_t request_id;
Lines 618-632 Link Here
618
	struct hv_storvsc_request *request;
795
	struct hv_storvsc_request *request;
619
	struct vstor_packet *vstor_packet;
796
	struct vstor_packet *vstor_packet;
620
797
798
	if (channel->primary_channel != NULL){
799
		device = channel->primary_channel->device;
800
	} else {
801
		device = channel->device;
802
	}
803
804
	KASSERT(device, ("device"));
805
621
	sc = get_stor_device(device, FALSE);
806
	sc = get_stor_device(device, FALSE);
622
	if (sc == NULL) {
807
	if (sc == NULL) {
808
		printf("Storvsc_error: get stor device failed.\n");
623
		return;
809
		return;
624
	}
810
	}
625
811
626
	KASSERT(device, ("device"));
627
628
	ret = hv_vmbus_channel_recv_packet(
812
	ret = hv_vmbus_channel_recv_packet(
629
			device->channel,
813
			channel,
630
			packet,
814
			packet,
631
			roundup2(sizeof(struct vstor_packet), 8),
815
			roundup2(sizeof(struct vstor_packet), 8),
632
			&bytes_recvd,
816
			&bytes_recvd,
Lines 634-654 Link Here
634
818
635
	while ((ret == 0) && (bytes_recvd > 0)) {
819
	while ((ret == 0) && (bytes_recvd > 0)) {
636
		request = (struct hv_storvsc_request *)(uintptr_t)request_id;
820
		request = (struct hv_storvsc_request *)(uintptr_t)request_id;
637
		KASSERT(request, ("request"));
638
821
639
		if ((request == &sc->hs_init_req) ||
822
		if ((request == &sc->hs_init_req) ||
640
			(request == &sc->hs_reset_req)) {
823
			(request == &sc->hs_reset_req)) {
641
			memcpy(&request->vstor_packet, packet,
824
			memcpy(&request->vstor_packet, packet,
642
				   sizeof(struct vstor_packet));
825
				   sizeof(struct vstor_packet));
643
			sema_post(&request->synch_sema); 
826
			sema_post(&request->synch_sema);
644
		} else {
827
		} else {
645
			vstor_packet = (struct vstor_packet *)packet;
828
			vstor_packet = (struct vstor_packet *)packet;
646
			switch(vstor_packet->operation) {
829
			switch(vstor_packet->operation) {
647
			case VSTOR_OPERATION_COMPLETEIO:
830
			case VSTOR_OPERATION_COMPLETEIO:
831
				if (request == NULL) {
832
					printf("VMBUS: storvsc received a "
833
					    "packet with NULL request id in "
834
					    "COMPLETEIO operation. Panick!\n");
835
					KASSERT(request, ("request"));
836
				}
648
				hv_storvsc_on_iocompletion(sc,
837
				hv_storvsc_on_iocompletion(sc,
649
							vstor_packet, request);
838
							vstor_packet, request);
650
				break;
839
				break;
651
			case VSTOR_OPERATION_REMOVEDEVICE:
840
			case VSTOR_OPERATION_REMOVEDEVICE:
841
			case VSTOR_OPERATION_ENUMERATE_BUS:
842
				printf("VMBUS: storvsc operation %d not "
843
				    "implemented.\n", vstor_packet->operation);
652
				/* TODO: implement */
844
				/* TODO: implement */
653
				break;
845
				break;
654
			default:
846
			default:
Lines 656-662 Link Here
656
			}			
848
			}			
657
		}
849
		}
658
		ret = hv_vmbus_channel_recv_packet(
850
		ret = hv_vmbus_channel_recv_packet(
659
				device->channel,
851
				channel,
660
				packet,
852
				packet,
661
				roundup2(sizeof(struct vstor_packet), 8),
853
				roundup2(sizeof(struct vstor_packet), 8),
662
				&bytes_recvd,
854
				&bytes_recvd,
Lines 680-686 Link Here
680
{
872
{
681
	int ata_disk_enable = 0;
873
	int ata_disk_enable = 0;
682
	int ret	= ENXIO;
874
	int ret	= ENXIO;
683
875
	
876
	if ((HV_VMBUS_VERSION_WIN8 == hv_vmbus_protocal_version) ||
877
	    (HV_VMBUS_VERSION_WIN8_1 == hv_vmbus_protocal_version)){
878
		storvsc_current_major = STORVSC_WIN8_MAJOR;
879
		storvsc_current_minor = STORVSC_WIN8_MINOR;
880
	} else {
881
		storvsc_current_major = STORVSC_WIN7_MAJOR;
882
		storvsc_current_minor = STORVSC_WIN7_MINOR;
883
	}
884
	
684
	switch (storvsc_get_storage_type(dev)) {
885
	switch (storvsc_get_storage_type(dev)) {
685
	case DRIVER_BLKVSC:
886
	case DRIVER_BLKVSC:
686
		if(bootverbose)
887
		if(bootverbose)
Lines 721-729 Link Here
721
	enum hv_storage_type stor_type;
922
	enum hv_storage_type stor_type;
722
	struct storvsc_softc *sc;
923
	struct storvsc_softc *sc;
723
	struct cam_devq *devq;
924
	struct cam_devq *devq;
724
	int ret, i;
925
	int ret, i, j;
725
	struct hv_storvsc_request *reqp;
926
	struct hv_storvsc_request *reqp;
726
	struct root_hold_token *root_mount_token = NULL;
927
	struct root_hold_token *root_mount_token = NULL;
928
	struct hv_sgl_node *sgl_node = NULL;
929
	void *tmp_buff = NULL;
727
930
728
	/*
931
	/*
729
	 * We need to serialize storvsc attach calls.
932
	 * We need to serialize storvsc attach calls.
Lines 764-771 Link Here
764
		LIST_INSERT_HEAD(&sc->hs_free_list, reqp, link);
967
		LIST_INSERT_HEAD(&sc->hs_free_list, reqp, link);
765
	}
968
	}
766
969
970
	/* create sg-list page pool */
971
	if (FALSE == g_hv_sgl_page_pool.is_init){
972
		g_hv_sgl_page_pool.is_init = TRUE;
973
		LIST_INIT(&g_hv_sgl_page_pool.in_use_sgl_list);
974
		LIST_INIT(&g_hv_sgl_page_pool.free_sgl_list);
975
976
	    /* pre-create SG list, each SG list with HV_MAX_MULTIPAGE_BUFFER_COUNT segments, each segment has one page buffer */
977
		for (i = 0; i < STORVSC_MAX_IO_REQUESTS; i++){
978
	        sgl_node = malloc(sizeof(struct hv_sgl_node),
979
				          M_DEVBUF, M_WAITOK|M_ZERO);
980
			if (NULL == sgl_node){
981
				ret = ENOMEM;
982
	            goto cleanup;
983
			}
984
985
			sgl_node->sgl_data = sglist_alloc(HV_MAX_MULTIPAGE_BUFFER_COUNT,
986
				                      M_WAITOK|M_ZERO);
987
			if (NULL == sgl_node->sgl_data){
988
				ret = ENOMEM;
989
	            goto cleanup;
990
			}
991
992
			for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++){
993
				tmp_buff = malloc(PAGE_SIZE,
994
				            M_DEVBUF, M_WAITOK|M_ZERO);
995
				if (NULL == tmp_buff){
996
	    			ret = ENOMEM;
997
		            goto cleanup;
998
				}
999
1000
				sgl_node->sgl_data->sg_segs[j].ss_paddr = (vm_paddr_t)tmp_buff;
1001
			}
1002
1003
			LIST_INSERT_HEAD(&g_hv_sgl_page_pool.free_sgl_list, sgl_node, link);
1004
		}
1005
	}
1006
767
	sc->hs_destroy = FALSE;
1007
	sc->hs_destroy = FALSE;
768
	sc->hs_drain_notify = FALSE;
1008
	sc->hs_drain_notify = FALSE;
1009
	sc->hs_open_multi_channel = FALSE;
769
	sema_init(&sc->hs_drain_sema, 0, "Store Drain Sema");
1010
	sema_init(&sc->hs_drain_sema, 0, "Store Drain Sema");
770
1011
771
	ret = hv_storvsc_connect_vsp(hv_dev);
1012
	ret = hv_storvsc_connect_vsp(hv_dev);
Lines 834-839 Link Here
834
		LIST_REMOVE(reqp, link);
1075
		LIST_REMOVE(reqp, link);
835
		free(reqp, M_DEVBUF);
1076
		free(reqp, M_DEVBUF);
836
	}
1077
	}
1078
1079
	while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) {
1080
		sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
1081
		LIST_REMOVE(sgl_node, link);
1082
		for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++){
1083
			if (NULL != (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr){
1084
		        free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF);
1085
			}
1086
		}
1087
		sglist_free(sgl_node->sgl_data);
1088
		free(sgl_node, M_DEVBUF);
1089
	}
1090
837
	return (ret);
1091
	return (ret);
838
}
1092
}
839
1093
Lines 853-858 Link Here
853
	struct storvsc_softc *sc = device_get_softc(dev);
1107
	struct storvsc_softc *sc = device_get_softc(dev);
854
	struct hv_storvsc_request *reqp = NULL;
1108
	struct hv_storvsc_request *reqp = NULL;
855
	struct hv_device *hv_device = vmbus_get_devctx(dev);
1109
	struct hv_device *hv_device = vmbus_get_devctx(dev);
1110
	struct hv_sgl_node *sgl_node = NULL;
1111
	int j = 0;
856
1112
857
	mtx_lock(&hv_device->channel->inbound_lock);
1113
	mtx_lock(&hv_device->channel->inbound_lock);
858
	sc->hs_destroy = TRUE;
1114
	sc->hs_destroy = TRUE;
Lines 884-889 Link Here
884
		free(reqp, M_DEVBUF);
1140
		free(reqp, M_DEVBUF);
885
	}
1141
	}
886
	mtx_unlock(&sc->hs_lock);
1142
	mtx_unlock(&sc->hs_lock);
1143
1144
	while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) {
1145
		sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
1146
		LIST_REMOVE(sgl_node, link);
1147
		for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++){
1148
			if (NULL != (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr){
1149
		        free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF);
1150
			}
1151
		}
1152
		sglist_free(sgl_node->sgl_data);
1153
		free(sgl_node, M_DEVBUF);
1154
	}
1155
	
887
	return (0);
1156
	return (0);
888
}
1157
}
889
1158
Lines 939-945 Link Here
939
				ticks, __func__, (ret == 0)?
1208
				ticks, __func__, (ret == 0)?
940
				"IO return detected" :
1209
				"IO return detected" :
941
				"IO return not detected");
1210
				"IO return not detected");
942
		/* 
1211
		/*
943
		 * Now both the timer handler and io done are running
1212
		 * Now both the timer handler and io done are running
944
		 * simultaneously. We want to confirm the io done always
1213
		 * simultaneously. We want to confirm the io done always
945
		 * finishes after the timer handler exits. So reqp used by
1214
		 * finishes after the timer handler exits. So reqp used by
Lines 1024-1030 Link Here
1024
1293
1025
	mtx_assert(&sc->hs_lock, MA_OWNED);
1294
	mtx_assert(&sc->hs_lock, MA_OWNED);
1026
	mtx_unlock(&sc->hs_lock);
1295
	mtx_unlock(&sc->hs_lock);
1027
	hv_storvsc_on_channel_callback(sc->hs_dev);
1296
	hv_storvsc_on_channel_callback(sc->hs_dev->channel);
1028
	mtx_lock(&sc->hs_lock);
1297
	mtx_lock(&sc->hs_lock);
1029
}
1298
}
1030
1299
Lines 1152-1161 Link Here
1152
1421
1153
		bzero(reqp, sizeof(struct hv_storvsc_request));
1422
		bzero(reqp, sizeof(struct hv_storvsc_request));
1154
		reqp->softc = sc;
1423
		reqp->softc = sc;
1424
		
1425
		ccb->ccb_h.status |= CAM_SIM_QUEUED;
1426
		if ((res = create_storvsc_request(ccb, reqp)) != 0) {
1427
			ccb->ccb_h.status = CAM_REQ_INVALID;
1428
			xpt_done(ccb);
1429
			return;
1430
		}
1155
1431
1156
		ccb->ccb_h.status |= CAM_SIM_QUEUED;	    
1157
		create_storvsc_request(ccb, reqp);
1158
1159
		if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
1432
		if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
1160
			callout_init(&reqp->callout, CALLOUT_MPSAFE);
1433
			callout_init(&reqp->callout, CALLOUT_MPSAFE);
1161
			callout_reset(&reqp->callout,
1434
			callout_reset(&reqp->callout,
Lines 1195-1200 Link Here
1195
}
1468
}
1196
1469
1197
/**
1470
/**
1471
 * @brief destroy bounce buffer
1472
 *
1473
 * This function is responsible for destroy a Scatter/Gather list
1474
 * that create by storvsc_create_bounce_buffer()
1475
 *
1476
 * @param sgl- the Scatter/Gather need be destroy
1477
 * @param sg_count- page count of the SG list.
1478
 *
1479
 */
1480
static void
1481
storvsc_destroy_bounce_buffer(struct sglist *sgl)
1482
{
1483
	struct hv_sgl_node *sgl_node = NULL;
1484
1485
	sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.in_use_sgl_list);
1486
	LIST_REMOVE(sgl_node, link);
1487
	if (NULL == sgl_node) {
1488
		printf("storvsc error: not enough in use sgl\n");
1489
		return;
1490
	}
1491
	sgl_node->sgl_data = sgl;
1492
	LIST_INSERT_HEAD(&g_hv_sgl_page_pool.free_sgl_list, sgl_node, link);
1493
}
1494
1495
/**
1496
 * @brief create bounce buffer
1497
 *
1498
 * This function is responsible for create a Scatter/Gather list,
1499
 * which hold several pages that can be aligned with page size.
1500
 *
1501
 * @param seg_count- SG-list segments count
1502
 * @param write - if WRITE_TYPE, set SG list page used size to 0,
1503
 * otherwise set used size to page size.
1504
 *
1505
 * return NULL if create failed
1506
 */
1507
static struct sglist *
1508
storvsc_create_bounce_buffer(uint16_t seg_count, int write)
1509
{
1510
	int i = 0;
1511
	struct sglist *bounce_sgl = NULL;
1512
	unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
1513
	struct hv_sgl_node *sgl_node = NULL;	
1514
1515
	/* get struct sglist from free_sgl_list */
1516
	sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
1517
	LIST_REMOVE(sgl_node, link);
1518
	if (NULL == sgl_node) {
1519
		printf("storvsc error: not enough free sgl\n");
1520
		return NULL;
1521
	}
1522
	bounce_sgl = sgl_node->sgl_data;
1523
	LIST_INSERT_HEAD(&g_hv_sgl_page_pool.in_use_sgl_list, sgl_node, link);
1524
1525
	bounce_sgl->sg_maxseg = seg_count;
1526
	if (write == WRITE_TYPE) {
1527
		bounce_sgl->sg_nseg = 0;
1528
	} else {
1529
		bounce_sgl->sg_nseg = seg_count;
1530
	}
1531
1532
	for (i = 0; i < seg_count; i++) {
1533
	        bounce_sgl->sg_segs[i].ss_len = buf_len;
1534
	}
1535
1536
	return bounce_sgl;
1537
}
1538
1539
/**
1540
 * @brief copy data from SG list to bounce buffer
1541
 *
1542
 * This function is responsible for copy data from one SG list's segments
1543
 * to another SG list which used as bounce buffer.
1544
 *
1545
 * @param bounce_sgl - the destination SG list
1546
 * @param orig_sgl - the segment of the source SG list.
1547
 * @param orig_sgl_count - the count of segments.
1548
 * @param orig_sgl_count - indicate which segment need bounce buffer, set 1 means need.
1549
 *
1550
 */
1551
void storvsc_copy_sgl_to_bounce_buf(struct sglist *bounce_sgl,
1552
				bus_dma_segment_t *orig_sgl,
1553
				unsigned int orig_sgl_count,
1554
				uint64_t seg_bits)
1555
{
1556
	int src_sgl_idx = 0;
1557
1558
	for (src_sgl_idx = 0; src_sgl_idx < orig_sgl_count; src_sgl_idx++) {
1559
		if (seg_bits & (1 << src_sgl_idx)) {
1560
			memcpy((void*)bounce_sgl->sg_segs[src_sgl_idx].ss_paddr,
1561
			    (void*)orig_sgl[src_sgl_idx].ds_addr,
1562
			    orig_sgl[src_sgl_idx].ds_len);
1563
			bounce_sgl->sg_segs[src_sgl_idx].ss_len =
1564
			    orig_sgl[src_sgl_idx].ds_len;
1565
		}
1566
	}
1567
}
1568
1569
/**
1570
 * @brief copy data from SG list which used as bounce to another SG list
1571
 *
1572
 * This function is responsible for copy data from one SG list with bounce
1573
 * buffer to another SG list's segments.
1574
 *
1575
 * @param dest_sgl - the destination SG list's segments
1576
 * @param dest_sgl_count - the count of destination SG list's segment.
1577
 * @param src_sgl - the source SG list.
1578
 * @param seg_bits - indicate which segment used bounce buffer of src SG-list.
1579
 *
1580
 */
1581
void
1582
storvsc_copy_from_bounce_buf_to_sgl(bus_dma_segment_t *dest_sgl,
1583
	                unsigned int dest_sgl_count,
1584
				    struct sglist* src_sgl,
1585
				    uint64_t seg_bits)
1586
{
1587
	int sgl_idx = 0;
1588
	
1589
	for (sgl_idx = 0; sgl_idx < dest_sgl_count; sgl_idx++) {
1590
		if (seg_bits & (1 << sgl_idx)) {
1591
			memcpy((void*)(dest_sgl[sgl_idx].ds_addr),
1592
			    (void*)(src_sgl->sg_segs[sgl_idx].ss_paddr),
1593
			    src_sgl->sg_segs[sgl_idx].ss_len);
1594
		}
1595
	}
1596
}
1597
1598
/**
1599
 * @brief check SG list with bounce buffer or not
1600
 *
1601
 * This function is responsible for check if need bounce buffer for SG list.
1602
 *
1603
 * @param sgl - the SG list's segments
1604
 * @param sg_count - the count of SG list's segment.
1605
 * @param bits - segmengs number that need bounce buffer
1606
 *
1607
 * return -1 if SG list needless bounce buffer
1608
 */
1609
static int
1610
storvsc_check_bounce_buffer_sgl(bus_dma_segment_t *sgl, unsigned int sg_count, uint64_t *bits)
1611
{
1612
	int i = 0;
1613
	int offset = 0;
1614
	uint64_t phys_addr = 0;
1615
	uint64_t tmp_bits = 0;
1616
	boolean_t found_hole = FALSE;
1617
	boolean_t pre_aligned = TRUE;
1618
1619
	if (sg_count < 2){
1620
		return -1;
1621
	}
1622
1623
	*bits = 0;
1624
	
1625
	phys_addr = vtophys(sgl[0].ds_addr);
1626
	offset =  phys_addr - trunc_page(phys_addr);
1627
	if (offset){
1628
	    pre_aligned = FALSE;
1629
		tmp_bits |= 1;
1630
	}
1631
1632
	for (i = 1; i < sg_count; i++) {
1633
		phys_addr = vtophys(sgl[i].ds_addr);
1634
		offset =  phys_addr - trunc_page(phys_addr);
1635
1636
		if (0 == offset) {
1637
			if (FALSE == pre_aligned){
1638
				/*
1639
				 * This segment is aligned, if the previous
1640
				 * one is not aligned, find a hole
1641
				 */
1642
				found_hole = TRUE;
1643
			}
1644
			pre_aligned = TRUE;
1645
		} else {
1646
			tmp_bits |= 1 << i;
1647
			if (FALSE == pre_aligned) {
1648
				if (phys_addr != vtophys(sgl[i-1].ds_addr +
1649
				    sgl[i-1].ds_len)) {
1650
					/*
1651
					 * Check whether connect to previous
1652
					 * segment,if not, find the hole
1653
					 */
1654
					found_hole = TRUE;
1655
				}
1656
			} else {
1657
				found_hole = TRUE;
1658
			}
1659
			pre_aligned = FALSE;
1660
		}
1661
	}
1662
1663
	if (FALSE == found_hole) {
1664
		return -1;
1665
	} else {
1666
		*bits = tmp_bits;
1667
		return 0;
1668
	}
1669
}
1670
1671
/**
1198
 * @brief Fill in a request structure based on a CAM control block
1672
 * @brief Fill in a request structure based on a CAM control block
1199
 *
1673
 *
1200
 * Fills in a request structure based on the contents of a CAM control
1674
 * Fills in a request structure based on the contents of a CAM control
Lines 1204-1210 Link Here
1204
 * @param ccb pointer to a CAM contorl block
1678
 * @param ccb pointer to a CAM contorl block
1205
 * @param reqp pointer to a request structure
1679
 * @param reqp pointer to a request structure
1206
 */
1680
 */
1207
static void
1681
static int
1208
create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
1682
create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
1209
{
1683
{
1210
	struct ccb_scsiio *csio = &ccb->csio;
1684
	struct ccb_scsiio *csio = &ccb->csio;
Lines 1212-1217 Link Here
1212
	uint32_t bytes_to_copy = 0;
1686
	uint32_t bytes_to_copy = 0;
1213
	uint32_t pfn_num = 0;
1687
	uint32_t pfn_num = 0;
1214
	uint32_t pfn;
1688
	uint32_t pfn;
1689
	uint64_t not_aligned_seg_bits = 0;
1215
	
1690
	
1216
	/* refer to struct vmscsi_req for meanings of these two fields */
1691
	/* refer to struct vmscsi_req for meanings of these two fields */
1217
	reqp->vstor_packet.u.vm_srb.port =
1692
	reqp->vstor_packet.u.vm_srb.port =
Lines 1232-1249 Link Here
1232
	}
1707
	}
1233
1708
1234
	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
1709
	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
1235
    	case CAM_DIR_OUT: 
1710
	case CAM_DIR_OUT:
1236
    		reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE;
1711
		reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE;	
1237
    		break;
1712
		break;
1238
    	case CAM_DIR_IN:
1713
	case CAM_DIR_IN:
1239
    		reqp->vstor_packet.u.vm_srb.data_in = READ_TYPE;
1714
		reqp->vstor_packet.u.vm_srb.data_in = READ_TYPE;
1240
    		break;
1715
		break;
1241
    	case CAM_DIR_NONE:
1716
	case CAM_DIR_NONE:
1242
    		reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
1717
		reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
1243
    		break;
1718
		break;
1244
    	default:
1719
	default:
1245
    		reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
1720
		reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
1246
    		break;
1721
		break;
1247
	}
1722
	}
1248
1723
1249
	reqp->sense_data     = &csio->sense_data;
1724
	reqp->sense_data     = &csio->sense_data;
Lines 1250-1279 Link Here
1250
	reqp->sense_info_len = csio->sense_len;
1725
	reqp->sense_info_len = csio->sense_len;
1251
1726
1252
	reqp->ccb = ccb;
1727
	reqp->ccb = ccb;
1253
	/*
1728
1254
	KASSERT((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0,
1729
	if (0 == csio->dxfer_len) {
1255
			("ccb is scatter gather valid\n"));
1730
		return 0;
1256
	*/
1731
	}
1257
	if (csio->dxfer_len != 0) {
1732
1258
		reqp->data_buf.length = csio->dxfer_len;
1733
	reqp->data_buf.length = csio->dxfer_len;
1734
1735
	switch (ccb->ccb_h.flags & CAM_DATA_MASK) {
1736
	case CAM_DATA_VADDR:{
1259
		bytes_to_copy = csio->dxfer_len;
1737
		bytes_to_copy = csio->dxfer_len;
1260
		phys_addr = vtophys(csio->data_ptr);
1738
		phys_addr = vtophys(csio->data_ptr);
1261
		reqp->data_buf.offset = phys_addr - trunc_page(phys_addr);
1739
		reqp->data_buf.offset = phys_addr & PAGE_MASK;
1740
		
1741
		while (bytes_to_copy != 0) {
1742
			int bytes, page_offset;
1743
			phys_addr =
1744
			    vtophys(&csio->data_ptr[reqp->data_buf.length -
1745
			    bytes_to_copy]);
1746
			pfn = phys_addr >> PAGE_SHIFT;
1747
			reqp->data_buf.pfn_array[pfn_num] = pfn;
1748
			page_offset = phys_addr & PAGE_MASK;
1749
1750
			bytes = min(PAGE_SIZE - page_offset, bytes_to_copy);
1751
1752
			bytes_to_copy -= bytes;
1753
			pfn_num++;
1754
		}
1755
		break;
1262
	}
1756
	}
1757
	case CAM_DATA_SG:{
1758
		int i = 0;
1759
		int offset = 0;
1760
		bus_dma_segment_t *storvsc_sglist =
1761
		    (bus_dma_segment_t *)ccb->csio.data_ptr;
1762
		u_int16_t storvsc_sg_count = ccb->csio.sglist_cnt;
1263
1763
1264
	while (bytes_to_copy != 0) {
1764
		printf("Storvsc: get SG I/O operation, %d\n",
1265
		int bytes, page_offset;
1765
		    reqp->vstor_packet.u.vm_srb.data_in);
1266
		phys_addr = vtophys(&csio->data_ptr[reqp->data_buf.length -
1267
		                                    bytes_to_copy]);
1268
		pfn = phys_addr >> PAGE_SHIFT;
1269
		reqp->data_buf.pfn_array[pfn_num] = pfn;
1270
		page_offset = phys_addr - trunc_page(phys_addr);
1271
1766
1272
		bytes = min(PAGE_SIZE - page_offset, bytes_to_copy);
1767
		if (storvsc_sg_count > HV_MAX_MULTIPAGE_BUFFER_COUNT){
1768
			printf("Storvsc: %d segments is too much, "
1769
			    "only support %d segments\n",
1770
			    storvsc_sg_count, HV_MAX_MULTIPAGE_BUFFER_COUNT);
1771
			return EINVAL;
1772
		}
1273
1773
1274
		bytes_to_copy -= bytes;
1774
		/* check if we need to create bounce buffer */
1275
		pfn_num++;
1775
		if (storvsc_check_bounce_buffer_sgl(
1776
			          storvsc_sglist,
1777
			          storvsc_sg_count,
1778
			          &not_aligned_seg_bits) != -1) {
1779
			reqp->bounce_sgl =
1780
			    storvsc_create_bounce_buffer(storvsc_sg_count,
1781
			       reqp->vstor_packet.u.vm_srb.data_in);
1782
			if (NULL == reqp->bounce_sgl) {
1783
				printf("Storvsc_error: create bounce buffer failed.\n");
1784
				return ENOMEM;
1785
			}
1786
1787
			reqp->bounce_sgl_count = storvsc_sg_count;
1788
			reqp->not_aligned_seg_bits = not_aligned_seg_bits;
1789
1790
			/*
1791
			 * if it is write, we need copy the original data
1792
			 *to bounce buffer
1793
			 */
1794
			if (WRITE_TYPE == reqp->vstor_packet.u.vm_srb.data_in) {
1795
				storvsc_copy_sgl_to_bounce_buf(
1796
				    reqp->bounce_sgl,
1797
				    storvsc_sglist,
1798
				    storvsc_sg_count,
1799
				    reqp->not_aligned_seg_bits);
1800
			}
1801
1802
			/* transfer virtual address to physical frame number */
1803
			if (reqp->not_aligned_seg_bits & 0x1){
1804
 				phys_addr =
1805
					vtophys(reqp->bounce_sgl->sg_segs[0].ss_paddr);
1806
			}else{
1807
 				phys_addr =
1808
					vtophys(storvsc_sglist[0].ds_addr);
1809
			}
1810
			reqp->data_buf.offset = phys_addr & PAGE_MASK;
1811
1812
			pfn = phys_addr >> PAGE_SHIFT;
1813
			reqp->data_buf.pfn_array[0] = pfn;
1814
			
1815
			for (i = 1; i < storvsc_sg_count; i++) {
1816
				if (reqp->not_aligned_seg_bits & (1 << i)){
1817
					phys_addr =
1818
						vtophys(reqp->bounce_sgl->sg_segs[i].ss_paddr);
1819
				}
1820
				else{
1821
					phys_addr =
1822
						vtophys(storvsc_sglist[i].ds_addr);
1823
				}
1824
1825
				pfn = phys_addr >> PAGE_SHIFT;
1826
				reqp->data_buf.pfn_array[i] = pfn;
1827
			}
1828
		}
1829
		else {
1830
			phys_addr = vtophys(storvsc_sglist[0].ds_addr);
1831
1832
			reqp->data_buf.offset = phys_addr & PAGE_MASK;
1833
1834
			for (i = 0; i < storvsc_sg_count; i++){
1835
				phys_addr = vtophys(storvsc_sglist[i].ds_addr);
1836
				pfn = phys_addr >> PAGE_SHIFT;
1837
				reqp->data_buf.pfn_array[i] = pfn;
1838
			}
1839
1840
			/* check the last segment cross boundary or not */
1841
			offset = phys_addr & PAGE_MASK;
1842
			if (offset){
1843
				phys_addr =
1844
				    vtophys(storvsc_sglist[i-1].ds_addr +
1845
				    PAGE_SIZE - offset);
1846
				pfn = phys_addr >> PAGE_SHIFT;
1847
				reqp->data_buf.pfn_array[i] = pfn;
1848
			}
1849
			
1850
			reqp->bounce_sgl_count = 0;
1851
		}
1852
		break;
1276
	}
1853
	}
1854
	default:
1855
		printf("Unknow flags: %d\n", ccb->ccb_h.flags);
1856
		return EINVAL;
1857
	}
1858
1859
	return 0;
1277
}
1860
}
1278
1861
1279
/**
1862
/**
Lines 1292-1298 Link Here
1292
	struct ccb_scsiio *csio = &ccb->csio;
1875
	struct ccb_scsiio *csio = &ccb->csio;
1293
	struct storvsc_softc *sc = reqp->softc;
1876
	struct storvsc_softc *sc = reqp->softc;
1294
	struct vmscsi_req *vm_srb = &reqp->vstor_packet.u.vm_srb;
1877
	struct vmscsi_req *vm_srb = &reqp->vstor_packet.u.vm_srb;
1295
	
1878
	bus_dma_segment_t *ori_sglist = NULL;
1879
	int ori_sg_count = 0;
1880
1881
	/* destroy bounce buffer if it is used */
1882
	if (reqp->bounce_sgl_count) {
1883
		ori_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr;
1884
		ori_sg_count = ccb->csio.sglist_cnt;
1885
1886
		/*
1887
		 * If it is READ operation, we should copy back the data
1888
		 * to original SG list.
1889
		 */
1890
		if (READ_TYPE == reqp->vstor_packet.u.vm_srb.data_in) {
1891
			storvsc_copy_from_bounce_buf_to_sgl(ori_sglist,
1892
			    ori_sg_count,
1893
			    reqp->bounce_sgl,
1894
			    reqp->not_aligned_seg_bits);
1895
		}
1896
1897
		storvsc_destroy_bounce_buffer(reqp->bounce_sgl);
1898
		reqp->bounce_sgl_count = 0;
1899
	}
1900
		
1296
	if (reqp->retries > 0) {
1901
	if (reqp->retries > 0) {
1297
		mtx_lock(&sc->hs_lock);
1902
		mtx_lock(&sc->hs_lock);
1298
#if HVS_TIMEOUT_TEST
1903
#if HVS_TIMEOUT_TEST
Lines 1310-1316 Link Here
1310
		mtx_unlock(&sc->hs_lock);
1915
		mtx_unlock(&sc->hs_lock);
1311
	}
1916
	}
1312
1917
1313
	/* 
1918
	/*
1314
	 * callout_drain() will wait for the timer handler to finish
1919
	 * callout_drain() will wait for the timer handler to finish
1315
	 * if it is running. So we don't need any lock to synchronize
1920
	 * if it is running. So we don't need any lock to synchronize
1316
	 * between this routine and the timer handler.
1921
	 * between this routine and the timer handler.
(-)sys/dev/hyperv/storvsc/hv_vstorage.h (-3 / +13 lines)
Lines 53-59 Link Here
53
 * V1 RC > 2008/1/31          2.0
53
 * V1 RC > 2008/1/31          2.0
54
 */
54
 */
55
55
56
#define VMSTOR_PROTOCOL_VERSION_CURRENT	VMSTOR_PROTOCOL_VERSION(2, 0)
56
#define VMSTOR_PROTOCOL_VERSION_CURRENT	VMSTOR_PROTOCOL_VERSION(5, 1)
57
57
58
/**
58
/**
59
 *  Packet structure ops describing virtual storage requests.
59
 *  Packet structure ops describing virtual storage requests.
Lines 69-75 Link Here
69
	VSTOR_OPERATION_ENDINITIALIZATION     = 8,
69
	VSTOR_OPERATION_ENDINITIALIZATION     = 8,
70
	VSTOR_OPERATION_QUERYPROTOCOLVERSION  = 9,
70
	VSTOR_OPERATION_QUERYPROTOCOLVERSION  = 9,
71
	VSTOR_OPERATION_QUERYPROPERTIES       = 10,
71
	VSTOR_OPERATION_QUERYPROPERTIES       = 10,
72
	VSTOR_OPERATION_MAXIMUM               = 10
72
	VSTOR_OPERATION_ENUMERATE_BUS         = 11,
73
	VSTOR_OPERATION_FCHBA_DATA            = 12,
74
	VSTOR_OPERATION_CREATE_MULTI_CHANNELS = 13,
75
	VSTOR_OPERATION_MAXIMUM               = 13
73
};
76
};
74
77
75
78
Lines 123-132 Link Here
123
	uint8_t  path_id;
126
	uint8_t  path_id;
124
	uint8_t  target_id;
127
	uint8_t  target_id;
125
128
129
	uint16_t max_channel_cnt;
130
126
	/**
131
	/**
127
	 * Note: port number is only really known on the client side
132
	 * Note: port number is only really known on the client side
128
	 */
133
	 */
129
	uint32_t port;
134
	uint16_t port;
130
	uint32_t flags;
135
	uint32_t flags;
131
	uint32_t max_transfer_bytes;
136
	uint32_t max_transfer_bytes;
132
137
Lines 193-198 Link Here
193
	     * Used during version negotiations.
198
	     * Used during version negotiations.
194
	     */
199
	     */
195
	    struct vmstor_proto_ver version;
200
	    struct vmstor_proto_ver version;
201
202
	    /**
203
             * Number of multichannels to create
204
	     */
205
	    uint16_t multi_channels_cnt;
196
	} u;
206
	} u;
197
207
198
} __packed;
208
} __packed;
(-)sys/dev/hyperv/utilities/hv_util.c (+9 lines)
Lines 408-413 Link Here
408
	    }
408
	    }
409
	}
409
	}
410
410
411
	/*
412
	 * These services are not performance critical and do not need
413
	 * batched reading. Furthermore, some services such as KVP can
414
	 * only handle one message from the host at a time.
415
	 * Turn off batched reading for all util drivers before we open the
416
	 * channel.
417
	 */
418
	hv_set_channel_read_state(hv_dev->channel, FALSE);
419
411
	ret = hv_vmbus_channel_open(hv_dev->channel, 4 * PAGE_SIZE,
420
	ret = hv_vmbus_channel_open(hv_dev->channel, 4 * PAGE_SIZE,
412
		    4 * PAGE_SIZE, NULL, 0,
421
		    4 * PAGE_SIZE, NULL, 0,
413
		    service->callback, hv_dev->channel);
422
		    service->callback, hv_dev->channel);
(-)sys/dev/hyperv/utilities/hv_kvp.c (-5 / +6 lines)
Lines 55-60 Link Here
55
#include <sys/_null.h>
55
#include <sys/_null.h>
56
#include <sys/signal.h>
56
#include <sys/signal.h>
57
#include <sys/syslog.h>
57
#include <sys/syslog.h>
58
#include <sys/systm.h>
58
#include <sys/mutex.h>
59
#include <sys/mutex.h>
59
#include <net/if_arp.h>
60
#include <net/if_arp.h>
60
61
Lines 232-238 Link Here
232
	 */
233
	 */
233
	if ((icframe_vercnt >= 2) && (negop->icversion_data[1].major == 3)) {
234
	if ((icframe_vercnt >= 2) && (negop->icversion_data[1].major == 3)) {
234
		icframe_vercnt = 3;
235
		icframe_vercnt = 3;
235
		if (icmsg_vercnt >= 2)
236
		if (icmsg_vercnt > 2)
236
			icmsg_vercnt = 4;
237
			icmsg_vercnt = 4;
237
		else
238
		else
238
			icmsg_vercnt = 3;
239
			icmsg_vercnt = 3;
Lines 734-741 Link Here
734
		recvlen = 0;
735
		recvlen = 0;
735
		ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE,
736
		ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE,
736
			&recvlen, &requestid);
737
			&recvlen, &requestid);
737
		hv_kvp_log_info("%s: read: context %p, pending_cnt %ju ret =%d, recvlen=%d\n",
738
		hv_kvp_log_info("%s: read: context %p, pending_cnt %llu ret =%d, recvlen=%d\n",
738
			__func__, context, pending_cnt, ret, recvlen);
739
			__func__, context, (unsigned long long)pending_cnt, ret, recvlen);
739
	} 
740
	} 
740
}
741
}
741
742
Lines 813-821 Link Here
813
hv_kvp_dev_destroy(void)
814
hv_kvp_dev_destroy(void)
814
{
815
{
815
816
816
        if (daemon_task != NULL) {
817
	if (daemon_task != NULL) {
817
		PROC_LOCK(daemon_task);
818
		PROC_LOCK(daemon_task);
818
        	kern_psignal(daemon_task, SIGKILL);
819
		kern_psignal(daemon_task, SIGKILL);
819
		PROC_UNLOCK(daemon_task);
820
		PROC_UNLOCK(daemon_task);
820
	}
821
	}
821
	
822
	
(-)sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c (-118 / +226 lines)
Lines 53-59 Link Here
53
53
54
#include <machine/stdarg.h>
54
#include <machine/stdarg.h>
55
#include <machine/intr_machdep.h>
55
#include <machine/intr_machdep.h>
56
#include <machine/md_var.h>
57
#include <machine/segments.h>
56
#include <sys/pcpu.h>
58
#include <sys/pcpu.h>
59
#include <x86/apicvar.h>
57
60
58
#include "hv_vmbus_priv.h"
61
#include "hv_vmbus_priv.h"
59
62
Lines 60-74 Link Here
60
63
61
#define VMBUS_IRQ	0x5
64
#define VMBUS_IRQ	0x5
62
65
63
static struct intr_event *hv_msg_intr_event;
64
static struct intr_event *hv_event_intr_event;
65
static void *msg_swintr;
66
static void *event_swintr;
67
static device_t vmbus_devp;
66
static device_t vmbus_devp;
68
static void *vmbus_cookiep;
69
static int vmbus_rid;
70
struct resource *intr_res;
71
static int vmbus_irq = VMBUS_IRQ;
72
static int vmbus_inited;
67
static int vmbus_inited;
73
static hv_setup_args setup_args; /* only CPU 0 supported at this time */
68
static hv_setup_args setup_args; /* only CPU 0 supported at this time */
74
69
Lines 77-83 Link Here
77
 * the hypervisor.
72
 * the hypervisor.
78
 */
73
 */
79
static void
74
static void
80
vmbus_msg_swintr(void *dummy)
75
vmbus_msg_swintr(void *arg)
81
{
76
{
82
	int 			cpu;
77
	int 			cpu;
83
	void*			page_addr;
78
	void*			page_addr;
Lines 84-90 Link Here
84
	hv_vmbus_message*	msg;
79
	hv_vmbus_message*	msg;
85
	hv_vmbus_message*	copied;
80
	hv_vmbus_message*	copied;
86
81
87
	cpu = PCPU_GET(cpuid);
82
	cpu = (int)(long)arg;
83
	KASSERT(cpu <= mp_maxid, ("VMBUS: vmbus_msg_swintr: "
84
	    "cpu out of range!"));
85
88
	page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
86
	page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
89
	msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
87
	msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
90
88
Lines 130-146 Link Here
130
 *
128
 *
131
 * The purpose of this routine is to determine the type of VMBUS protocol
129
 * The purpose of this routine is to determine the type of VMBUS protocol
132
 * message to process - an event or a channel message.
130
 * message to process - an event or a channel message.
133
 * As this is an interrupt filter routine, the function runs in a very
134
 * restricted envinronment.  From the manpage for bus_setup_intr(9)
135
 *
136
 *   In this restricted environment, care must be taken to account for all
137
 *   races.  A careful analysis of races should be done as well.  It is gener-
138
 *   ally cheaper to take an extra interrupt, for example, than to protect
139
 *   variables with spinlocks.	Read, modify, write cycles of hardware regis-
140
 *   ters need to be carefully analyzed if other threads are accessing the
141
 *   same registers.
142
 */
131
 */
143
static int
132
static inline int
144
hv_vmbus_isr(void *unused) 
133
hv_vmbus_isr(void *unused) 
145
{
134
{
146
	int				cpu;
135
	int				cpu;
Lines 149-156 Link Here
149
	void*				page_addr;
138
	void*				page_addr;
150
139
151
	cpu = PCPU_GET(cpuid);
140
	cpu = PCPU_GET(cpuid);
152
	/* (Temporary limit) */
153
	KASSERT(cpu == 0, ("hv_vmbus_isr: Interrupt on CPU other than zero"));
154
141
155
	/*
142
	/*
156
	 * The Windows team has advised that we check for events
143
	 * The Windows team has advised that we check for events
Lines 162-170 Link Here
162
	event = (hv_vmbus_synic_event_flags*)
149
	event = (hv_vmbus_synic_event_flags*)
163
		    page_addr + HV_VMBUS_MESSAGE_SINT;
150
		    page_addr + HV_VMBUS_MESSAGE_SINT;
164
151
165
	/* Since we are a child, we only need to check bit 0 */
152
	if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
166
	if (synch_test_and_clear_bit(0, &event->flags32[0])) {
153
	    (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) {
167
		swi_sched(event_swintr, 0);
154
		/* Since we are a child, we only need to check bit 0 */
155
		if (synch_test_and_clear_bit(0, &event->flags32[0])) {
156
			swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0);
157
		}
158
	} else {
159
		/*
160
		 * On host with Win8 or above, we can directly look at
161
		 * the event page. If bit n is set, we have an interrupt 
162
		 * on the channel with id n.
163
		 * Directly schedule the event software interrupt on
164
		 * current cpu.
165
		 */
166
		swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0);
168
	}
167
	}
169
168
170
	/* Check if there are actual msgs to be process */
169
	/* Check if there are actual msgs to be process */
Lines 172-183 Link Here
172
	msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
171
	msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
173
172
174
	if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
173
	if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
175
		swi_sched(msg_swintr, 0);
174
		swi_sched(hv_vmbus_g_context.msg_swintr[cpu], 0);
176
	}
175
	}
177
176
178
	return FILTER_HANDLED;
177
	return FILTER_HANDLED;
179
}
178
}
180
179
180
#ifdef HV_DEBUG_INTR 
181
uint32_t hv_intr_count = 0;
182
#endif
183
uint32_t hv_vmbus_swintr_event_cpu[MAXCPU];
184
uint32_t hv_vmbus_intr_cpu[MAXCPU];
185
186
void
187
hv_vector_handler(struct trapframe *trap_frame)
188
{
189
#ifdef HV_DEBUG_INTR
190
	int cpu;
191
#endif
192
193
	/*
194
	 * Disable preemption.
195
	 */
196
	critical_enter();
197
198
#ifdef HV_DEBUG_INTR
199
	/*
200
	 * Do a little interrupt counting.
201
	 */
202
	cpu = PCPU_GET(cpuid);
203
	hv_vmbus_intr_cpu[cpu]++;
204
	hv_intr_count++;
205
#endif
206
207
	hv_vmbus_isr(NULL); 
208
209
	/*
210
	 * Enable preemption.
211
	 */
212
	critical_exit();
213
}
214
181
static int
215
static int
182
vmbus_read_ivar(
216
vmbus_read_ivar(
183
	device_t	dev,
217
	device_t	dev,
Lines 316-322 Link Here
316
	return (BUS_PROBE_NOWILDCARD);
350
	return (BUS_PROBE_NOWILDCARD);
317
}
351
}
318
352
353
extern inthand_t IDTVEC(rsvd), IDTVEC(hv_vmbus_callback);
354
319
/**
355
/**
356
 * @brief Find a free IDT slot and setup the interrupt handler.
357
 */
358
static int
359
vmbus_vector_alloc(void)
360
{
361
	int vector;
362
	uintptr_t func;
363
	struct gate_descriptor *ip;
364
365
	/*
366
	 * Search backwards form the highest IDT vector available for use
367
	 * as vmbus channel callback vector. We install 'hv_vmbus_callback'
368
	 * handler at that vector and use it to interrupt vcpus.
369
	 */
370
	vector = APIC_SPURIOUS_INT;
371
	while (--vector >= APIC_IPI_INTS) {
372
		ip = &idt[vector];
373
		func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
374
		if (func == (uintptr_t)&IDTVEC(rsvd)) {
375
#ifdef __i386__
376
			setidt(vector , &IDTVEC(hv_vmbus_callback), SDT_SYS386IGT,
377
			    SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
378
#else
379
			setidt(vector , IDTVEC(hv_vmbus_callback), SDT_SYSIGT,
380
			    SEL_KPL, 0);
381
#endif
382
383
			return (vector);
384
		}
385
	}
386
	return (0);
387
}
388
389
/**
390
 * @brief Restore the IDT slot to rsvd.
391
 */
392
static void
393
vmbus_vector_free(int vector)
394
{
395
        uintptr_t func;
396
        struct gate_descriptor *ip;
397
398
	if (vector == 0)
399
		return;
400
401
        KASSERT(vector >= APIC_IPI_INTS && vector < APIC_SPURIOUS_INT,
402
            ("invalid vector %d", vector));
403
404
        ip = &idt[vector];
405
        func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
406
        KASSERT(func == (uintptr_t)&IDTVEC(hv_vmbus_callback),
407
            ("invalid vector %d", vector));
408
409
        setidt(vector, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0);
410
}
411
412
/**
320
 * @brief Main vmbus driver initialization routine.
413
 * @brief Main vmbus driver initialization routine.
321
 *
414
 *
322
 * Here, we
415
 * Here, we
Lines 331-352 Link Here
331
static int
424
static int
332
vmbus_bus_init(void)
425
vmbus_bus_init(void)
333
{
426
{
334
	struct ioapic_intsrc {
427
	int i, j, n, ret;
335
		struct intsrc io_intsrc;
336
		u_int io_irq;
337
		u_int io_intpin:8;
338
		u_int io_vector:8;
339
		u_int io_cpu:8;
340
		u_int io_activehi:1;
341
		u_int io_edgetrigger:1;
342
		u_int io_masked:1;
343
		int io_bus:4;
344
		uint32_t io_lowreg;
345
	};
346
	int i, ret;
347
	unsigned int vector = 0;
348
	struct intsrc *isrc;
349
	struct ioapic_intsrc *intpin;
350
428
351
	if (vmbus_inited)
429
	if (vmbus_inited)
352
		return (0);
430
		return (0);
Lines 361-440 Link Here
361
		return (ret);
439
		return (ret);
362
	}
440
	}
363
441
364
	ret = swi_add(&hv_msg_intr_event, "hv_msg", vmbus_msg_swintr,
365
	    NULL, SWI_CLOCK, 0, &msg_swintr);
366
367
	if (ret)
368
	    goto cleanup;
369
370
	/*
442
	/*
371
	 * Message SW interrupt handler checks a per-CPU page and
443
	 * Find a free IDT slot for vmbus callback.
372
	 * thus the thread needs to be bound to CPU-0 - which is where
373
	 * all interrupts are processed.
374
	 */
444
	 */
375
	ret = intr_event_bind(hv_msg_intr_event, 0);
445
	hv_vmbus_g_context.hv_cb_vector = vmbus_vector_alloc();
376
446
377
	if (ret)
447
	if (hv_vmbus_g_context.hv_cb_vector == 0) {
378
		goto cleanup1;
448
		if(bootverbose)
449
			printf("Error VMBUS: Cannot find free IDT slot for "
450
			    "vmbus callback!\n");
451
		goto cleanup;
452
	}
379
453
380
	ret = swi_add(&hv_event_intr_event, "hv_event", hv_vmbus_on_events,
454
	if(bootverbose)
381
	    NULL, SWI_CLOCK, 0, &event_swintr);
455
		printf("VMBUS: vmbus callback vector %d\n",
456
		    hv_vmbus_g_context.hv_cb_vector);
382
457
383
	if (ret)
458
	/*
384
		goto cleanup1;
459
	 * Notify the hypervisor of our vector.
460
	 */
461
	setup_args.vector = hv_vmbus_g_context.hv_cb_vector;
385
462
386
	intr_res = bus_alloc_resource(vmbus_devp,
463
	CPU_FOREACH(j) {
387
	    SYS_RES_IRQ, &vmbus_rid, vmbus_irq, vmbus_irq, 1, RF_ACTIVE);
464
		hv_vmbus_intr_cpu[j] = 0;
465
		hv_vmbus_swintr_event_cpu[j] = 0;
466
		hv_vmbus_g_context.hv_event_intr_event[j] = NULL;
467
		hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;
468
		hv_vmbus_g_context.event_swintr[j] = NULL;
469
		hv_vmbus_g_context.msg_swintr[j] = NULL;
388
470
389
	if (intr_res == NULL) {
471
		for (i = 0; i < 2; i++)
390
		ret = ENOMEM; /* XXXKYS: Need a better errno */
472
			setup_args.page_buffers[2 * j + i] = NULL;
391
		goto cleanup2;
392
	}
473
	}
393
474
394
	/*
475
	/*
395
	 * Setup interrupt filter handler
476
	 * Per cpu setup.
396
	 */
477
	 */
397
	ret = bus_setup_intr(vmbus_devp, intr_res,
478
	CPU_FOREACH(j) {
398
	    INTR_TYPE_NET | INTR_MPSAFE, hv_vmbus_isr, NULL,
479
		/*
399
	    NULL, &vmbus_cookiep);
480
		 * Setup software interrupt thread and handler for msg handling.
481
		 */
482
		ret = swi_add(&hv_vmbus_g_context.hv_msg_intr_event[j],
483
		    "hv_msg", vmbus_msg_swintr, (void *)(long)j, SWI_CLOCK, 0,
484
		    &hv_vmbus_g_context.msg_swintr[j]);
485
		if (ret) {
486
			if(bootverbose)
487
				printf("VMBUS: failed to setup msg swi for "
488
				    "cpu %d\n", j);
489
			goto cleanup1;
490
		}
400
491
401
	if (ret != 0)
492
		/*
402
		goto cleanup3;
493
		 * Bind the swi thread to the cpu.
494
		 */
495
		ret = intr_event_bind(hv_vmbus_g_context.hv_msg_intr_event[j],
496
		    j);
497
	 	if (ret) {
498
			if(bootverbose)
499
				printf("VMBUS: failed to bind msg swi thread "
500
				    "to cpu %d\n", j);
501
			goto cleanup1;
502
		}
403
503
404
	ret = bus_bind_intr(vmbus_devp, intr_res, 0);
504
		/*
405
	if (ret != 0)
505
		 * Setup software interrupt thread and handler for
406
		goto cleanup4;
506
		 * event handling.
507
		 */
508
		ret = swi_add(&hv_vmbus_g_context.hv_event_intr_event[j],
509
		    "hv_event", hv_vmbus_on_events, (void *)(long)j,
510
		    SWI_CLOCK, 0, &hv_vmbus_g_context.event_swintr[j]);
511
		if (ret) {
512
			if(bootverbose)
513
				printf("VMBUS: failed to setup event swi for "
514
				    "cpu %d\n", j);
515
			goto cleanup1;
516
		}
407
517
408
	isrc = intr_lookup_source(vmbus_irq);
518
		/*
409
	if ((isrc == NULL) || (isrc->is_event == NULL)) {
519
		 * Prepare the per cpu msg and event pages to be called on each cpu.
410
		ret = EINVAL;
520
		 */
411
		goto cleanup4;
521
		for(i = 0; i < 2; i++) {
412
	}
522
			setup_args.page_buffers[2 * j + i] =
413
414
	/* vector = isrc->is_event->ie_vector; */
415
	intpin = (struct ioapic_intsrc *)isrc;
416
	vector = intpin->io_vector;
417
418
	if(bootverbose)
419
		printf("VMBUS: irq 0x%x vector 0x%x\n", vmbus_irq, vector);
420
421
	/**
422
	 * Notify the hypervisor of our irq.
423
	 */
424
	setup_args.vector = vector;
425
	for(i = 0; i < 2; i++) {
426
		setup_args.page_buffers[i] =
427
				malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
523
				malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
428
		if (setup_args.page_buffers[i] == NULL) {
524
			if (setup_args.page_buffers[2 * j + i] == NULL) {
429
			KASSERT(setup_args.page_buffers[i] != NULL,
525
				KASSERT(setup_args.page_buffers[2 * j + i] != NULL,
430
					("Error VMBUS: malloc failed!"));
526
					("Error VMBUS: malloc failed!"));
431
			if (i > 0)
527
				goto cleanup1;
432
				free(setup_args.page_buffers[0], M_DEVBUF);
528
			}
433
			goto cleanup4;
434
		}
529
		}
435
	}
530
	}
436
531
437
	/* only CPU #0 supported at this time */
532
	if (bootverbose)
533
		printf("VMBUS: Calling smp_rendezvous, smp_started = %d\n",
534
		    smp_started);
535
438
	smp_rendezvous(NULL, hv_vmbus_synic_init, NULL, &setup_args);
536
	smp_rendezvous(NULL, hv_vmbus_synic_init, NULL, &setup_args);
439
537
440
	/*
538
	/*
Lines 443-469 Link Here
443
	ret = hv_vmbus_connect();
541
	ret = hv_vmbus_connect();
444
542
445
	if (ret != 0)
543
	if (ret != 0)
446
	    goto cleanup4;
544
		goto cleanup1;
447
545
448
	hv_vmbus_request_channel_offers();
546
	hv_vmbus_request_channel_offers();
449
	return (ret);
547
	return (ret);
450
548
451
	cleanup4:
549
	cleanup1:
550
	/*
551
	 * Free pages alloc'ed
552
	 */
553
	for (n = 0; n < 2 * MAXCPU; n++)
554
		if (setup_args.page_buffers[n] != NULL)
555
			free(setup_args.page_buffers[n], M_DEVBUF);
452
556
453
	/*
557
	/*
454
	 * remove swi, bus and intr resource
558
	 * remove swi and vmbus callback vector;
455
	 */
559
	 */
456
	bus_teardown_intr(vmbus_devp, intr_res, vmbus_cookiep);
560
	CPU_FOREACH(j) {
561
		if (hv_vmbus_g_context.msg_swintr[j] != NULL)
562
			swi_remove(hv_vmbus_g_context.msg_swintr[j]);
563
		if (hv_vmbus_g_context.event_swintr[j] != NULL)
564
			swi_remove(hv_vmbus_g_context.event_swintr[j]);
565
		hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;	
566
		hv_vmbus_g_context.hv_event_intr_event[j] = NULL;	
567
	}
457
568
458
	cleanup3:
569
	vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector);
459
	bus_release_resource(vmbus_devp, SYS_RES_IRQ, vmbus_rid, intr_res);
460
570
461
	cleanup2:
462
	swi_remove(event_swintr);
463
464
	cleanup1:
465
	swi_remove(msg_swintr);
466
467
	cleanup:
571
	cleanup:
468
	hv_vmbus_cleanup();
572
	hv_vmbus_cleanup();
469
573
Lines 515-521 Link Here
515
619
516
	smp_rendezvous(NULL, hv_vmbus_synic_cleanup, NULL, NULL);
620
	smp_rendezvous(NULL, hv_vmbus_synic_cleanup, NULL, NULL);
517
621
518
	for(i = 0; i < 2; i++) {
622
	for(i = 0; i < 2 * MAXCPU; i++) {
519
		if (setup_args.page_buffers[i] != 0)
623
		if (setup_args.page_buffers[i] != 0)
520
			free(setup_args.page_buffers[i], M_DEVBUF);
624
			free(setup_args.page_buffers[i], M_DEVBUF);
521
	}
625
	}
Lines 522-535 Link Here
522
626
523
	hv_vmbus_cleanup();
627
	hv_vmbus_cleanup();
524
628
525
	/* remove swi, bus and intr resource */
629
	/* remove swi */
526
	bus_teardown_intr(vmbus_devp, intr_res, vmbus_cookiep);
630
	CPU_FOREACH(i) {
631
		if (hv_vmbus_g_context.msg_swintr[i] != NULL)
632
			swi_remove(hv_vmbus_g_context.msg_swintr[i]);
633
		if (hv_vmbus_g_context.event_swintr[i] != NULL)
634
			swi_remove(hv_vmbus_g_context.event_swintr[i]);
635
		hv_vmbus_g_context.hv_msg_intr_event[i] = NULL;	
636
		hv_vmbus_g_context.hv_event_intr_event[i] = NULL;	
637
	}
527
638
528
	bus_release_resource(vmbus_devp, SYS_RES_IRQ, vmbus_rid, intr_res);
639
	vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector);
529
640
530
	swi_remove(msg_swintr);
531
	swi_remove(event_swintr);
532
533
	return;
641
	return;
534
}
642
}
535
643
Lines 603-608 Link Here
603
DRIVER_MODULE(vmbus, nexus, vmbus_driver, vmbus_devclass, vmbus_modevent, 0);
711
DRIVER_MODULE(vmbus, nexus, vmbus_driver, vmbus_devclass, vmbus_modevent, 0);
604
MODULE_VERSION(vmbus,1);
712
MODULE_VERSION(vmbus,1);
605
713
606
/* TODO: We want to be earlier than SI_SUB_VFS */
714
/* We want to be started after SMP is initialized */
607
SYSINIT(vmb_init, SI_SUB_VFS, SI_ORDER_MIDDLE, vmbus_init, NULL);
715
SYSINIT(vmb_init, SI_SUB_SMP + 1, SI_ORDER_FIRST, vmbus_init, NULL);
608
716
(-)sys/dev/hyperv/vmbus/hv_vmbus_priv.h (-40 / +31 lines)
Lines 181-229 Link Here
181
181
182
#define HV_HYPERCALL_PARAM_ALIGN sizeof(uint64_t)
182
#define HV_HYPERCALL_PARAM_ALIGN sizeof(uint64_t)
183
183
184
/*
185
 *  Connection identifier type
186
 */
187
typedef union {
188
	uint32_t		as_uint32_t;
189
	struct {
190
		uint32_t	id:24;
191
		uint32_t	reserved:8;
192
	} u;
193
194
} __packed hv_vmbus_connection_id;
195
196
/*
197
 * Definition of the hv_vmbus_signal_event hypercall input structure
198
 */
199
typedef struct {
184
typedef struct {
200
	hv_vmbus_connection_id	connection_id;
201
	uint16_t		flag_number;
202
	uint16_t		rsvd_z;
203
} __packed hv_vmbus_input_signal_event;
204
205
typedef struct {
206
	uint64_t			align8;
207
	hv_vmbus_input_signal_event	event;
208
} __packed hv_vmbus_input_signal_event_buffer;
209
210
typedef struct {
211
	uint64_t	guest_id;
185
	uint64_t	guest_id;
212
	void*		hypercall_page;
186
	void*		hypercall_page;
213
	hv_bool_uint8_t	syn_ic_initialized;
187
	hv_bool_uint8_t	syn_ic_initialized;
188
189
	hv_vmbus_handle	syn_ic_msg_page[MAXCPU];
190
	hv_vmbus_handle	syn_ic_event_page[MAXCPU];
214
	/*
191
	/*
215
	 * This is used as an input param to HV_CALL_SIGNAL_EVENT hypercall.
192
	 * For FreeBSD cpuid to Hyper-V vcpuid mapping.
216
	 * The input param is immutable  in our usage and
217
	 * must be dynamic mem (vs stack or global).
218
	 */
193
	 */
219
	hv_vmbus_input_signal_event_buffer	*signal_event_buffer;
194
	uint32_t	hv_vcpu_index[MAXCPU];
220
	/*
195
	/*
221
	 * 8-bytes aligned of the buffer above
196
	 * Each cpu has its own software interrupt handler for channel
197
	 * event and msg handling.
222
	 */
198
	 */
223
	hv_vmbus_input_signal_event		*signal_event_param;
199
	struct intr_event		*hv_event_intr_event[MAXCPU];
224
200
	struct intr_event		*hv_msg_intr_event[MAXCPU];
225
	hv_vmbus_handle	syn_ic_msg_page[MAXCPU];
201
	void				*event_swintr[MAXCPU];
226
	hv_vmbus_handle	syn_ic_event_page[MAXCPU];
202
	void				*msg_swintr[MAXCPU];
203
	/*
204
	 * Host use this vector to intrrupt guest for vmbus channel
205
	 * event and msg.
206
	 */
207
	unsigned int			hv_cb_vector;
227
} hv_vmbus_context;
208
} hv_vmbus_context;
228
209
229
/*
210
/*
Lines 368-374 Link Here
368
	TAILQ_HEAD(, hv_vmbus_channel_msg_info)	channel_msg_anchor;
349
	TAILQ_HEAD(, hv_vmbus_channel_msg_info)	channel_msg_anchor;
369
	struct mtx				channel_msg_lock;
350
	struct mtx				channel_msg_lock;
370
	/**
351
	/**
371
	 * List of channels
352
	 * List of primary channels. Sub channels will be linked
353
	 * under their primary channel.
372
	 */
354
	 */
373
	TAILQ_HEAD(, hv_vmbus_channel)		channel_anchor;
355
	TAILQ_HEAD(, hv_vmbus_channel)		channel_anchor;
374
	struct mtx				channel_lock;
356
	struct mtx				channel_lock;
Lines 560-565 Link Here
560
	uint32_t	flags32[HV_EVENT_FLAGS_DWORD_COUNT];
542
	uint32_t	flags32[HV_EVENT_FLAGS_DWORD_COUNT];
561
} hv_vmbus_synic_event_flags;
543
} hv_vmbus_synic_event_flags;
562
544
545
/* MSR used to provide vcpu index */
546
#define	HV_X64_MSR_VP_INDEX   (0x40000002)
563
547
564
/*
548
/*
565
 * Define synthetic interrupt controller model specific registers
549
 * Define synthetic interrupt controller model specific registers
Lines 618-624 Link Here
618
int			hv_ring_buffer_write(
602
int			hv_ring_buffer_write(
619
				hv_vmbus_ring_buffer_info	*ring_info,
603
				hv_vmbus_ring_buffer_info	*ring_info,
620
				hv_vmbus_sg_buffer_list		sg_buffers[],
604
				hv_vmbus_sg_buffer_list		sg_buffers[],
621
				uint32_t			sg_buff_count);
605
				uint32_t			sg_buff_count,
606
				boolean_t			*need_sig);
622
607
623
int			hv_ring_buffer_peek(
608
int			hv_ring_buffer_peek(
624
				hv_vmbus_ring_buffer_info	*ring_info,
609
				hv_vmbus_ring_buffer_info	*ring_info,
Lines 638-643 Link Here
638
				hv_vmbus_ring_buffer_info	*ring_info,
623
				hv_vmbus_ring_buffer_info	*ring_info,
639
				char				*prefix);
624
				char				*prefix);
640
625
626
void			hv_ring_buffer_read_begin(
627
				hv_vmbus_ring_buffer_info	*ring_info);
628
629
uint32_t		hv_ring_buffer_read_end(
630
				hv_vmbus_ring_buffer_info	*ring_info);
631
641
hv_vmbus_channel*	hv_vmbus_allocate_channel(void);
632
hv_vmbus_channel*	hv_vmbus_allocate_channel(void);
642
void			hv_vmbus_free_vmbus_channel(hv_vmbus_channel *channel);
633
void			hv_vmbus_free_vmbus_channel(hv_vmbus_channel *channel);
643
void			hv_vmbus_on_channel_message(void *context);
634
void			hv_vmbus_on_channel_message(void *context);
Lines 652-658 Link Here
652
				void			*payload,
643
				void			*payload,
653
				size_t			payload_size);
644
				size_t			payload_size);
654
645
655
uint16_t		hv_vmbus_signal_event(void);
646
uint16_t		hv_vmbus_signal_event(void *con_id);
656
void			hv_vmbus_synic_init(void *irq_arg);
647
void			hv_vmbus_synic_init(void *irq_arg);
657
void			hv_vmbus_synic_cleanup(void *arg);
648
void			hv_vmbus_synic_cleanup(void *arg);
658
int			hv_vmbus_query_hypervisor_presence(void);
649
int			hv_vmbus_query_hypervisor_presence(void);
Lines 674-680 Link Here
674
int			hv_vmbus_connect(void);
665
int			hv_vmbus_connect(void);
675
int			hv_vmbus_disconnect(void);
666
int			hv_vmbus_disconnect(void);
676
int			hv_vmbus_post_message(void *buffer, size_t buf_size);
667
int			hv_vmbus_post_message(void *buffer, size_t buf_size);
677
int			hv_vmbus_set_event(uint32_t child_rel_id);
668
int			hv_vmbus_set_event(hv_vmbus_channel *channel);
678
void			hv_vmbus_on_events(void *);
669
void			hv_vmbus_on_events(void *);
679
670
680
671
Lines 718-724 Link Here
718
709
719
typedef struct {
710
typedef struct {
720
	unsigned int	vector;
711
	unsigned int	vector;
721
	void		*page_buffers[2];
712
	void		*page_buffers[2 * MAXCPU];
722
} hv_setup_args;
713
} hv_setup_args;
723
714
724
#endif  /* __HYPERV_PRIV_H__ */
715
#endif  /* __HYPERV_PRIV_H__ */
(-)sys/dev/hyperv/vmbus/hv_channel.c (-31 / +67 lines)
Lines 75-81 Link Here
75
			(uint32_t *)&monitor_page->
75
			(uint32_t *)&monitor_page->
76
				trigger_group[channel->monitor_group].u.pending);
76
				trigger_group[channel->monitor_group].u.pending);
77
	} else {
77
	} else {
78
		hv_vmbus_set_event(channel->offer_msg.child_rel_id);
78
		hv_vmbus_set_event(channel);
79
	}
79
	}
80
80
81
}
81
}
Lines 99-104 Link Here
99
	hv_vmbus_channel_open_channel*	open_msg;
99
	hv_vmbus_channel_open_channel*	open_msg;
100
	hv_vmbus_channel_msg_info* 	open_info;
100
	hv_vmbus_channel_msg_info* 	open_info;
101
101
102
	mtx_lock_spin(&new_channel->sc_lock);
103
	if (new_channel->state == HV_CHANNEL_OPEN_STATE) {
104
	    new_channel->state = HV_CHANNEL_OPENING_STATE;
105
	} else {
106
	    mtx_unlock_spin(&new_channel->sc_lock);
107
	    if(bootverbose)
108
		printf("VMBUS: Trying to open channel <%p> which in "
109
		    "%d state.\n", new_channel, new_channel->state);
110
	    return (EINVAL);
111
	}
112
	mtx_unlock_spin(&new_channel->sc_lock);
113
102
	new_channel->on_channel_callback = pfn_on_channel_callback;
114
	new_channel->on_channel_callback = pfn_on_channel_callback;
103
	new_channel->channel_callback_context = context;
115
	new_channel->channel_callback_context = context;
104
116
Lines 162-168 Link Here
162
		new_channel->ring_buffer_gpadl_handle;
174
		new_channel->ring_buffer_gpadl_handle;
163
	open_msg->downstream_ring_buffer_page_offset = send_ring_buffer_size
175
	open_msg->downstream_ring_buffer_page_offset = send_ring_buffer_size
164
		>> PAGE_SHIFT;
176
		>> PAGE_SHIFT;
165
	open_msg->server_context_area_gpadl_handle = 0;
177
	open_msg->target_vcpu = new_channel->target_vcpu;
166
178
167
	if (user_data_len)
179
	if (user_data_len)
168
		memcpy(open_msg->user_data, user_data, user_data_len);
180
		memcpy(open_msg->user_data, user_data, user_data_len);
Lines 182-191 Link Here
182
194
183
	ret = sema_timedwait(&open_info->wait_sema, 500); /* KYS 5 seconds */
195
	ret = sema_timedwait(&open_info->wait_sema, 500); /* KYS 5 seconds */
184
196
185
	if (ret)
197
	if (ret) {
198
	    if(bootverbose)
199
		printf("VMBUS: channel <%p> open timeout.\n", new_channel);
186
	    goto cleanup;
200
	    goto cleanup;
201
	}
187
202
188
	if (open_info->response.open_result.status == 0) {
203
	if (open_info->response.open_result.status == 0) {
204
	    new_channel->state = HV_CHANNEL_OPENED_STATE;
189
	    if(bootverbose)
205
	    if(bootverbose)
190
		printf("VMBUS: channel <%p> open success.\n", new_channel);
206
		printf("VMBUS: channel <%p> open success.\n", new_channel);
191
	} else {
207
	} else {
Lines 497-512 Link Here
497
	return (ret);
513
	return (ret);
498
}
514
}
499
515
500
/**
516
static void
501
 * @brief Close the specified channel
517
hv_vmbus_channel_close_internal(hv_vmbus_channel *channel)
502
 */
503
void
504
hv_vmbus_channel_close(hv_vmbus_channel *channel)
505
{
518
{
506
	int ret = 0;
519
	int ret = 0;
507
	hv_vmbus_channel_close_channel* msg;
520
	hv_vmbus_channel_close_channel* msg;
508
	hv_vmbus_channel_msg_info* info;
521
	hv_vmbus_channel_msg_info* info;
509
522
523
	channel->state = HV_CHANNEL_OPEN_STATE;
524
	channel->sc_creation_callback = NULL;
525
526
	/*
527
	 * Grab the lock to prevent race condition when a packet received
528
	 * and unloading driver is in the process.
529
	 */
510
	mtx_lock(&channel->inbound_lock);
530
	mtx_lock(&channel->inbound_lock);
511
	channel->on_channel_callback = NULL;
531
	channel->on_channel_callback = NULL;
512
	mtx_unlock(&channel->inbound_lock);
532
	mtx_unlock(&channel->inbound_lock);
Lines 545-567 Link Here
545
	    M_DEVBUF);
565
	    M_DEVBUF);
546
566
547
	free(info, M_DEVBUF);
567
	free(info, M_DEVBUF);
568
}
548
569
570
/**
571
 * @brief Close the specified channel
572
 */
573
void
574
hv_vmbus_channel_close(hv_vmbus_channel *channel)
575
{
576
	hv_vmbus_channel*	sub_channel;
577
578
	if (channel->primary_channel != NULL) {
579
		/*
580
		 * We only close multi-channels when the primary is
581
		 * closed.
582
		 */
583
		return;
584
	}
585
549
	/*
586
	/*
550
	 *  If we are closing the channel during an error path in
587
	 * Close all multi-channels first.
551
	 *  opening the channel, don't free the channel
552
	 *  since the caller will free the channel
553
	 */
588
	 */
554
	if (channel->state == HV_CHANNEL_OPEN_STATE) {
589
	TAILQ_FOREACH(sub_channel, &channel->sc_list_anchor,
555
		mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
590
	    sc_list_entry) {
556
		TAILQ_REMOVE(
591
		if (sub_channel->state != HV_CHANNEL_OPENED_STATE)
557
			&hv_vmbus_g_connection.channel_anchor,
592
			continue;
558
			channel,
593
		hv_vmbus_channel_close_internal(sub_channel);
559
			list_entry);
560
		mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
561
562
		hv_vmbus_free_vmbus_channel(channel);
563
	}
594
	}
564
595
	/*
596
	 * Then close the primary channel.
597
	 */
598
	hv_vmbus_channel_close_internal(channel);
565
}
599
}
566
600
567
/**
601
/**
Lines 581-586 Link Here
581
	uint32_t		packet_len;
615
	uint32_t		packet_len;
582
	uint64_t		aligned_data;
616
	uint64_t		aligned_data;
583
	uint32_t		packet_len_aligned;
617
	uint32_t		packet_len_aligned;
618
	boolean_t		need_sig;
584
	hv_vmbus_sg_buffer_list	buffer_list[3];
619
	hv_vmbus_sg_buffer_list	buffer_list[3];
585
620
586
	packet_len = sizeof(hv_vm_packet_descriptor) + buffer_len;
621
	packet_len = sizeof(hv_vm_packet_descriptor) + buffer_len;
Lines 604-615 Link Here
604
	buffer_list[2].data = &aligned_data;
639
	buffer_list[2].data = &aligned_data;
605
	buffer_list[2].length = packet_len_aligned - packet_len;
640
	buffer_list[2].length = packet_len_aligned - packet_len;
606
641
607
	ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3);
642
	ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3,
643
	    &need_sig);
608
644
609
	/* TODO: We should determine if this is optional */
645
	/* TODO: We should determine if this is optional */
610
	if (ret == 0
646
	if (ret == 0 && need_sig) {
611
		&& !hv_vmbus_get_ring_buffer_interrupt_mask(
612
			&channel->outbound)) {
613
		vmbus_channel_set_event(channel);
647
		vmbus_channel_set_event(channel);
614
	}
648
	}
615
649
Lines 632-637 Link Here
632
666
633
	int					ret = 0;
667
	int					ret = 0;
634
	int					i = 0;
668
	int					i = 0;
669
	boolean_t				need_sig;
635
	uint32_t				packet_len;
670
	uint32_t				packet_len;
636
	uint32_t				packetLen_aligned;
671
	uint32_t				packetLen_aligned;
637
	hv_vmbus_sg_buffer_list			buffer_list[3];
672
	hv_vmbus_sg_buffer_list			buffer_list[3];
Lines 675-685 Link Here
675
	buffer_list[2].data = &alignedData;
710
	buffer_list[2].data = &alignedData;
676
	buffer_list[2].length = packetLen_aligned - packet_len;
711
	buffer_list[2].length = packetLen_aligned - packet_len;
677
712
678
	ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3);
713
	ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3,
714
	    &need_sig);
679
715
680
	/* TODO: We should determine if this is optional */
716
	/* TODO: We should determine if this is optional */
681
	if (ret == 0 &&
717
	if (ret == 0 && need_sig) {
682
		!hv_vmbus_get_ring_buffer_interrupt_mask(&channel->outbound)) {
683
		vmbus_channel_set_event(channel);
718
		vmbus_channel_set_event(channel);
684
	}
719
	}
685
720
Lines 700-705 Link Here
700
735
701
	int			ret = 0;
736
	int			ret = 0;
702
	uint32_t		desc_size;
737
	uint32_t		desc_size;
738
	boolean_t		need_sig;
703
	uint32_t		packet_len;
739
	uint32_t		packet_len;
704
	uint32_t		packet_len_aligned;
740
	uint32_t		packet_len_aligned;
705
	uint32_t		pfn_count;
741
	uint32_t		pfn_count;
Lines 750-760 Link Here
750
	buffer_list[2].data = &aligned_data;
786
	buffer_list[2].data = &aligned_data;
751
	buffer_list[2].length = packet_len_aligned - packet_len;
787
	buffer_list[2].length = packet_len_aligned - packet_len;
752
788
753
	ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3);
789
	ret = hv_ring_buffer_write(&channel->outbound, buffer_list, 3,
790
	    &need_sig);
754
791
755
	/* TODO: We should determine if this is optional */
792
	/* TODO: We should determine if this is optional */
756
	if (ret == 0 &&
793
	if (ret == 0 && need_sig) {
757
	    !hv_vmbus_get_ring_buffer_interrupt_mask(&channel->outbound)) {
758
	    vmbus_channel_set_event(channel);
794
	    vmbus_channel_set_event(channel);
759
	}
795
	}
760
796
(-)sys/dev/hyperv/vmbus/hv_ring_buffer.c (-3 / +73 lines)
Lines 144-149 Link Here
144
	return (uint64_t) ring_info->ring_buffer->write_index << 32;
144
	return (uint64_t) ring_info->ring_buffer->write_index << 32;
145
}
145
}
146
146
147
void
148
hv_ring_buffer_read_begin(
149
	hv_vmbus_ring_buffer_info*	ring_info)
150
{
151
	ring_info->ring_buffer->interrupt_mask = 1;
152
	mb();
153
}
154
155
uint32_t
156
hv_ring_buffer_read_end(
157
	hv_vmbus_ring_buffer_info*	ring_info)
158
{
159
	uint32_t read, write;	
160
161
	ring_info->ring_buffer->interrupt_mask = 0;
162
	mb();
163
164
	/*
165
	 * Now check to see if the ring buffer is still empty.
166
	 * If it is not, we raced and we need to process new
167
	 * incoming messages.
168
	 */
169
	get_ring_buffer_avail_bytes(ring_info, &read, &write);
170
171
	return (read);
172
}
173
174
/*
175
 * When we write to the ring buffer, check if the host needs to
176
 * be signaled. Here is the details of this protocol:
177
 *
178
 *	1. The host guarantees that while it is draining the
179
 *	   ring buffer, it will set the interrupt_mask to
180
 *	   indicate it does not need to be interrupted when
181
 *	   new data is placed.
182
 *
183
 *	2. The host guarantees that it will completely drain
184
 *	   the ring buffer before exiting the read loop. Further,
185
 *	   once the ring buffer is empty, it will clear the
186
 *	   interrupt_mask and re-check to see if new data has
187
 *	   arrived.
188
 */
189
static boolean_t
190
hv_ring_buffer_needsig_on_write(
191
	uint32_t			old_write_location,
192
	hv_vmbus_ring_buffer_info*	rbi)
193
{
194
	mb();
195
	if (rbi->ring_buffer->interrupt_mask)
196
		return (FALSE);
197
198
	/* Read memory barrier */
199
	rmb();
200
	/*
201
	 * This is the only case we need to signal when the
202
	 * ring transitions from being empty to non-empty.
203
	 */
204
	if (old_write_location == rbi->ring_buffer->read_index)
205
		return (TRUE);
206
207
	return (FALSE);
208
}
209
147
static uint32_t	copy_to_ring_buffer(
210
static uint32_t	copy_to_ring_buffer(
148
			hv_vmbus_ring_buffer_info*	ring_info,
211
			hv_vmbus_ring_buffer_info*	ring_info,
149
			uint32_t			start_write_offset,
212
			uint32_t			start_write_offset,
Lines 204-214 Link Here
204
hv_ring_buffer_write(
267
hv_ring_buffer_write(
205
	hv_vmbus_ring_buffer_info*	out_ring_info,
268
	hv_vmbus_ring_buffer_info*	out_ring_info,
206
	hv_vmbus_sg_buffer_list		sg_buffers[],
269
	hv_vmbus_sg_buffer_list		sg_buffers[],
207
	uint32_t			sg_buffer_count)
270
	uint32_t			sg_buffer_count,
271
	boolean_t			*need_sig)
208
{
272
{
209
	int i = 0;
273
	int i = 0;
210
	uint32_t byte_avail_to_write;
274
	uint32_t byte_avail_to_write;
211
	uint32_t byte_avail_to_read;
275
	uint32_t byte_avail_to_read;
276
	uint32_t old_write_location;
212
	uint32_t total_bytes_to_write = 0;
277
	uint32_t total_bytes_to_write = 0;
213
278
214
	volatile uint32_t next_write_location;
279
	volatile uint32_t next_write_location;
Lines 242-247 Link Here
242
	 */
307
	 */
243
	next_write_location = get_next_write_location(out_ring_info);
308
	next_write_location = get_next_write_location(out_ring_info);
244
309
310
	old_write_location = next_write_location;
311
245
	for (i = 0; i < sg_buffer_count; i++) {
312
	for (i = 0; i < sg_buffer_count; i++) {
246
	    next_write_location = copy_to_ring_buffer(out_ring_info,
313
	    next_write_location = copy_to_ring_buffer(out_ring_info,
247
		next_write_location, (char *) sg_buffers[i].data,
314
		next_write_location, (char *) sg_buffers[i].data,
Lines 258-266 Link Here
258
		(char *) &prev_indices, sizeof(uint64_t));
325
		(char *) &prev_indices, sizeof(uint64_t));
259
326
260
	/*
327
	/*
261
	 * Make sure we flush all writes before updating the writeIndex
328
	 * Full memory barrier before upding the write index. 
262
	 */
329
	 */
263
	wmb();
330
	mb();
264
331
265
	/*
332
	/*
266
	 * Now, update the write location
333
	 * Now, update the write location
Lines 269-274 Link Here
269
336
270
	mtx_unlock_spin(&out_ring_info->ring_lock);
337
	mtx_unlock_spin(&out_ring_info->ring_lock);
271
338
339
	*need_sig = hv_ring_buffer_needsig_on_write(old_write_location,
340
	    out_ring_info);
341
272
	return (0);
342
	return (0);
273
}
343
}
274
344
(-)sys/dev/hyperv/vmbus/hv_channel_mgmt.c (-36 / +219 lines)
Lines 50-55 Link Here
50
static void vmbus_channel_on_offers_delivered(hv_vmbus_channel_msg_header* hdr);
50
static void vmbus_channel_on_offers_delivered(hv_vmbus_channel_msg_header* hdr);
51
static void vmbus_channel_on_version_response(hv_vmbus_channel_msg_header* hdr);
51
static void vmbus_channel_on_version_response(hv_vmbus_channel_msg_header* hdr);
52
static void vmbus_channel_process_offer(void *context);
52
static void vmbus_channel_process_offer(void *context);
53
struct hv_vmbus_channel* vmbus_select_outgoing_channel(struct hv_vmbus_channel *promary);
53
54
54
/**
55
/**
55
 * Channel message dispatch table
56
 * Channel message dispatch table
Lines 233-239 Link Here
233
	    return (NULL);
234
	    return (NULL);
234
235
235
	mtx_init(&channel->inbound_lock, "channel inbound", NULL, MTX_DEF);
236
	mtx_init(&channel->inbound_lock, "channel inbound", NULL, MTX_DEF);
237
	mtx_init(&channel->sc_lock, "vmbus multi channel", NULL, MTX_SPIN);
236
238
239
	TAILQ_INIT(&channel->sc_list_anchor);
240
237
	channel->control_work_queue = hv_work_queue_create("control");
241
	channel->control_work_queue = hv_work_queue_create("control");
238
242
239
	if (channel->control_work_queue == NULL) {
243
	if (channel->control_work_queue == NULL) {
Lines 262-267 Link Here
262
void
266
void
263
hv_vmbus_free_vmbus_channel(hv_vmbus_channel* channel)
267
hv_vmbus_free_vmbus_channel(hv_vmbus_channel* channel)
264
{
268
{
269
	mtx_destroy(&channel->sc_lock);
265
	mtx_destroy(&channel->inbound_lock);
270
	mtx_destroy(&channel->inbound_lock);
266
	/*
271
	/*
267
	 * We have to release the channel's workqueue/thread in
272
	 * We have to release the channel's workqueue/thread in
Lines 279-288 Link Here
279
static void
284
static void
280
vmbus_channel_process_offer(void *context)
285
vmbus_channel_process_offer(void *context)
281
{
286
{
282
	int			ret;
283
	hv_vmbus_channel*	new_channel;
287
	hv_vmbus_channel*	new_channel;
284
	boolean_t		f_new;
288
	boolean_t		f_new;
285
	hv_vmbus_channel*	channel;
289
	hv_vmbus_channel*	channel;
290
	int			ret;
286
291
287
	new_channel = (hv_vmbus_channel*) context;
292
	new_channel = (hv_vmbus_channel*) context;
288
	f_new = TRUE;
293
	f_new = TRUE;
Lines 296-328 Link Here
296
	TAILQ_FOREACH(channel, &hv_vmbus_g_connection.channel_anchor,
301
	TAILQ_FOREACH(channel, &hv_vmbus_g_connection.channel_anchor,
297
	    list_entry)
302
	    list_entry)
298
	{
303
	{
299
	    if (!memcmp(
304
		if (!memcmp( &channel->offer_msg.offer.interface_type,
300
		&channel->offer_msg.offer.interface_type,
305
		    &new_channel->offer_msg.offer.interface_type,
301
		&new_channel->offer_msg.offer.interface_type,
306
		    sizeof(hv_guid)) &&
302
		sizeof(hv_guid))
307
		    !memcmp(&channel->offer_msg.offer.interface_instance,
303
		&& !memcmp(
304
		    &channel->offer_msg.offer.interface_instance,
305
		    &new_channel->offer_msg.offer.interface_instance,
308
		    &new_channel->offer_msg.offer.interface_instance,
306
		    sizeof(hv_guid))) {
309
		    sizeof(hv_guid))) {
307
		f_new = FALSE;
310
			f_new = FALSE;
308
		break;
311
			break;
309
	    }
312
		}
310
	}
313
	}
311
314
312
	if (f_new) {
315
	if (f_new) {
313
	    /* Insert at tail */
316
		/* Insert at tail */
314
	    TAILQ_INSERT_TAIL(
317
		TAILQ_INSERT_TAIL(
315
		&hv_vmbus_g_connection.channel_anchor,
318
		    &hv_vmbus_g_connection.channel_anchor,
316
		new_channel,
319
		    new_channel,
317
		list_entry);
320
		    list_entry);
318
	}
321
	}
319
	mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
322
	mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
320
323
324
	/*XXX add new channel to percpu_list */
325
321
	if (!f_new) {
326
	if (!f_new) {
327
		/*
328
		 * Check if this is a sub channel.
329
		 */
330
		if (new_channel->offer_msg.offer.sub_channel_index != 0) {
331
			/*
332
			 * It is a sub channel offer, process it.
333
			 */
334
			new_channel->primary_channel = channel;
335
			mtx_lock_spin(&channel->sc_lock);
336
			TAILQ_INSERT_TAIL(
337
			    &channel->sc_list_anchor,
338
			    new_channel,
339
			    sc_list_entry);
340
			mtx_unlock_spin(&channel->sc_lock);
341
342
			/* Insert new channel into channel_anchor. */
343
			printf("Storvsc get multi-channel offer, rel=%u.\n",
344
			    new_channel->offer_msg.child_rel_id);	
345
			mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
346
			TAILQ_INSERT_TAIL(&hv_vmbus_g_connection.channel_anchor,
347
			    new_channel, list_entry);				
348
			mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
349
350
			if(bootverbose)
351
				printf("VMBUS: new multi-channel offer <%p>.\n",
352
				    new_channel);
353
354
			/*XXX add it to percpu_list */
355
356
			new_channel->state = HV_CHANNEL_OPEN_STATE;
357
			if (channel->sc_creation_callback != NULL) {
358
				channel->sc_creation_callback(new_channel);
359
			}
360
			return;
361
		}
362
322
	    hv_vmbus_free_vmbus_channel(new_channel);
363
	    hv_vmbus_free_vmbus_channel(new_channel);
323
	    return;
364
	    return;
324
	}
365
	}
325
366
367
	new_channel->state = HV_CHANNEL_OPEN_STATE;
368
326
	/*
369
	/*
327
	 * Start the process of binding this offer to the driver
370
	 * Start the process of binding this offer to the driver
328
	 * (We need to set the device field before calling
371
	 * (We need to set the device field before calling
Lines 333-345 Link Here
333
	    new_channel->offer_msg.offer.interface_instance, new_channel);
376
	    new_channel->offer_msg.offer.interface_instance, new_channel);
334
377
335
	/*
378
	/*
336
	 *  TODO - the HV_CHANNEL_OPEN_STATE flag should not be set below
337
	 *  but in the "open" channel request. The ret != 0 logic below
338
	 *  doesn't take into account that a channel
339
	 *  may have been opened successfully
340
	 */
341
342
	/*
343
	 * Add the new device to the bus. This will kick off device-driver
379
	 * Add the new device to the bus. This will kick off device-driver
344
	 * binding which eventually invokes the device driver's AddDevice()
380
	 * binding which eventually invokes the device driver's AddDevice()
345
	 * method.
381
	 * method.
Lines 346-367 Link Here
346
	 */
382
	 */
347
	ret = hv_vmbus_child_device_register(new_channel->device);
383
	ret = hv_vmbus_child_device_register(new_channel->device);
348
	if (ret != 0) {
384
	if (ret != 0) {
349
	    mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
385
		mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
350
	    TAILQ_REMOVE(
386
		TAILQ_REMOVE(
351
		&hv_vmbus_g_connection.channel_anchor,
387
		    &hv_vmbus_g_connection.channel_anchor,
352
		new_channel,
388
		    new_channel,
353
		list_entry);
389
		    list_entry);
354
	    mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
390
		mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
355
	    hv_vmbus_free_vmbus_channel(new_channel);
391
		hv_vmbus_free_vmbus_channel(new_channel);
356
	} else {
392
	}
357
	    /*
393
}
358
	     * This state is used to indicate a successful open
359
	     * so that when we do close the channel normally,
360
	     * we can clean up properly
361
	     */
362
	    new_channel->state = HV_CHANNEL_OPEN_STATE;
363
394
395
/**
396
 * Array of device guids that are performance critical. We try to distribute
397
 * the interrupt load for these devices across all online cpus. 
398
 */
399
static const hv_guid high_perf_devices[] = {
400
	{HV_NIC_GUID, },
401
	{HV_IDE_GUID, },
402
	{HV_SCSI_GUID, },
403
};
404
405
enum {
406
	PERF_CHN_NIC = 0,
407
	PERF_CHN_IDE,
408
	PERF_CHN_SCSI,
409
	MAX_PERF_CHN,
410
};
411
412
/*
413
 * We use this static number to distribute the channel interrupt load.
414
 */
415
static uint32_t next_vcpu;
416
417
/**
418
 * Starting with Win8, we can statically distribute the incoming
419
 * channel interrupt load by binding a channel to VCPU. We
420
 * implement here a simple round robin scheme for distributing
421
 * the interrupt load.
422
 * We will bind channels that are not performance critical to cpu 0 and
423
 * performance critical channels (IDE, SCSI and Network) will be uniformly
424
 * distributed across all available CPUs.
425
 */
426
static void
427
vmbus_channel_select_cpu(hv_vmbus_channel *channel, hv_guid *guid)
428
{
429
	uint32_t current_cpu;
430
	int i;
431
	boolean_t is_perf_channel = FALSE;
432
433
	for (i = PERF_CHN_NIC; i < MAX_PERF_CHN; i++) {
434
		if (!memcmp(guid->data, high_perf_devices[i].data,
435
		    sizeof(hv_guid))) {
436
			is_perf_channel = TRUE;
437
			break;
438
		}
364
	}
439
	}
440
441
	if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
442
	    (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) ||
443
	    (!is_perf_channel)) {
444
		/* Host's view of guest cpu */
445
		channel->target_vcpu = 0;
446
		/* Guest's own view of cpu */
447
		channel->target_cpu = 0;
448
		return;
449
	}
450
	/* mp_ncpus should have the number cpus currently online */
451
	current_cpu = (++next_vcpu % mp_ncpus);
452
	channel->target_cpu = current_cpu;
453
	channel->target_vcpu =
454
	    hv_vmbus_g_context.hv_vcpu_index[current_cpu];
455
	if (bootverbose)
456
		printf("VMBUS: Total online cpus %d, assign perf channel %d "
457
		    "to vcpu %d, cpu %d\n", mp_ncpus, i, channel->target_vcpu,
458
		    current_cpu);
365
}
459
}
366
460
367
/**
461
/**
Lines 391-396 Link Here
391
	if (new_channel == NULL)
485
	if (new_channel == NULL)
392
	    return;
486
	    return;
393
487
488
	/*
489
	 * By default we setup state to enable batched
490
	 * reading. A specific service can choose to
491
	 * disable this prior to opening the channel.
492
	 */
493
	new_channel->batched_reading = TRUE;
494
495
	new_channel->signal_event_param =
496
	    (hv_vmbus_input_signal_event *)
497
	    (HV_ALIGN_UP((unsigned long)
498
		&new_channel->signal_event_buffer,
499
		HV_HYPERCALL_PARAM_ALIGN));
500
501
 	new_channel->signal_event_param->connection_id.as_uint32_t = 0;	
502
	new_channel->signal_event_param->connection_id.u.id =
503
	    HV_VMBUS_EVENT_CONNECTION_ID;
504
	new_channel->signal_event_param->flag_number = 0;
505
	new_channel->signal_event_param->rsvd_z = 0;
506
507
	if (hv_vmbus_protocal_version != HV_VMBUS_VERSION_WS2008) {
508
		new_channel->is_dedicated_interrupt =
509
		    (offer->is_dedicated_interrupt != 0);
510
		new_channel->signal_event_param->connection_id.u.id =
511
		    offer->connection_id;
512
	}
513
514
	/*
515
	 * Bind the channel to a chosen cpu.
516
	 */
517
	vmbus_channel_select_cpu(new_channel,
518
	    &offer->offer.interface_type);
519
394
	memcpy(&new_channel->offer_msg, offer,
520
	memcpy(&new_channel->offer_msg, offer,
395
	    sizeof(hv_vmbus_channel_offer_channel));
521
	    sizeof(hv_vmbus_channel_offer_channel));
396
	new_channel->monitor_group = (uint8_t) offer->monitor_id / 32;
522
	new_channel->monitor_group = (uint8_t) offer->monitor_id / 32;
Lines 678-680 Link Here
678
	}
804
	}
679
	mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
805
	mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
680
}
806
}
807
808
/**
809
 * @brief Select the best outgoing channel
810
 * 
811
 * The channel whose vcpu binding is closest to the currect vcpu will
812
 * be selected.
813
 * If no multi-channel, always select primary channel
814
 * 
815
 * @param primary - primary channel
816
 */
817
struct hv_vmbus_channel *
818
vmbus_select_outgoing_channel(struct hv_vmbus_channel *primary)
819
{
820
	hv_vmbus_channel *new_channel = NULL;
821
	hv_vmbus_channel *outgoing_channel = primary;
822
	int old_cpu_distance = 0;
823
	int new_cpu_distance = 0;
824
	int cur_vcpu = 0;
825
	int smp_pro_id = PCPU_GET(cpuid);
826
827
	if (TAILQ_EMPTY(&primary->sc_list_anchor)) {
828
		return outgoing_channel;
829
	}
830
831
	if (smp_pro_id >= MAXCPU) {
832
		return outgoing_channel;
833
	}
834
835
	cur_vcpu = hv_vmbus_g_context.hv_vcpu_index[smp_pro_id];
836
	
837
	TAILQ_FOREACH(new_channel, &primary->sc_list_anchor, sc_list_entry) {
838
		if (new_channel->state != HV_CHANNEL_OPENED_STATE){
839
			continue;
840
		}
841
842
		if (new_channel->target_vcpu == cur_vcpu){
843
			return new_channel;
844
		}
845
846
		old_cpu_distance = ((outgoing_channel->target_vcpu > cur_vcpu) ?
847
		    (outgoing_channel->target_vcpu - cur_vcpu) :
848
		    (cur_vcpu - outgoing_channel->target_vcpu));
849
850
		new_cpu_distance = ((new_channel->target_vcpu > cur_vcpu) ?
851
		    (new_channel->target_vcpu - cur_vcpu) :
852
		    (cur_vcpu - new_channel->target_vcpu));
853
854
		if (old_cpu_distance < new_cpu_distance) {
855
			continue;
856
		}
857
858
		outgoing_channel = new_channel;
859
	}
860
861
	return outgoing_channel;
862
}
863
(-)sys/dev/hyperv/vmbus/hv_hv.c (-50 / +16 lines)
Lines 67-74 Link Here
67
hv_vmbus_context hv_vmbus_g_context = {
67
hv_vmbus_context hv_vmbus_g_context = {
68
	.syn_ic_initialized = FALSE,
68
	.syn_ic_initialized = FALSE,
69
	.hypercall_page = NULL,
69
	.hypercall_page = NULL,
70
	.signal_event_param = NULL,
71
	.signal_event_buffer = NULL,
72
};
70
};
73
71
74
static struct timecounter hv_timecounter = {
72
static struct timecounter hv_timecounter = {
Lines 256-283 Link Here
256
254
257
	hv_vmbus_g_context.hypercall_page = virt_addr;
255
	hv_vmbus_g_context.hypercall_page = virt_addr;
258
256
259
	/*
260
	 * Setup the global signal event param for the signal event hypercall
261
	 */
262
	hv_vmbus_g_context.signal_event_buffer =
263
	    malloc(sizeof(hv_vmbus_input_signal_event_buffer), M_DEVBUF,
264
		M_ZERO | M_NOWAIT);
265
	KASSERT(hv_vmbus_g_context.signal_event_buffer != NULL,
266
	    ("Error VMBUS: Failed to allocate signal_event_buffer\n"));
267
	if (hv_vmbus_g_context.signal_event_buffer == NULL)
268
	    goto cleanup;
269
270
	hv_vmbus_g_context.signal_event_param =
271
	    (hv_vmbus_input_signal_event*)
272
	    (HV_ALIGN_UP((unsigned long)
273
		hv_vmbus_g_context.signal_event_buffer,
274
		HV_HYPERCALL_PARAM_ALIGN));
275
	hv_vmbus_g_context.signal_event_param->connection_id.as_uint32_t = 0;
276
	hv_vmbus_g_context.signal_event_param->connection_id.u.id =
277
	    HV_VMBUS_EVENT_CONNECTION_ID;
278
	hv_vmbus_g_context.signal_event_param->flag_number = 0;
279
	hv_vmbus_g_context.signal_event_param->rsvd_z = 0;
280
	
281
	tc_init(&hv_timecounter); /* register virtual timecount */
257
	tc_init(&hv_timecounter); /* register virtual timecount */
282
	
258
	
283
	return (0);
259
	return (0);
Lines 303-314 Link Here
303
{
279
{
304
	hv_vmbus_x64_msr_hypercall_contents hypercall_msr;
280
	hv_vmbus_x64_msr_hypercall_contents hypercall_msr;
305
281
306
	if (hv_vmbus_g_context.signal_event_buffer != NULL) {
307
	    free(hv_vmbus_g_context.signal_event_buffer, M_DEVBUF);
308
	    hv_vmbus_g_context.signal_event_buffer = NULL;
309
	    hv_vmbus_g_context.signal_event_param = NULL;
310
	}
311
312
	if (hv_vmbus_g_context.guest_id == HV_FREEBSD_GUEST_ID) {
282
	if (hv_vmbus_g_context.guest_id == HV_FREEBSD_GUEST_ID) {
313
	    if (hv_vmbus_g_context.hypercall_page != NULL) {
283
	    if (hv_vmbus_g_context.hypercall_page != NULL) {
314
		hypercall_msr.as_uint64_t = 0;
284
		hypercall_msr.as_uint64_t = 0;
Lines 370-382 Link Here
370
 * event IPC. (This involves a hypercall.)
340
 * event IPC. (This involves a hypercall.)
371
 */
341
 */
372
hv_vmbus_status
342
hv_vmbus_status
373
hv_vmbus_signal_event()
343
hv_vmbus_signal_event(void *con_id)
374
{
344
{
375
	hv_vmbus_status status;
345
	hv_vmbus_status status;
376
346
377
	status = hv_vmbus_do_hypercall(
347
	status = hv_vmbus_do_hypercall(
378
		    HV_CALL_SIGNAL_EVENT,
348
		    HV_CALL_SIGNAL_EVENT,
379
		    hv_vmbus_g_context.signal_event_param,
349
		    con_id,
380
		    0) & 0xFFFF;
350
		    0) & 0xFFFF;
381
351
382
	return (status);
352
	return (status);
Lines 390-395 Link Here
390
360
391
{
361
{
392
	int			cpu;
362
	int			cpu;
363
	uint64_t		hv_vcpu_index;
393
	hv_vmbus_synic_simp	simp;
364
	hv_vmbus_synic_simp	simp;
394
	hv_vmbus_synic_siefp	siefp;
365
	hv_vmbus_synic_siefp	siefp;
395
	hv_vmbus_synic_scontrol sctrl;
366
	hv_vmbus_synic_scontrol sctrl;
Lines 403-425 Link Here
403
	    return;
374
	    return;
404
375
405
	/*
376
	/*
406
	 * KYS: Looks like we can only initialize on cpu0; don't we support
407
	 * SMP guests?
408
	 *
409
	 * TODO: Need to add SMP support for FreeBSD V9
410
	 */
411
412
	if (cpu != 0)
413
	    return;
414
415
	/*
416
	 * TODO: Check the version
377
	 * TODO: Check the version
417
	 */
378
	 */
418
	version = rdmsr(HV_X64_MSR_SVERSION);
379
	version = rdmsr(HV_X64_MSR_SVERSION);
419
420
	
380
	
421
	hv_vmbus_g_context.syn_ic_msg_page[cpu] = setup_args->page_buffers[0];
381
	hv_vmbus_g_context.syn_ic_msg_page[cpu] =
422
	hv_vmbus_g_context.syn_ic_event_page[cpu] = setup_args->page_buffers[1];
382
	    setup_args->page_buffers[2 * cpu];
383
	hv_vmbus_g_context.syn_ic_event_page[cpu] =
384
	    setup_args->page_buffers[2 * cpu + 1];
423
385
424
	/*
386
	/*
425
	 * Setup the Synic's message page
387
	 * Setup the Synic's message page
Lines 443-451 Link Here
443
	wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
405
	wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
444
406
445
	/*HV_SHARED_SINT_IDT_VECTOR + 0x20; */
407
	/*HV_SHARED_SINT_IDT_VECTOR + 0x20; */
408
	shared_sint.as_uint64_t = 0;
446
	shared_sint.u.vector = setup_args->vector;
409
	shared_sint.u.vector = setup_args->vector;
447
	shared_sint.u.masked = FALSE;
410
	shared_sint.u.masked = FALSE;
448
	shared_sint.u.auto_eoi = FALSE;
411
	shared_sint.u.auto_eoi = TRUE;
449
412
450
	wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
413
	wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
451
	    shared_sint.as_uint64_t);
414
	    shared_sint.as_uint64_t);
Lines 458-463 Link Here
458
421
459
	hv_vmbus_g_context.syn_ic_initialized = TRUE;
422
	hv_vmbus_g_context.syn_ic_initialized = TRUE;
460
423
424
	/*
425
	 * Set up the cpuid mapping from Hyper-V to FreeBSD.
426
	 * The array is indexed using FreeBSD cpuid.
427
	 */
428
	hv_vcpu_index = rdmsr(HV_X64_MSR_VP_INDEX);
429
	hv_vmbus_g_context.hv_vcpu_index[cpu] = (uint32_t)hv_vcpu_index;
430
461
	return;
431
	return;
462
}
432
}
463
433
Lines 469-482 Link Here
469
	hv_vmbus_synic_sint	shared_sint;
439
	hv_vmbus_synic_sint	shared_sint;
470
	hv_vmbus_synic_simp	simp;
440
	hv_vmbus_synic_simp	simp;
471
	hv_vmbus_synic_siefp	siefp;
441
	hv_vmbus_synic_siefp	siefp;
472
	int			cpu = PCPU_GET(cpuid);
473
442
474
	if (!hv_vmbus_g_context.syn_ic_initialized)
443
	if (!hv_vmbus_g_context.syn_ic_initialized)
475
	    return;
444
	    return;
476
445
477
	if (cpu != 0)
478
	    return; /* TODO: XXXKYS: SMP? */
479
480
	shared_sint.as_uint64_t = rdmsr(
446
	shared_sint.as_uint64_t = rdmsr(
481
	    HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT);
447
	    HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT);
482
448
(-)sys/dev/hyperv/vmbus/hv_connection.c (-72 / +195 lines)
Lines 45-58 Link Here
45
	{ .connect_state = HV_DISCONNECTED,
45
	{ .connect_state = HV_DISCONNECTED,
46
	  .next_gpadl_handle = 0xE1E10, };
46
	  .next_gpadl_handle = 0xE1E10, };
47
47
48
uint32_t hv_vmbus_protocal_version = HV_VMBUS_VERSION_WS2008;
49
50
static uint32_t
51
hv_vmbus_get_next_version(uint32_t current_ver)
52
{
53
	switch (current_ver) {
54
	case (HV_VMBUS_VERSION_WIN7):
55
		return 	HV_VMBUS_VERSION_WS2008;
56
57
	case (HV_VMBUS_VERSION_WIN8):
58
		return 	HV_VMBUS_VERSION_WIN7;
59
60
	case (HV_VMBUS_VERSION_WIN8_1):
61
		return 	HV_VMBUS_VERSION_WIN8;
62
63
	case (HV_VMBUS_VERSION_WS2008):
64
	default:
65
		return 	HV_VMBUS_VERSION_INVALID;
66
	}
67
}
68
48
/**
69
/**
70
 * Negotiate the highest supported hypervisor version.
71
 */
72
static int
73
hv_vmbus_negotiate_version(hv_vmbus_channel_msg_info *msg_info,
74
	uint32_t version)
75
{
76
	int					ret = 0;
77
	hv_vmbus_channel_initiate_contact	*msg;
78
79
	sema_init(&msg_info->wait_sema, 0, "Msg Info Sema");
80
	msg = (hv_vmbus_channel_initiate_contact*) msg_info->msg;
81
82
	msg->header.message_type = HV_CHANNEL_MESSAGE_INITIATED_CONTACT;
83
	msg->vmbus_version_requested = version;
84
85
	msg->interrupt_page = hv_get_phys_addr(
86
		hv_vmbus_g_connection.interrupt_page);
87
88
	msg->monitor_page_1 = hv_get_phys_addr(
89
		hv_vmbus_g_connection.monitor_pages);
90
91
	msg->monitor_page_2 =
92
		hv_get_phys_addr(
93
			((uint8_t *) hv_vmbus_g_connection.monitor_pages
94
			+ PAGE_SIZE));
95
96
	/**
97
	 * Add to list before we send the request since we may receive the
98
	 * response before returning from this routine
99
	 */
100
	mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
101
102
	TAILQ_INSERT_TAIL(
103
		&hv_vmbus_g_connection.channel_msg_anchor,
104
		msg_info,
105
		msg_list_entry);
106
107
	mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
108
109
	ret = hv_vmbus_post_message(
110
		msg,
111
		sizeof(hv_vmbus_channel_initiate_contact));
112
113
	if (ret != 0) {
114
		mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
115
		TAILQ_REMOVE(
116
			&hv_vmbus_g_connection.channel_msg_anchor,
117
			msg_info,
118
			msg_list_entry);
119
		mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
120
		return (ret);
121
	}
122
123
	/**
124
	 * Wait for the connection response
125
	 */
126
	ret = sema_timedwait(&msg_info->wait_sema, 500); /* KYS 5 seconds */
127
128
	mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
129
	TAILQ_REMOVE(
130
		&hv_vmbus_g_connection.channel_msg_anchor,
131
		msg_info,
132
		msg_list_entry);
133
	mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
134
135
	/**
136
	 * Check if successful
137
	 */
138
	if (msg_info->response.version_response.version_supported) {
139
		hv_vmbus_g_connection.connect_state = HV_CONNECTED;
140
	} else {
141
		ret = ECONNREFUSED;
142
	}
143
144
	return (ret);
145
}
146
147
/**
49
 * Send a connect request on the partition service connection
148
 * Send a connect request on the partition service connection
50
 */
149
 */
51
int
150
int
52
hv_vmbus_connect(void) {
151
hv_vmbus_connect(void) {
53
	int					ret = 0;
152
	int					ret = 0;
153
	uint32_t				version;
54
	hv_vmbus_channel_msg_info*		msg_info = NULL;
154
	hv_vmbus_channel_msg_info*		msg_info = NULL;
55
	hv_vmbus_channel_initiate_contact*	msg;
56
155
57
	/**
156
	/**
58
	 * Make sure we are not connecting or connected
157
	 * Make sure we are not connecting or connected
Lines 130-201 Link Here
130
	    goto cleanup;
229
	    goto cleanup;
131
	}
230
	}
132
231
133
	sema_init(&msg_info->wait_sema, 0, "Msg Info Sema");
232
	/*
134
	msg = (hv_vmbus_channel_initiate_contact*) msg_info->msg;
233
	 * Find the highest vmbus version number we can support.
135
136
	msg->header.message_type = HV_CHANNEL_MESSAGE_INITIATED_CONTACT;
137
	msg->vmbus_version_requested = HV_VMBUS_REVISION_NUMBER;
138
139
	msg->interrupt_page = hv_get_phys_addr(
140
		hv_vmbus_g_connection.interrupt_page);
141
142
	msg->monitor_page_1 = hv_get_phys_addr(
143
		hv_vmbus_g_connection.monitor_pages);
144
145
	msg->monitor_page_2 =
146
		hv_get_phys_addr(
147
			((uint8_t *) hv_vmbus_g_connection.monitor_pages
148
			+ PAGE_SIZE));
149
150
	/**
151
	 * Add to list before we send the request since we may receive the
152
	 * response before returning from this routine
153
	 */
234
	 */
154
	mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
235
	version = HV_VMBUS_VERSION_CURRENT;
155
236
156
	TAILQ_INSERT_TAIL(
237
	do {
157
		&hv_vmbus_g_connection.channel_msg_anchor,
238
		ret = hv_vmbus_negotiate_version(msg_info, version);
158
		msg_info,
239
		if (ret == EWOULDBLOCK) {
159
		msg_list_entry);
240
			/*
241
			 * We timed out.
242
			 */
243
			goto cleanup;
244
		}
160
245
161
	mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
246
		if (hv_vmbus_g_connection.connect_state == HV_CONNECTED)
247
			break;
162
248
163
	ret = hv_vmbus_post_message(
249
		version = hv_vmbus_get_next_version(version);
164
		msg,
250
	} while (version != HV_VMBUS_VERSION_INVALID);
165
		sizeof(hv_vmbus_channel_initiate_contact));
166
251
167
	if (ret != 0) {
252
	hv_vmbus_protocal_version = version;
168
		mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
253
	if (bootverbose)
169
		TAILQ_REMOVE(
254
		printf("VMBUS: Portocal Version: %d.%d\n",
170
			&hv_vmbus_g_connection.channel_msg_anchor,
255
		    version >> 16, version & 0xFFFF);
171
			msg_info,
172
			msg_list_entry);
173
		mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
174
		goto cleanup;
175
	}
176
256
177
	/**
178
	 * Wait for the connection response
179
	 */
180
	ret = sema_timedwait(&msg_info->wait_sema, 500); /* KYS 5 seconds */
181
182
	mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
183
	TAILQ_REMOVE(
184
		&hv_vmbus_g_connection.channel_msg_anchor,
185
		msg_info,
186
		msg_list_entry);
187
	mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
188
189
	/**
190
	 * Check if successful
191
	 */
192
	if (msg_info->response.version_response.version_supported) {
193
		hv_vmbus_g_connection.connect_state = HV_CONNECTED;
194
	} else {
195
		ret = ECONNREFUSED;
196
		goto cleanup;
197
	}
198
199
	sema_destroy(&msg_info->wait_sema);
257
	sema_destroy(&msg_info->wait_sema);
200
	free(msg_info, M_DEVBUF);
258
	free(msg_info, M_DEVBUF);
201
259
Lines 306-312 Link Here
306
static void
364
static void
307
VmbusProcessChannelEvent(uint32_t relid) 
365
VmbusProcessChannelEvent(uint32_t relid) 
308
{
366
{
367
	void* arg;
368
	uint32_t bytes_to_read;
309
	hv_vmbus_channel* channel;
369
	hv_vmbus_channel* channel;
370
	boolean_t is_batched_reading;
310
371
311
	/**
372
	/**
312
	 * Find the channel based on this relid and invokes
373
	 * Find the channel based on this relid and invokes
Lines 329-339 Link Here
329
390
330
	mtx_lock(&channel->inbound_lock);
391
	mtx_lock(&channel->inbound_lock);
331
	if (channel->on_channel_callback != NULL) {
392
	if (channel->on_channel_callback != NULL) {
332
		channel->on_channel_callback(channel->channel_callback_context);
393
		arg = channel->channel_callback_context;
394
		is_batched_reading = channel->batched_reading;
395
		/*
396
		 * Optimize host to guest signaling by ensuring:
397
		 * 1. While reading the channel, we disable interrupts from
398
		 *    host.
399
		 * 2. Ensure that we process all posted messages from the host
400
		 *    before returning from this callback.
401
		 * 3. Once we return, enable signaling from the host. Once this
402
		 *    state is set we check to see if additional packets are
403
		 *    available to read. In this case we repeat the process.
404
		 */
405
		do {
406
			if (is_batched_reading)
407
				hv_ring_buffer_read_begin(&channel->inbound);
408
409
			channel->on_channel_callback(arg);
410
411
			if (is_batched_reading)
412
				bytes_to_read =
413
				    hv_ring_buffer_read_end(&channel->inbound);
414
			else
415
				bytes_to_read = 0;
416
		} while (is_batched_reading && (bytes_to_read != 0));
333
	}
417
	}
334
	mtx_unlock(&channel->inbound_lock);
418
	mtx_unlock(&channel->inbound_lock);
335
}
419
}
336
420
421
#ifdef HV_DEBUG_INTR
422
extern uint32_t hv_intr_count;
423
extern uint32_t hv_vmbus_swintr_event_cpu[MAXCPU];
424
extern uint32_t hv_vmbus_intr_cpu[MAXCPU];
425
#endif
426
337
/**
427
/**
338
 * Handler for events
428
 * Handler for events
339
 */
429
 */
Lines 340-358 Link Here
340
void
430
void
341
hv_vmbus_on_events(void *arg) 
431
hv_vmbus_on_events(void *arg) 
342
{
432
{
433
	int bit;
434
	int cpu;
343
	int dword;
435
	int dword;
344
	int bit;
436
	void *page_addr;
437
	uint32_t* recv_interrupt_page = NULL;
345
	int rel_id;
438
	int rel_id;
346
	int maxdword = HV_MAX_NUM_CHANNELS_SUPPORTED >> 5;
439
	int maxdword;
440
	hv_vmbus_synic_event_flags *event;
347
	/* int maxdword = PAGE_SIZE >> 3; */
441
	/* int maxdword = PAGE_SIZE >> 3; */
348
442
349
	/*
443
	cpu = (int)(long)arg;
350
	 * receive size is 1/2 page and divide that by 4 bytes
444
	KASSERT(cpu <= mp_maxid, ("VMBUS: hv_vmbus_on_events: "
351
	 */
445
	    "cpu out of range!"));
352
446
353
	uint32_t* recv_interrupt_page =
447
#ifdef HV_DEBUG_INTR
354
	    hv_vmbus_g_connection.recv_interrupt_page;
448
	int i;
449
	hv_vmbus_swintr_event_cpu[cpu]++;
450
	if (hv_intr_count % 10000 == 0) {
451
                printf("VMBUS: Total interrupt %d\n", hv_intr_count);
452
                for (i = 0; i < mp_ncpus; i++)
453
                        printf("VMBUS: hw cpu[%d]: %d, event sw intr cpu[%d]: %d\n",
454
			    i, hv_vmbus_intr_cpu[i], i, hv_vmbus_swintr_event_cpu[i]);
455
        }
456
#endif
355
457
458
	if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
459
	    (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) {
460
		maxdword = HV_MAX_NUM_CHANNELS_SUPPORTED >> 5;
461
		/*
462
		 * receive size is 1/2 page and divide that by 4 bytes
463
		 */
464
		recv_interrupt_page =
465
		    hv_vmbus_g_connection.recv_interrupt_page;
466
	} else {
467
		/*
468
		 * On Host with Win8 or above, the event page can be
469
		 * checked directly to get the id of the channel
470
		 * that has the pending interrupt.
471
		 */
472
		maxdword = HV_EVENT_FLAGS_DWORD_COUNT;
473
		page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu];
474
		event = (hv_vmbus_synic_event_flags *)
475
		    page_addr + HV_VMBUS_MESSAGE_SINT;
476
		recv_interrupt_page = event->flags32;
477
	}
478
356
	/*
479
	/*
357
	 * Check events
480
	 * Check events
358
	 */
481
	 */
Lines 416-423 Link Here
416
 * Send an event notification to the parent
539
 * Send an event notification to the parent
417
 */
540
 */
418
int
541
int
419
hv_vmbus_set_event(uint32_t child_rel_id) {
542
hv_vmbus_set_event(hv_vmbus_channel *channel) {
420
	int ret = 0;
543
	int ret = 0;
544
	uint32_t child_rel_id = channel->offer_msg.child_rel_id;
421
545
422
	/* Each uint32_t represents 32 channels */
546
	/* Each uint32_t represents 32 channels */
423
547
Lines 424-431 Link Here
424
	synch_set_bit(child_rel_id & 31,
548
	synch_set_bit(child_rel_id & 31,
425
		(((uint32_t *)hv_vmbus_g_connection.send_interrupt_page
549
		(((uint32_t *)hv_vmbus_g_connection.send_interrupt_page
426
			+ (child_rel_id >> 5))));
550
			+ (child_rel_id >> 5))));
427
	ret = hv_vmbus_signal_event();
551
	ret = hv_vmbus_signal_event(channel->signal_event_param);
428
552
429
	return (ret);
553
	return (ret);
430
}
554
}
431
(-)sys/x86/include/apicvar.h (+1 lines)
Lines 416-421 Link Here
416
void	lapic_handle_intr(int vector, struct trapframe *frame);
416
void	lapic_handle_intr(int vector, struct trapframe *frame);
417
void	lapic_handle_timer(struct trapframe *frame);
417
void	lapic_handle_timer(struct trapframe *frame);
418
void	xen_intr_handle_upcall(struct trapframe *frame);
418
void	xen_intr_handle_upcall(struct trapframe *frame);
419
void	hv_vector_handler(struct trapframe *frame);
419
420
420
#endif /* !LOCORE */
421
#endif /* !LOCORE */
421
#endif /* _X86_APICVAR_H_ */
422
#endif /* _X86_APICVAR_H_ */
(-)sys/i386/i386/apic_vector.s (+17 lines)
Lines 157-162 Link Here
157
	jmp	doreti
157
	jmp	doreti
158
#endif
158
#endif
159
159
160
/*
161
 * This is the Hyper-V vmbus channel direct callback interrupt.
162
 * Only used when it is running on Hyper-V.
163
 */
164
	.text
165
	SUPERALIGN_TEXT
166
IDTVEC(hv_vmbus_callback)
167
	PUSH_FRAME
168
	SET_KERNEL_SREGS
169
	cld
170
	FAKE_MCOUNT(TF_EIP(%esp))
171
	pushl	%esp
172
	call	hv_vector_handler
173
	add	$4, %esp
174
	MEXITCOUNT
175
	jmp	doreti
176
160
#ifdef SMP
177
#ifdef SMP
161
/*
178
/*
162
 * Global address space TLB shootdown.
179
 * Global address space TLB shootdown.
(-)sys/amd64/amd64/apic_vector.S (+14 lines)
Lines 150-155 Link Here
150
	jmp	doreti
150
	jmp	doreti
151
#endif
151
#endif
152
152
153
/*
154
 * This is the Hyper-V vmbus channel direct callback interrupt.
155
 * Only used when it is running on Hyper-V.
156
 */
157
	.text
158
	SUPERALIGN_TEXT
159
IDTVEC(hv_vmbus_callback)
160
	PUSH_FRAME
161
	FAKE_MCOUNT(TF_RIP(%rsp))
162
	movq	%rsp, %rdi
163
	call	hv_vector_handler
164
	MEXITCOUNT
165
	jmp	doreti
166
153
#ifdef SMP
167
#ifdef SMP
154
/*
168
/*
155
 * Global address space TLB shootdown.
169
 * Global address space TLB shootdown.

Return to bug 195238