Commit f56dbdda authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hyperv-next-signed-20220528' of...

Merge tag 'hyperv-next-signed-20220528' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux

Pull hyperv updates from Wei Liu:

 - Harden hv_sock driver (Andrea Parri)

 - Harden Hyper-V PCI driver (Andrea Parri)

 - Fix multi-MSI for Hyper-V PCI driver (Jeffrey Hugo)

 - Fix Hyper-V PCI to reduce boot time (Dexuan Cui)

 - Remove code for long EOL'ed Hyper-V versions (Michael Kelley, Saurabh
   Sengar)

 - Fix balloon driver error handling (Shradha Gupta)

 - Fix a typo in vmbus driver (Julia Lawall)

 - Ignore vmbus IMC device (Michael Kelley)

 - Add a new error message to Hyper-V DRM driver (Saurabh Sengar)

* tag 'hyperv-next-signed-20220528' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: (28 commits)
  hv_balloon: Fix balloon_probe() and balloon_remove() error handling
  scsi: storvsc: Removing Pre Win8 related logic
  Drivers: hv: vmbus: fix typo in comment
  PCI: hv: Fix synchronization between channel callback and hv_pci_bus_exit()
  PCI: hv: Add validation for untrusted Hyper-V values
  PCI: hv: Fix interrupt mapping for multi-MSI
  PCI: hv: Reuse existing IRTE allocation in compose_msi_msg()
  drm/hyperv: Remove support for Hyper-V 2008 and 2008R2/Win7
  video: hyperv_fb: Remove support for Hyper-V 2008 and 2008R2/Win7
  scsi: storvsc: Remove support for Hyper-V 2008 and 2008R2/Win7
  Drivers: hv: vmbus: Remove support for Hyper-V 2008 and Hyper-V 2008R2/Win7
  x86/hyperv: Disable hardlockup detector by default in Hyper-V guests
  drm/hyperv: Add error message for fb size greater than allocated
  PCI: hv: Do not set PCI_COMMAND_MEMORY to reduce VM boot time
  PCI: hv: Fix hv_arch_irq_unmask() for multi-MSI
  Drivers: hv: vmbus: Refactor the ring-buffer iterator functions
  Drivers: hv: vmbus: Accept hv_sock offers in isolated guests
  hv_sock: Add validation for untrusted Hyper-V values
  hv_sock: Copy packets sent by Hyper-V out of the ring buffer
  hv_sock: Check hv_pkt_iter_first_raw()'s return value
  ...
parents 6112bd00 d27423bf
...@@ -457,6 +457,8 @@ static void __init ms_hyperv_init_platform(void) ...@@ -457,6 +457,8 @@ static void __init ms_hyperv_init_platform(void)
*/ */
if (!(ms_hyperv.features & HV_ACCESS_TSC_INVARIANT)) if (!(ms_hyperv.features & HV_ACCESS_TSC_INVARIANT))
mark_tsc_unstable("running on Hyper-V"); mark_tsc_unstable("running on Hyper-V");
hardlockup_detector_disable();
} }
static bool __init ms_hyperv_x2apic_available(void) static bool __init ms_hyperv_x2apic_available(void)
......
...@@ -123,8 +123,11 @@ static int hyperv_pipe_check(struct drm_simple_display_pipe *pipe, ...@@ -123,8 +123,11 @@ static int hyperv_pipe_check(struct drm_simple_display_pipe *pipe,
if (fb->format->format != DRM_FORMAT_XRGB8888) if (fb->format->format != DRM_FORMAT_XRGB8888)
return -EINVAL; return -EINVAL;
if (fb->pitches[0] * fb->height > hv->fb_size) if (fb->pitches[0] * fb->height > hv->fb_size) {
drm_err(&hv->dev, "fb size requested by %s for %dX%d (pitch %d) greater than %ld\n",
current->comm, fb->width, fb->height, fb->pitches[0], hv->fb_size);
return -EINVAL; return -EINVAL;
}
return 0; return 0;
} }
......
...@@ -18,16 +18,16 @@ ...@@ -18,16 +18,16 @@
#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major)) #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff) #define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16) #define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
/* Support for VERSION_WIN7 is removed. #define is retained for reference. */
#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0) #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2) #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5) #define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
#define SYNTHVID_DEPTH_WIN7 16
#define SYNTHVID_DEPTH_WIN8 32 #define SYNTHVID_DEPTH_WIN8 32
#define SYNTHVID_FB_SIZE_WIN7 (4 * 1024 * 1024) #define SYNTHVID_WIDTH_WIN8 1600
#define SYNTHVID_HEIGHT_WIN8 1200
#define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024) #define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
#define SYNTHVID_WIDTH_MAX_WIN7 1600
#define SYNTHVID_HEIGHT_MAX_WIN7 1200
enum pipe_msg_type { enum pipe_msg_type {
PIPE_MSG_INVALID, PIPE_MSG_INVALID,
...@@ -496,12 +496,6 @@ int hyperv_connect_vsp(struct hv_device *hdev) ...@@ -496,12 +496,6 @@ int hyperv_connect_vsp(struct hv_device *hdev)
case VERSION_WIN8: case VERSION_WIN8:
case VERSION_WIN8_1: case VERSION_WIN8_1:
ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN8); ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN8);
if (!ret)
break;
fallthrough;
case VERSION_WS2008:
case VERSION_WIN7:
ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN7);
break; break;
default: default:
ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN10); ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN10);
...@@ -513,18 +507,15 @@ int hyperv_connect_vsp(struct hv_device *hdev) ...@@ -513,18 +507,15 @@ int hyperv_connect_vsp(struct hv_device *hdev)
goto error; goto error;
} }
if (hv->synthvid_version == SYNTHVID_VERSION_WIN7) hv->screen_depth = SYNTHVID_DEPTH_WIN8;
hv->screen_depth = SYNTHVID_DEPTH_WIN7;
else
hv->screen_depth = SYNTHVID_DEPTH_WIN8;
if (hyperv_version_ge(hv->synthvid_version, SYNTHVID_VERSION_WIN10)) { if (hyperv_version_ge(hv->synthvid_version, SYNTHVID_VERSION_WIN10)) {
ret = hyperv_get_supported_resolution(hdev); ret = hyperv_get_supported_resolution(hdev);
if (ret) if (ret)
drm_err(dev, "Failed to get supported resolution from host, use default\n"); drm_err(dev, "Failed to get supported resolution from host, use default\n");
} else { } else {
hv->screen_width_max = SYNTHVID_WIDTH_MAX_WIN7; hv->screen_width_max = SYNTHVID_WIDTH_WIN8;
hv->screen_height_max = SYNTHVID_HEIGHT_MAX_WIN7; hv->screen_height_max = SYNTHVID_HEIGHT_WIN8;
} }
hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes; hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes;
......
...@@ -1022,11 +1022,13 @@ void vmbus_close(struct vmbus_channel *channel) ...@@ -1022,11 +1022,13 @@ void vmbus_close(struct vmbus_channel *channel)
EXPORT_SYMBOL_GPL(vmbus_close); EXPORT_SYMBOL_GPL(vmbus_close);
/** /**
* vmbus_sendpacket() - Send the specified buffer on the given channel * vmbus_sendpacket_getid() - Send the specified buffer on the given channel
* @channel: Pointer to vmbus_channel structure * @channel: Pointer to vmbus_channel structure
* @buffer: Pointer to the buffer you want to send the data from. * @buffer: Pointer to the buffer you want to send the data from.
* @bufferlen: Maximum size of what the buffer holds. * @bufferlen: Maximum size of what the buffer holds.
* @requestid: Identifier of the request * @requestid: Identifier of the request
* @trans_id: Identifier of the transaction associated to this request, if
* the send is successful; undefined, otherwise.
* @type: Type of packet that is being sent e.g. negotiate, time * @type: Type of packet that is being sent e.g. negotiate, time
* packet etc. * packet etc.
* @flags: 0 or VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED * @flags: 0 or VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
...@@ -1036,8 +1038,8 @@ EXPORT_SYMBOL_GPL(vmbus_close); ...@@ -1036,8 +1038,8 @@ EXPORT_SYMBOL_GPL(vmbus_close);
* *
* Mainly used by Hyper-V drivers. * Mainly used by Hyper-V drivers.
*/ */
int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, int vmbus_sendpacket_getid(struct vmbus_channel *channel, void *buffer,
u32 bufferlen, u64 requestid, u32 bufferlen, u64 requestid, u64 *trans_id,
enum vmbus_packet_type type, u32 flags) enum vmbus_packet_type type, u32 flags)
{ {
struct vmpacket_descriptor desc; struct vmpacket_descriptor desc;
...@@ -1063,7 +1065,31 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, ...@@ -1063,7 +1065,31 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen); bufferlist[2].iov_len = (packetlen_aligned - packetlen);
return hv_ringbuffer_write(channel, bufferlist, num_vecs, requestid); return hv_ringbuffer_write(channel, bufferlist, num_vecs, requestid, trans_id);
}
EXPORT_SYMBOL(vmbus_sendpacket_getid);
/**
* vmbus_sendpacket() - Send the specified buffer on the given channel
* @channel: Pointer to vmbus_channel structure
* @buffer: Pointer to the buffer you want to send the data from.
* @bufferlen: Maximum size of what the buffer holds.
* @requestid: Identifier of the request
* @type: Type of packet that is being sent e.g. negotiate, time
* packet etc.
* @flags: 0 or VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
*
* Sends data in @buffer directly to Hyper-V via the vmbus.
* This will send the data unparsed to Hyper-V.
*
* Mainly used by Hyper-V drivers.
*/
int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
u32 bufferlen, u64 requestid,
enum vmbus_packet_type type, u32 flags)
{
return vmbus_sendpacket_getid(channel, buffer, bufferlen,
requestid, NULL, type, flags);
} }
EXPORT_SYMBOL(vmbus_sendpacket); EXPORT_SYMBOL(vmbus_sendpacket);
...@@ -1122,7 +1148,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, ...@@ -1122,7 +1148,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen); bufferlist[2].iov_len = (packetlen_aligned - packetlen);
return hv_ringbuffer_write(channel, bufferlist, 3, requestid); return hv_ringbuffer_write(channel, bufferlist, 3, requestid, NULL);
} }
EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer); EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer);
...@@ -1160,7 +1186,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, ...@@ -1160,7 +1186,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen); bufferlist[2].iov_len = (packetlen_aligned - packetlen);
return hv_ringbuffer_write(channel, bufferlist, 3, requestid); return hv_ringbuffer_write(channel, bufferlist, 3, requestid, NULL);
} }
EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc); EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
...@@ -1226,12 +1252,12 @@ u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr) ...@@ -1226,12 +1252,12 @@ u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr)
if (!channel->rqstor_size) if (!channel->rqstor_size)
return VMBUS_NO_RQSTOR; return VMBUS_NO_RQSTOR;
spin_lock_irqsave(&rqstor->req_lock, flags); lock_requestor(channel, flags);
current_id = rqstor->next_request_id; current_id = rqstor->next_request_id;
/* Requestor array is full */ /* Requestor array is full */
if (current_id >= rqstor->size) { if (current_id >= rqstor->size) {
spin_unlock_irqrestore(&rqstor->req_lock, flags); unlock_requestor(channel, flags);
return VMBUS_RQST_ERROR; return VMBUS_RQST_ERROR;
} }
...@@ -1241,27 +1267,23 @@ u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr) ...@@ -1241,27 +1267,23 @@ u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr)
/* The already held spin lock provides atomicity */ /* The already held spin lock provides atomicity */
bitmap_set(rqstor->req_bitmap, current_id, 1); bitmap_set(rqstor->req_bitmap, current_id, 1);
spin_unlock_irqrestore(&rqstor->req_lock, flags); unlock_requestor(channel, flags);
/* /*
* Cannot return an ID of 0, which is reserved for an unsolicited * Cannot return an ID of 0, which is reserved for an unsolicited
* message from Hyper-V. * message from Hyper-V; Hyper-V does not acknowledge (respond to)
* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED requests with ID of
* 0 sent by the guest.
*/ */
return current_id + 1; return current_id + 1;
} }
EXPORT_SYMBOL_GPL(vmbus_next_request_id); EXPORT_SYMBOL_GPL(vmbus_next_request_id);
/* /* As in vmbus_request_addr_match() but without the requestor lock */
* vmbus_request_addr - Returns the memory address stored at @trans_id u64 __vmbus_request_addr_match(struct vmbus_channel *channel, u64 trans_id,
* in @rqstor. Uses a spin lock to avoid race conditions. u64 rqst_addr)
* @channel: Pointer to the VMbus channel struct
* @trans_id: Request id sent back from Hyper-V. Becomes the requestor's
* next request id.
*/
u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id)
{ {
struct vmbus_requestor *rqstor = &channel->requestor; struct vmbus_requestor *rqstor = &channel->requestor;
unsigned long flags;
u64 req_addr; u64 req_addr;
/* Check rqstor has been initialized */ /* Check rqstor has been initialized */
...@@ -1270,27 +1292,61 @@ u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id) ...@@ -1270,27 +1292,61 @@ u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id)
/* Hyper-V can send an unsolicited message with ID of 0 */ /* Hyper-V can send an unsolicited message with ID of 0 */
if (!trans_id) if (!trans_id)
return trans_id; return VMBUS_RQST_ERROR;
spin_lock_irqsave(&rqstor->req_lock, flags);
/* Data corresponding to trans_id is stored at trans_id - 1 */ /* Data corresponding to trans_id is stored at trans_id - 1 */
trans_id--; trans_id--;
/* Invalid trans_id */ /* Invalid trans_id */
if (trans_id >= rqstor->size || !test_bit(trans_id, rqstor->req_bitmap)) { if (trans_id >= rqstor->size || !test_bit(trans_id, rqstor->req_bitmap))
spin_unlock_irqrestore(&rqstor->req_lock, flags);
return VMBUS_RQST_ERROR; return VMBUS_RQST_ERROR;
}
req_addr = rqstor->req_arr[trans_id]; req_addr = rqstor->req_arr[trans_id];
rqstor->req_arr[trans_id] = rqstor->next_request_id; if (rqst_addr == VMBUS_RQST_ADDR_ANY || req_addr == rqst_addr) {
rqstor->next_request_id = trans_id; rqstor->req_arr[trans_id] = rqstor->next_request_id;
rqstor->next_request_id = trans_id;
/* The already held spin lock provides atomicity */ /* The already held spin lock provides atomicity */
bitmap_clear(rqstor->req_bitmap, trans_id, 1); bitmap_clear(rqstor->req_bitmap, trans_id, 1);
}
spin_unlock_irqrestore(&rqstor->req_lock, flags);
return req_addr; return req_addr;
} }
EXPORT_SYMBOL_GPL(__vmbus_request_addr_match);
/*
* vmbus_request_addr_match - Clears/removes @trans_id from the @channel's
* requestor, provided the memory address stored at @trans_id equals @rqst_addr
* (or provided @rqst_addr matches the sentinel value VMBUS_RQST_ADDR_ANY).
*
* Returns the memory address stored at @trans_id, or VMBUS_RQST_ERROR if
* @trans_id is not contained in the requestor.
*
* Acquires and releases the requestor spin lock.
*/
u64 vmbus_request_addr_match(struct vmbus_channel *channel, u64 trans_id,
u64 rqst_addr)
{
unsigned long flags;
u64 req_addr;
lock_requestor(channel, flags);
req_addr = __vmbus_request_addr_match(channel, trans_id, rqst_addr);
unlock_requestor(channel, flags);
return req_addr;
}
EXPORT_SYMBOL_GPL(vmbus_request_addr_match);
/*
* vmbus_request_addr - Returns the memory address stored at @trans_id
* in @rqstor. Uses a spin lock to avoid race conditions.
* @channel: Pointer to the VMbus channel struct
* @trans_id: Request id sent back from Hyper-V. Becomes the requestor's
* next request id.
*/
u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id)
{
return vmbus_request_addr_match(channel, trans_id, VMBUS_RQST_ADDR_ANY);
}
EXPORT_SYMBOL_GPL(vmbus_request_addr); EXPORT_SYMBOL_GPL(vmbus_request_addr);
...@@ -152,6 +152,7 @@ static const struct { ...@@ -152,6 +152,7 @@ static const struct {
{ HV_AVMA1_GUID }, { HV_AVMA1_GUID },
{ HV_AVMA2_GUID }, { HV_AVMA2_GUID },
{ HV_RDV_GUID }, { HV_RDV_GUID },
{ HV_IMC_GUID },
}; };
/* /*
...@@ -442,7 +443,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel) ...@@ -442,7 +443,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel)
/* /*
* Upon suspend, an in-use hv_sock channel is removed from the array of * Upon suspend, an in-use hv_sock channel is removed from the array of
* channels and the relid is invalidated. After hibernation, when the * channels and the relid is invalidated. After hibernation, when the
* user-space appplication destroys the channel, it's unnecessary and * user-space application destroys the channel, it's unnecessary and
* unsafe to remove the channel from the array of channels. See also * unsafe to remove the channel from the array of channels. See also
* the inline comments before the call of vmbus_release_relid() below. * the inline comments before the call of vmbus_release_relid() below.
*/ */
...@@ -713,15 +714,13 @@ static bool hv_cpuself_used(u32 cpu, struct vmbus_channel *chn) ...@@ -713,15 +714,13 @@ static bool hv_cpuself_used(u32 cpu, struct vmbus_channel *chn)
static int next_numa_node_id; static int next_numa_node_id;
/* /*
* Starting with Win8, we can statically distribute the incoming * We can statically distribute the incoming channel interrupt load
* channel interrupt load by binding a channel to VCPU. * by binding a channel to VCPU.
* *
* For pre-win8 hosts or non-performance critical channels we assign the * For non-performance critical channels we assign the VMBUS_CONNECT_CPU.
* VMBUS_CONNECT_CPU. * Performance critical channels will be distributed evenly among all
* * the available NUMA nodes. Once the node is assigned, we will assign
* Starting with win8, performance critical channels will be distributed * the CPU based on a simple round robin scheme.
* evenly among all the available NUMA nodes. Once the node is assigned,
* we will assign the CPU based on a simple round robin scheme.
*/ */
static void init_vp_index(struct vmbus_channel *channel) static void init_vp_index(struct vmbus_channel *channel)
{ {
...@@ -732,13 +731,10 @@ static void init_vp_index(struct vmbus_channel *channel) ...@@ -732,13 +731,10 @@ static void init_vp_index(struct vmbus_channel *channel)
u32 target_cpu; u32 target_cpu;
int numa_node; int numa_node;
if ((vmbus_proto_version == VERSION_WS2008) || if (!perf_chn ||
(vmbus_proto_version == VERSION_WIN7) || (!perf_chn) ||
!alloc_cpumask_var(&available_mask, GFP_KERNEL)) { !alloc_cpumask_var(&available_mask, GFP_KERNEL)) {
/* /*
* Prior to win8, all channel interrupts are * If the channel is not a performance critical
* delivered on VMBUS_CONNECT_CPU.
* Also if the channel is not a performance critical
* channel, bind it to VMBUS_CONNECT_CPU. * channel, bind it to VMBUS_CONNECT_CPU.
* In case alloc_cpumask_var() fails, bind it to * In case alloc_cpumask_var() fails, bind it to
* VMBUS_CONNECT_CPU. * VMBUS_CONNECT_CPU.
...@@ -931,11 +927,9 @@ static void vmbus_setup_channel_state(struct vmbus_channel *channel, ...@@ -931,11 +927,9 @@ static void vmbus_setup_channel_state(struct vmbus_channel *channel,
*/ */
channel->sig_event = VMBUS_EVENT_CONNECTION_ID; channel->sig_event = VMBUS_EVENT_CONNECTION_ID;
if (vmbus_proto_version != VERSION_WS2008) { channel->is_dedicated_interrupt =
channel->is_dedicated_interrupt = (offer->is_dedicated_interrupt != 0);
(offer->is_dedicated_interrupt != 0); channel->sig_event = offer->connection_id;
channel->sig_event = offer->connection_id;
}
memcpy(&channel->offermsg, offer, memcpy(&channel->offermsg, offer,
sizeof(struct vmbus_channel_offer_channel)); sizeof(struct vmbus_channel_offer_channel));
...@@ -975,13 +969,17 @@ find_primary_channel_by_offer(const struct vmbus_channel_offer_channel *offer) ...@@ -975,13 +969,17 @@ find_primary_channel_by_offer(const struct vmbus_channel_offer_channel *offer)
return channel; return channel;
} }
static bool vmbus_is_valid_device(const guid_t *guid) static bool vmbus_is_valid_offer(const struct vmbus_channel_offer_channel *offer)
{ {
const guid_t *guid = &offer->offer.if_type;
u16 i; u16 i;
if (!hv_is_isolation_supported()) if (!hv_is_isolation_supported())
return true; return true;
if (is_hvsock_offer(offer))
return true;
for (i = 0; i < ARRAY_SIZE(vmbus_devs); i++) { for (i = 0; i < ARRAY_SIZE(vmbus_devs); i++) {
if (guid_equal(guid, &vmbus_devs[i].guid)) if (guid_equal(guid, &vmbus_devs[i].guid))
return vmbus_devs[i].allowed_in_isolated; return vmbus_devs[i].allowed_in_isolated;
...@@ -1003,7 +1001,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) ...@@ -1003,7 +1001,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
trace_vmbus_onoffer(offer); trace_vmbus_onoffer(offer);
if (!vmbus_is_valid_device(&offer->offer.if_type)) { if (!vmbus_is_valid_offer(offer)) {
pr_err_ratelimited("Invalid offer %d from the host supporting isolation\n", pr_err_ratelimited("Invalid offer %d from the host supporting isolation\n",
offer->child_relid); offer->child_relid);
atomic_dec(&vmbus_connection.offer_in_progress); atomic_dec(&vmbus_connection.offer_in_progress);
......
...@@ -47,6 +47,8 @@ EXPORT_SYMBOL_GPL(vmbus_proto_version); ...@@ -47,6 +47,8 @@ EXPORT_SYMBOL_GPL(vmbus_proto_version);
/* /*
* Table of VMBus versions listed from newest to oldest. * Table of VMBus versions listed from newest to oldest.
* VERSION_WIN7 and VERSION_WS2008 are no longer supported in
* Linux guests and are not listed.
*/ */
static __u32 vmbus_versions[] = { static __u32 vmbus_versions[] = {
VERSION_WIN10_V5_3, VERSION_WIN10_V5_3,
...@@ -56,9 +58,7 @@ static __u32 vmbus_versions[] = { ...@@ -56,9 +58,7 @@ static __u32 vmbus_versions[] = {
VERSION_WIN10_V4_1, VERSION_WIN10_V4_1,
VERSION_WIN10, VERSION_WIN10,
VERSION_WIN8_1, VERSION_WIN8_1,
VERSION_WIN8, VERSION_WIN8
VERSION_WIN7,
VERSION_WS2008
}; };
/* /*
......
...@@ -1842,7 +1842,7 @@ static int balloon_probe(struct hv_device *dev, ...@@ -1842,7 +1842,7 @@ static int balloon_probe(struct hv_device *dev,
ret = balloon_connect_vsp(dev); ret = balloon_connect_vsp(dev);
if (ret != 0) if (ret != 0)
return ret; goto connect_error;
enable_page_reporting(); enable_page_reporting();
dm_device.state = DM_INITIALIZED; dm_device.state = DM_INITIALIZED;
...@@ -1861,6 +1861,7 @@ static int balloon_probe(struct hv_device *dev, ...@@ -1861,6 +1861,7 @@ static int balloon_probe(struct hv_device *dev,
dm_device.thread = NULL; dm_device.thread = NULL;
disable_page_reporting(); disable_page_reporting();
vmbus_close(dev->channel); vmbus_close(dev->channel);
connect_error:
#ifdef CONFIG_MEMORY_HOTPLUG #ifdef CONFIG_MEMORY_HOTPLUG
unregister_memory_notifier(&hv_memory_nb); unregister_memory_notifier(&hv_memory_nb);
restore_online_page_callback(&hv_online_page); restore_online_page_callback(&hv_online_page);
...@@ -1882,12 +1883,21 @@ static int balloon_remove(struct hv_device *dev) ...@@ -1882,12 +1883,21 @@ static int balloon_remove(struct hv_device *dev)
cancel_work_sync(&dm->ha_wrk.wrk); cancel_work_sync(&dm->ha_wrk.wrk);
kthread_stop(dm->thread); kthread_stop(dm->thread);
disable_page_reporting();
vmbus_close(dev->channel); /*
* This is to handle the case when balloon_resume()
* call has failed and some cleanup has been done as
* a part of the error handling.
*/
if (dm_device.state != DM_INIT_ERROR) {
disable_page_reporting();
vmbus_close(dev->channel);
#ifdef CONFIG_MEMORY_HOTPLUG #ifdef CONFIG_MEMORY_HOTPLUG
unregister_memory_notifier(&hv_memory_nb); unregister_memory_notifier(&hv_memory_nb);
restore_online_page_callback(&hv_online_page); restore_online_page_callback(&hv_online_page);
#endif #endif
}
spin_lock_irqsave(&dm_device.ha_lock, flags); spin_lock_irqsave(&dm_device.ha_lock, flags);
list_for_each_entry_safe(has, tmp, &dm->ha_region_list, list) { list_for_each_entry_safe(has, tmp, &dm->ha_region_list, list) {
list_for_each_entry_safe(gap, tmp_gap, &has->gap_list, list) { list_for_each_entry_safe(gap, tmp_gap, &has->gap_list, list) {
...@@ -1948,6 +1958,7 @@ static int balloon_resume(struct hv_device *dev) ...@@ -1948,6 +1958,7 @@ static int balloon_resume(struct hv_device *dev)
vmbus_close(dev->channel); vmbus_close(dev->channel);
out: out:
dm_device.state = DM_INIT_ERROR; dm_device.state = DM_INIT_ERROR;
disable_page_reporting();
#ifdef CONFIG_MEMORY_HOTPLUG #ifdef CONFIG_MEMORY_HOTPLUG
unregister_memory_notifier(&hv_memory_nb); unregister_memory_notifier(&hv_memory_nb);
restore_online_page_callback(&hv_online_page); restore_online_page_callback(&hv_online_page);
......
...@@ -181,7 +181,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info); ...@@ -181,7 +181,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
int hv_ringbuffer_write(struct vmbus_channel *channel, int hv_ringbuffer_write(struct vmbus_channel *channel,
const struct kvec *kv_list, u32 kv_count, const struct kvec *kv_list, u32 kv_count,
u64 requestid); u64 requestid, u64 *trans_id);
int hv_ringbuffer_read(struct vmbus_channel *channel, int hv_ringbuffer_read(struct vmbus_channel *channel,
void *buffer, u32 buflen, u32 *buffer_actual_len, void *buffer, u32 buflen, u32 *buffer_actual_len,
......
...@@ -283,7 +283,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) ...@@ -283,7 +283,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
/* Write to the ring buffer. */ /* Write to the ring buffer. */
int hv_ringbuffer_write(struct vmbus_channel *channel, int hv_ringbuffer_write(struct vmbus_channel *channel,
const struct kvec *kv_list, u32 kv_count, const struct kvec *kv_list, u32 kv_count,
u64 requestid) u64 requestid, u64 *trans_id)
{ {
int i; int i;
u32 bytes_avail_towrite; u32 bytes_avail_towrite;
...@@ -294,7 +294,7 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, ...@@ -294,7 +294,7 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
unsigned long flags; unsigned long flags;
struct hv_ring_buffer_info *outring_info = &channel->outbound; struct hv_ring_buffer_info *outring_info = &channel->outbound;
struct vmpacket_descriptor *desc = kv_list[0].iov_base; struct vmpacket_descriptor *desc = kv_list[0].iov_base;
u64 rqst_id = VMBUS_NO_RQSTOR; u64 __trans_id, rqst_id = VMBUS_NO_RQSTOR;
if (channel->rescind) if (channel->rescind)
return -ENODEV; return -ENODEV;
...@@ -353,7 +353,15 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, ...@@ -353,7 +353,15 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
} }
} }
desc = hv_get_ring_buffer(outring_info) + old_write; desc = hv_get_ring_buffer(outring_info) + old_write;
desc->trans_id = (rqst_id == VMBUS_NO_RQSTOR) ? requestid : rqst_id; __trans_id = (rqst_id == VMBUS_NO_RQSTOR) ? requestid : rqst_id;
/*
* Ensure the compiler doesn't generate code that reads the value of
* the transaction ID from the ring buffer, which is shared with the
* Hyper-V host and subject to being changed at any time.
*/
WRITE_ONCE(desc->trans_id, __trans_id);
if (trans_id)
*trans_id = __trans_id;
/* Set previous packet start */ /* Set previous packet start */
prev_indices = hv_get_ring_bufferindices(outring_info); prev_indices = hv_get_ring_bufferindices(outring_info);
...@@ -421,7 +429,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, ...@@ -421,7 +429,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
memcpy(buffer, (const char *)desc + offset, packetlen); memcpy(buffer, (const char *)desc + offset, packetlen);
/* Advance ring index to next packet descriptor */ /* Advance ring index to next packet descriptor */
__hv_pkt_iter_next(channel, desc, true); __hv_pkt_iter_next(channel, desc);
/* Notify host of update */ /* Notify host of update */
hv_pkt_iter_close(channel); hv_pkt_iter_close(channel);
...@@ -456,22 +464,6 @@ static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi) ...@@ -456,22 +464,6 @@ static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
return (rbi->ring_datasize - priv_read_loc) + write_loc; return (rbi->ring_datasize - priv_read_loc) + write_loc;
} }
/*
* Get first vmbus packet without copying it out of the ring buffer
*/
struct vmpacket_descriptor *hv_pkt_iter_first_raw(struct vmbus_channel *channel)
{
struct hv_ring_buffer_info *rbi = &channel->inbound;
hv_debug_delay_test(channel, MESSAGE_DELAY);
if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
return NULL;
return (struct vmpacket_descriptor *)(hv_get_ring_buffer(rbi) + rbi->priv_read_index);
}
EXPORT_SYMBOL_GPL(hv_pkt_iter_first_raw);
/* /*
* Get first vmbus packet from ring buffer after read_index * Get first vmbus packet from ring buffer after read_index
* *
...@@ -483,11 +475,14 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel) ...@@ -483,11 +475,14 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
struct vmpacket_descriptor *desc, *desc_copy; struct vmpacket_descriptor *desc, *desc_copy;
u32 bytes_avail, pkt_len, pkt_offset; u32 bytes_avail, pkt_len, pkt_offset;
desc = hv_pkt_iter_first_raw(channel); hv_debug_delay_test(channel, MESSAGE_DELAY);
if (!desc)
bytes_avail = hv_pkt_iter_avail(rbi);
if (bytes_avail < sizeof(struct vmpacket_descriptor))
return NULL; return NULL;
bytes_avail = min(rbi->pkt_buffer_size, bytes_avail);
bytes_avail = min(rbi->pkt_buffer_size, hv_pkt_iter_avail(rbi)); desc = (struct vmpacket_descriptor *)(hv_get_ring_buffer(rbi) + rbi->priv_read_index);
/* /*
* Ensure the compiler does not use references to incoming Hyper-V values (which * Ensure the compiler does not use references to incoming Hyper-V values (which
...@@ -534,8 +529,7 @@ EXPORT_SYMBOL_GPL(hv_pkt_iter_first); ...@@ -534,8 +529,7 @@ EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
*/ */
struct vmpacket_descriptor * struct vmpacket_descriptor *
__hv_pkt_iter_next(struct vmbus_channel *channel, __hv_pkt_iter_next(struct vmbus_channel *channel,
const struct vmpacket_descriptor *desc, const struct vmpacket_descriptor *desc)
bool copy)
{ {
struct hv_ring_buffer_info *rbi = &channel->inbound; struct hv_ring_buffer_info *rbi = &channel->inbound;
u32 packetlen = desc->len8 << 3; u32 packetlen = desc->len8 << 3;
...@@ -548,7 +542,7 @@ __hv_pkt_iter_next(struct vmbus_channel *channel, ...@@ -548,7 +542,7 @@ __hv_pkt_iter_next(struct vmbus_channel *channel,
rbi->priv_read_index -= dsize; rbi->priv_read_index -= dsize;
/* more data? */ /* more data? */
return copy ? hv_pkt_iter_first(channel) : hv_pkt_iter_first_raw(channel); return hv_pkt_iter_first(channel);
} }
EXPORT_SYMBOL_GPL(__hv_pkt_iter_next); EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);
......
...@@ -1263,23 +1263,17 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu) ...@@ -1263,23 +1263,17 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu)
unsigned long *recv_int_page; unsigned long *recv_int_page;
u32 maxbits, relid; u32 maxbits, relid;
if (vmbus_proto_version < VERSION_WIN8) { /*
maxbits = MAX_NUM_CHANNELS_SUPPORTED; * The event page can be directly checked to get the id of
recv_int_page = vmbus_connection.recv_int_page; * the channel that has the interrupt pending.
} else { */
/* void *page_addr = hv_cpu->synic_event_page;
* When the host is win8 and beyond, the event page union hv_synic_event_flags *event
* can be directly checked to get the id of the channel = (union hv_synic_event_flags *)page_addr +
* that has the interrupt pending. VMBUS_MESSAGE_SINT;
*/
void *page_addr = hv_cpu->synic_event_page;
union hv_synic_event_flags *event
= (union hv_synic_event_flags *)page_addr +
VMBUS_MESSAGE_SINT;
maxbits = HV_EVENT_FLAGS_COUNT; maxbits = HV_EVENT_FLAGS_COUNT;
recv_int_page = event->flags; recv_int_page = event->flags;
}
if (unlikely(!recv_int_page)) if (unlikely(!recv_int_page))
return; return;
...@@ -1351,40 +1345,10 @@ static void vmbus_isr(void) ...@@ -1351,40 +1345,10 @@ static void vmbus_isr(void)
{ {
struct hv_per_cpu_context *hv_cpu struct hv_per_cpu_context *hv_cpu
= this_cpu_ptr(hv_context.cpu_context); = this_cpu_ptr(hv_context.cpu_context);
void *page_addr = hv_cpu->synic_event_page; void *page_addr;
struct hv_message *msg; struct hv_message *msg;
union hv_synic_event_flags *event;
bool handled = false;
if (unlikely(page_addr == NULL))
return;
event = (union hv_synic_event_flags *)page_addr +
VMBUS_MESSAGE_SINT;
/*
* Check for events before checking for messages. This is the order
* in which events and messages are checked in Windows guests on
* Hyper-V, and the Windows team suggested we do the same.
*/
if ((vmbus_proto_version == VERSION_WS2008) ||
(vmbus_proto_version == VERSION_WIN7)) {
/* Since we are a child, we only need to check bit 0 */
if (sync_test_and_clear_bit(0, event->flags))
handled = true;
} else {
/*
* Our host is win8 or above. The signaling mechanism
* has changed and we can directly look at the event page.
* If bit n is set then we have an interrup on the channel
* whose id is n.
*/
handled = true;
}
if (handled) vmbus_chan_sched(hv_cpu);
vmbus_chan_sched(hv_cpu);
page_addr = hv_cpu->synic_message_page; page_addr = hv_cpu->synic_message_page;
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
......
This diff is collapsed.
This diff is collapsed.
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
#define MAX_VMBUS_PKT_SIZE 0x4000 #define MAX_VMBUS_PKT_SIZE 0x4000
#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major)) #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
/* Support for VERSION_WIN7 is removed. #define is retained for reference. */
#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0) #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2) #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5) #define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
...@@ -70,13 +71,7 @@ ...@@ -70,13 +71,7 @@
#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff) #define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16) #define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
#define SYNTHVID_DEPTH_WIN7 16
#define SYNTHVID_DEPTH_WIN8 32 #define SYNTHVID_DEPTH_WIN8 32
#define SYNTHVID_FB_SIZE_WIN7 (4 * 1024 * 1024)
#define SYNTHVID_WIDTH_MAX_WIN7 1600
#define SYNTHVID_HEIGHT_MAX_WIN7 1200
#define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024) #define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
#define PCI_VENDOR_ID_MICROSOFT 0x1414 #define PCI_VENDOR_ID_MICROSOFT 0x1414
...@@ -643,12 +638,6 @@ static int synthvid_connect_vsp(struct hv_device *hdev) ...@@ -643,12 +638,6 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
case VERSION_WIN8: case VERSION_WIN8:
case VERSION_WIN8_1: case VERSION_WIN8_1:
ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8); ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
if (!ret)
break;
fallthrough;
case VERSION_WS2008:
case VERSION_WIN7:
ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
break; break;
default: default:
ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10); ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
...@@ -660,11 +649,7 @@ static int synthvid_connect_vsp(struct hv_device *hdev) ...@@ -660,11 +649,7 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
goto error; goto error;
} }
if (par->synthvid_version == SYNTHVID_VERSION_WIN7) screen_depth = SYNTHVID_DEPTH_WIN8;
screen_depth = SYNTHVID_DEPTH_WIN7;
else
screen_depth = SYNTHVID_DEPTH_WIN8;
if (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10)) { if (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10)) {
ret = synthvid_get_supported_resolution(hdev); ret = synthvid_get_supported_resolution(hdev);
if (ret) if (ret)
...@@ -933,9 +918,7 @@ static void hvfb_get_option(struct fb_info *info) ...@@ -933,9 +918,7 @@ static void hvfb_get_option(struct fb_info *info)
(synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) && (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) &&
(x * y * screen_depth / 8 > screen_fb_size)) || (x * y * screen_depth / 8 > screen_fb_size)) ||
(par->synthvid_version == SYNTHVID_VERSION_WIN8 && (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) || x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8)) {
(par->synthvid_version == SYNTHVID_VERSION_WIN7 &&
(x > SYNTHVID_WIDTH_MAX_WIN7 || y > SYNTHVID_HEIGHT_MAX_WIN7))) {
pr_err("Screen resolution option is out of range: skipped\n"); pr_err("Screen resolution option is out of range: skipped\n");
return; return;
} }
......
...@@ -230,15 +230,19 @@ static inline u32 hv_get_avail_to_write_percent( ...@@ -230,15 +230,19 @@ static inline u32 hv_get_avail_to_write_percent(
* two 16 bit quantities: major_number. minor_number. * two 16 bit quantities: major_number. minor_number.
* *
* 0 . 13 (Windows Server 2008) * 0 . 13 (Windows Server 2008)
* 1 . 1 (Windows 7) * 1 . 1 (Windows 7, WS2008 R2)
* 2 . 4 (Windows 8) * 2 . 4 (Windows 8, WS2012)
* 3 . 0 (Windows 8 R2) * 3 . 0 (Windows 8.1, WS2012 R2)
* 4 . 0 (Windows 10) * 4 . 0 (Windows 10)
* 4 . 1 (Windows 10 RS3) * 4 . 1 (Windows 10 RS3)
* 5 . 0 (Newer Windows 10) * 5 . 0 (Newer Windows 10)
* 5 . 1 (Windows 10 RS4) * 5 . 1 (Windows 10 RS4)
* 5 . 2 (Windows Server 2019, RS5) * 5 . 2 (Windows Server 2019, RS5)
* 5 . 3 (Windows Server 2022) * 5 . 3 (Windows Server 2022)
*
* The WS2008 and WIN7 versions are listed here for
* completeness but are no longer supported in the
* Linux kernel.
*/ */
#define VERSION_WS2008 ((0 << 16) | (13)) #define VERSION_WS2008 ((0 << 16) | (13))
...@@ -788,6 +792,7 @@ struct vmbus_requestor { ...@@ -788,6 +792,7 @@ struct vmbus_requestor {
#define VMBUS_NO_RQSTOR U64_MAX #define VMBUS_NO_RQSTOR U64_MAX
#define VMBUS_RQST_ERROR (U64_MAX - 1) #define VMBUS_RQST_ERROR (U64_MAX - 1)
#define VMBUS_RQST_ADDR_ANY U64_MAX
/* NetVSC-specific */ /* NetVSC-specific */
#define VMBUS_RQST_ID_NO_RESPONSE (U64_MAX - 2) #define VMBUS_RQST_ID_NO_RESPONSE (U64_MAX - 2)
/* StorVSC-specific */ /* StorVSC-specific */
...@@ -1041,13 +1046,36 @@ struct vmbus_channel { ...@@ -1041,13 +1046,36 @@ struct vmbus_channel {
u32 max_pkt_size; u32 max_pkt_size;
}; };
#define lock_requestor(channel, flags) \
do { \
struct vmbus_requestor *rqstor = &(channel)->requestor; \
\
spin_lock_irqsave(&rqstor->req_lock, flags); \
} while (0)
static __always_inline void unlock_requestor(struct vmbus_channel *channel,
unsigned long flags)
{
struct vmbus_requestor *rqstor = &channel->requestor;
spin_unlock_irqrestore(&rqstor->req_lock, flags);
}
u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr); u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr);
u64 __vmbus_request_addr_match(struct vmbus_channel *channel, u64 trans_id,
u64 rqst_addr);
u64 vmbus_request_addr_match(struct vmbus_channel *channel, u64 trans_id,
u64 rqst_addr);
u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id); u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id);
static inline bool is_hvsock_offer(const struct vmbus_channel_offer_channel *o)
{
return !!(o->offer.chn_flags & VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER);
}
static inline bool is_hvsock_channel(const struct vmbus_channel *c) static inline bool is_hvsock_channel(const struct vmbus_channel *c)
{ {
return !!(c->offermsg.offer.chn_flags & return is_hvsock_offer(&c->offermsg);
VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER);
} }
static inline bool is_sub_channel(const struct vmbus_channel *c) static inline bool is_sub_channel(const struct vmbus_channel *c)
...@@ -1161,6 +1189,13 @@ extern int vmbus_open(struct vmbus_channel *channel, ...@@ -1161,6 +1189,13 @@ extern int vmbus_open(struct vmbus_channel *channel,
extern void vmbus_close(struct vmbus_channel *channel); extern void vmbus_close(struct vmbus_channel *channel);
extern int vmbus_sendpacket_getid(struct vmbus_channel *channel,
void *buffer,
u32 bufferLen,
u64 requestid,
u64 *trans_id,
enum vmbus_packet_type type,
u32 flags);
extern int vmbus_sendpacket(struct vmbus_channel *channel, extern int vmbus_sendpacket(struct vmbus_channel *channel,
void *buffer, void *buffer,
u32 bufferLen, u32 bufferLen,
...@@ -1451,12 +1486,14 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size); ...@@ -1451,12 +1486,14 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size);
0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f) 0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f)
/* /*
* Linux doesn't support the 3 devices: the first two are for * Linux doesn't support these 4 devices: the first two are for
* Automatic Virtual Machine Activation, and the third is for * Automatic Virtual Machine Activation, the third is for
* Remote Desktop Virtualization. * Remote Desktop Virtualization, and the fourth is Initial
* Machine Configuration (IMC) used only by Windows guests.
* {f8e65716-3cb3-4a06-9a60-1889c5cccab5} * {f8e65716-3cb3-4a06-9a60-1889c5cccab5}
* {3375baf4-9e15-4b30-b765-67acb10d607b} * {3375baf4-9e15-4b30-b765-67acb10d607b}
* {276aacf4-ac15-426c-98dd-7521ad3f01fe} * {276aacf4-ac15-426c-98dd-7521ad3f01fe}
* {c376c1c3-d276-48d2-90a9-c04748072c60}
*/ */
#define HV_AVMA1_GUID \ #define HV_AVMA1_GUID \
...@@ -1471,6 +1508,10 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size); ...@@ -1471,6 +1508,10 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size);
.guid = GUID_INIT(0x276aacf4, 0xac15, 0x426c, 0x98, 0xdd, \ .guid = GUID_INIT(0x276aacf4, 0xac15, 0x426c, 0x98, 0xdd, \
0x75, 0x21, 0xad, 0x3f, 0x01, 0xfe) 0x75, 0x21, 0xad, 0x3f, 0x01, 0xfe)
#define HV_IMC_GUID \
.guid = GUID_INIT(0xc376c1c3, 0xd276, 0x48d2, 0x90, 0xa9, \
0xc0, 0x47, 0x48, 0x07, 0x2c, 0x60)
/* /*
* Common header for Hyper-V ICs * Common header for Hyper-V ICs
*/ */
...@@ -1663,56 +1704,34 @@ static inline u32 hv_pkt_datalen(const struct vmpacket_descriptor *desc) ...@@ -1663,56 +1704,34 @@ static inline u32 hv_pkt_datalen(const struct vmpacket_descriptor *desc)
return (desc->len8 << 3) - (desc->offset8 << 3); return (desc->len8 << 3) - (desc->offset8 << 3);
} }
/* Get packet length associated with descriptor */
struct vmpacket_descriptor * static inline u32 hv_pkt_len(const struct vmpacket_descriptor *desc)
hv_pkt_iter_first_raw(struct vmbus_channel *channel); {
return desc->len8 << 3;
}
struct vmpacket_descriptor * struct vmpacket_descriptor *
hv_pkt_iter_first(struct vmbus_channel *channel); hv_pkt_iter_first(struct vmbus_channel *channel);
struct vmpacket_descriptor * struct vmpacket_descriptor *
__hv_pkt_iter_next(struct vmbus_channel *channel, __hv_pkt_iter_next(struct vmbus_channel *channel,
const struct vmpacket_descriptor *pkt, const struct vmpacket_descriptor *pkt);
bool copy);
void hv_pkt_iter_close(struct vmbus_channel *channel); void hv_pkt_iter_close(struct vmbus_channel *channel);
static inline struct vmpacket_descriptor * static inline struct vmpacket_descriptor *
hv_pkt_iter_next_pkt(struct vmbus_channel *channel, hv_pkt_iter_next(struct vmbus_channel *channel,
const struct vmpacket_descriptor *pkt, const struct vmpacket_descriptor *pkt)
bool copy)
{ {
struct vmpacket_descriptor *nxt; struct vmpacket_descriptor *nxt;
nxt = __hv_pkt_iter_next(channel, pkt, copy); nxt = __hv_pkt_iter_next(channel, pkt);
if (!nxt) if (!nxt)
hv_pkt_iter_close(channel); hv_pkt_iter_close(channel);
return nxt; return nxt;
} }
/*
* Get next packet descriptor without copying it out of the ring buffer
* If at end of list, return NULL and update host.
*/
static inline struct vmpacket_descriptor *
hv_pkt_iter_next_raw(struct vmbus_channel *channel,
const struct vmpacket_descriptor *pkt)
{
return hv_pkt_iter_next_pkt(channel, pkt, false);
}
/*
* Get next packet descriptor from iterator
* If at end of list, return NULL and update host.
*/
static inline struct vmpacket_descriptor *
hv_pkt_iter_next(struct vmbus_channel *channel,
const struct vmpacket_descriptor *pkt)
{
return hv_pkt_iter_next_pkt(channel, pkt, true);
}
#define foreach_vmbus_pkt(pkt, channel) \ #define foreach_vmbus_pkt(pkt, channel) \
for (pkt = hv_pkt_iter_first(channel); pkt; \ for (pkt = hv_pkt_iter_first(channel); pkt; \
pkt = hv_pkt_iter_next(channel, pkt)) pkt = hv_pkt_iter_next(channel, pkt))
......
...@@ -78,6 +78,9 @@ struct hvs_send_buf { ...@@ -78,6 +78,9 @@ struct hvs_send_buf {
ALIGN((payload_len), 8) + \ ALIGN((payload_len), 8) + \
VMBUS_PKT_TRAILER_SIZE) VMBUS_PKT_TRAILER_SIZE)
/* Upper bound on the size of a VMbus packet for hv_sock */
#define HVS_MAX_PKT_SIZE HVS_PKT_LEN(HVS_MTU_SIZE)
union hvs_service_id { union hvs_service_id {
guid_t srv_id; guid_t srv_id;
...@@ -378,6 +381,8 @@ static void hvs_open_connection(struct vmbus_channel *chan) ...@@ -378,6 +381,8 @@ static void hvs_open_connection(struct vmbus_channel *chan)
rcvbuf = ALIGN(rcvbuf, HV_HYP_PAGE_SIZE); rcvbuf = ALIGN(rcvbuf, HV_HYP_PAGE_SIZE);
} }
chan->max_pkt_size = HVS_MAX_PKT_SIZE;
ret = vmbus_open(chan, sndbuf, rcvbuf, NULL, 0, hvs_channel_cb, ret = vmbus_open(chan, sndbuf, rcvbuf, NULL, 0, hvs_channel_cb,
conn_from_host ? new : sk); conn_from_host ? new : sk);
if (ret != 0) { if (ret != 0) {
...@@ -572,12 +577,18 @@ static bool hvs_dgram_allow(u32 cid, u32 port) ...@@ -572,12 +577,18 @@ static bool hvs_dgram_allow(u32 cid, u32 port)
static int hvs_update_recv_data(struct hvsock *hvs) static int hvs_update_recv_data(struct hvsock *hvs)
{ {
struct hvs_recv_buf *recv_buf; struct hvs_recv_buf *recv_buf;
u32 payload_len; u32 pkt_len, payload_len;
pkt_len = hv_pkt_len(hvs->recv_desc);
if (pkt_len < HVS_HEADER_LEN)
return -EIO;
recv_buf = (struct hvs_recv_buf *)(hvs->recv_desc + 1); recv_buf = (struct hvs_recv_buf *)(hvs->recv_desc + 1);
payload_len = recv_buf->hdr.data_size; payload_len = recv_buf->hdr.data_size;
if (payload_len > HVS_MTU_SIZE) if (payload_len > pkt_len - HVS_HEADER_LEN ||
payload_len > HVS_MTU_SIZE)
return -EIO; return -EIO;
if (payload_len == 0) if (payload_len == 0)
...@@ -602,7 +613,9 @@ static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg, ...@@ -602,7 +613,9 @@ static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg,
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (need_refill) { if (need_refill) {
hvs->recv_desc = hv_pkt_iter_first_raw(hvs->chan); hvs->recv_desc = hv_pkt_iter_first(hvs->chan);
if (!hvs->recv_desc)
return -ENOBUFS;
ret = hvs_update_recv_data(hvs); ret = hvs_update_recv_data(hvs);
if (ret) if (ret)
return ret; return ret;
...@@ -616,7 +629,7 @@ static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg, ...@@ -616,7 +629,7 @@ static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg,
hvs->recv_data_len -= to_read; hvs->recv_data_len -= to_read;
if (hvs->recv_data_len == 0) { if (hvs->recv_data_len == 0) {
hvs->recv_desc = hv_pkt_iter_next_raw(hvs->chan, hvs->recv_desc); hvs->recv_desc = hv_pkt_iter_next(hvs->chan, hvs->recv_desc);
if (hvs->recv_desc) { if (hvs->recv_desc) {
ret = hvs_update_recv_data(hvs); ret = hvs_update_recv_data(hvs);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment