mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
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 ...
This commit is contained in:
@@ -457,6 +457,8 @@ static void __init ms_hyperv_init_platform(void)
|
||||
*/
|
||||
if (!(ms_hyperv.features & HV_ACCESS_TSC_INVARIANT))
|
||||
mark_tsc_unstable("running on Hyper-V");
|
||||
|
||||
hardlockup_detector_disable();
|
||||
}
|
||||
|
||||
static bool __init ms_hyperv_x2apic_available(void)
|
||||
|
||||
@@ -123,8 +123,11 @@ static int hyperv_pipe_check(struct drm_simple_display_pipe *pipe,
|
||||
if (fb->format->format != DRM_FORMAT_XRGB8888)
|
||||
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 0;
|
||||
}
|
||||
|
||||
@@ -18,16 +18,16 @@
|
||||
#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
|
||||
#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
|
||||
#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_WIN8 SYNTHVID_VERSION(3, 2)
|
||||
#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
|
||||
|
||||
#define SYNTHVID_DEPTH_WIN7 16
|
||||
#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_WIDTH_MAX_WIN7 1600
|
||||
#define SYNTHVID_HEIGHT_MAX_WIN7 1200
|
||||
|
||||
enum pipe_msg_type {
|
||||
PIPE_MSG_INVALID,
|
||||
@@ -496,12 +496,6 @@ int hyperv_connect_vsp(struct hv_device *hdev)
|
||||
case VERSION_WIN8:
|
||||
case VERSION_WIN8_1:
|
||||
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;
|
||||
default:
|
||||
ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN10);
|
||||
@@ -513,18 +507,15 @@ int hyperv_connect_vsp(struct hv_device *hdev)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (hv->synthvid_version == SYNTHVID_VERSION_WIN7)
|
||||
hv->screen_depth = SYNTHVID_DEPTH_WIN7;
|
||||
else
|
||||
hv->screen_depth = SYNTHVID_DEPTH_WIN8;
|
||||
hv->screen_depth = SYNTHVID_DEPTH_WIN8;
|
||||
|
||||
if (hyperv_version_ge(hv->synthvid_version, SYNTHVID_VERSION_WIN10)) {
|
||||
ret = hyperv_get_supported_resolution(hdev);
|
||||
if (ret)
|
||||
drm_err(dev, "Failed to get supported resolution from host, use default\n");
|
||||
} else {
|
||||
hv->screen_width_max = SYNTHVID_WIDTH_MAX_WIN7;
|
||||
hv->screen_height_max = SYNTHVID_HEIGHT_MAX_WIN7;
|
||||
hv->screen_width_max = SYNTHVID_WIDTH_WIN8;
|
||||
hv->screen_height_max = SYNTHVID_HEIGHT_WIN8;
|
||||
}
|
||||
|
||||
hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes;
|
||||
|
||||
@@ -1022,11 +1022,13 @@ void vmbus_close(struct vmbus_channel *channel)
|
||||
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
|
||||
* @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
|
||||
* @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
|
||||
* packet etc.
|
||||
* @flags: 0 or VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED
|
||||
@@ -1036,8 +1038,8 @@ EXPORT_SYMBOL_GPL(vmbus_close);
|
||||
*
|
||||
* Mainly used by Hyper-V drivers.
|
||||
*/
|
||||
int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
|
||||
u32 bufferlen, u64 requestid,
|
||||
int vmbus_sendpacket_getid(struct vmbus_channel *channel, void *buffer,
|
||||
u32 bufferlen, u64 requestid, u64 *trans_id,
|
||||
enum vmbus_packet_type type, u32 flags)
|
||||
{
|
||||
struct vmpacket_descriptor desc;
|
||||
@@ -1063,7 +1065,31 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer,
|
||||
bufferlist[2].iov_base = &aligned_data;
|
||||
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);
|
||||
|
||||
@@ -1122,7 +1148,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
|
||||
bufferlist[2].iov_base = &aligned_data;
|
||||
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);
|
||||
|
||||
@@ -1160,7 +1186,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
|
||||
bufferlist[2].iov_base = &aligned_data;
|
||||
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);
|
||||
|
||||
@@ -1226,12 +1252,12 @@ u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr)
|
||||
if (!channel->rqstor_size)
|
||||
return VMBUS_NO_RQSTOR;
|
||||
|
||||
spin_lock_irqsave(&rqstor->req_lock, flags);
|
||||
lock_requestor(channel, flags);
|
||||
current_id = rqstor->next_request_id;
|
||||
|
||||
/* Requestor array is full */
|
||||
if (current_id >= rqstor->size) {
|
||||
spin_unlock_irqrestore(&rqstor->req_lock, flags);
|
||||
unlock_requestor(channel, flags);
|
||||
return VMBUS_RQST_ERROR;
|
||||
}
|
||||
|
||||
@@ -1241,16 +1267,77 @@ u64 vmbus_next_request_id(struct vmbus_channel *channel, u64 rqst_addr)
|
||||
/* The already held spin lock provides atomicity */
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_next_request_id);
|
||||
|
||||
/* As in vmbus_request_addr_match() but without the requestor lock */
|
||||
u64 __vmbus_request_addr_match(struct vmbus_channel *channel, u64 trans_id,
|
||||
u64 rqst_addr)
|
||||
{
|
||||
struct vmbus_requestor *rqstor = &channel->requestor;
|
||||
u64 req_addr;
|
||||
|
||||
/* Check rqstor has been initialized */
|
||||
if (!channel->rqstor_size)
|
||||
return VMBUS_NO_RQSTOR;
|
||||
|
||||
/* Hyper-V can send an unsolicited message with ID of 0 */
|
||||
if (!trans_id)
|
||||
return VMBUS_RQST_ERROR;
|
||||
|
||||
/* Data corresponding to trans_id is stored at trans_id - 1 */
|
||||
trans_id--;
|
||||
|
||||
/* Invalid trans_id */
|
||||
if (trans_id >= rqstor->size || !test_bit(trans_id, rqstor->req_bitmap))
|
||||
return VMBUS_RQST_ERROR;
|
||||
|
||||
req_addr = rqstor->req_arr[trans_id];
|
||||
if (rqst_addr == VMBUS_RQST_ADDR_ANY || req_addr == rqst_addr) {
|
||||
rqstor->req_arr[trans_id] = rqstor->next_request_id;
|
||||
rqstor->next_request_id = trans_id;
|
||||
|
||||
/* The already held spin lock provides atomicity */
|
||||
bitmap_clear(rqstor->req_bitmap, trans_id, 1);
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -1260,37 +1347,6 @@ EXPORT_SYMBOL_GPL(vmbus_next_request_id);
|
||||
*/
|
||||
u64 vmbus_request_addr(struct vmbus_channel *channel, u64 trans_id)
|
||||
{
|
||||
struct vmbus_requestor *rqstor = &channel->requestor;
|
||||
unsigned long flags;
|
||||
u64 req_addr;
|
||||
|
||||
/* Check rqstor has been initialized */
|
||||
if (!channel->rqstor_size)
|
||||
return VMBUS_NO_RQSTOR;
|
||||
|
||||
/* Hyper-V can send an unsolicited message with ID of 0 */
|
||||
if (!trans_id)
|
||||
return trans_id;
|
||||
|
||||
spin_lock_irqsave(&rqstor->req_lock, flags);
|
||||
|
||||
/* Data corresponding to trans_id is stored at trans_id - 1 */
|
||||
trans_id--;
|
||||
|
||||
/* Invalid trans_id */
|
||||
if (trans_id >= rqstor->size || !test_bit(trans_id, rqstor->req_bitmap)) {
|
||||
spin_unlock_irqrestore(&rqstor->req_lock, flags);
|
||||
return VMBUS_RQST_ERROR;
|
||||
}
|
||||
|
||||
req_addr = rqstor->req_arr[trans_id];
|
||||
rqstor->req_arr[trans_id] = rqstor->next_request_id;
|
||||
rqstor->next_request_id = trans_id;
|
||||
|
||||
/* The already held spin lock provides atomicity */
|
||||
bitmap_clear(rqstor->req_bitmap, trans_id, 1);
|
||||
|
||||
spin_unlock_irqrestore(&rqstor->req_lock, flags);
|
||||
return req_addr;
|
||||
return vmbus_request_addr_match(channel, trans_id, VMBUS_RQST_ADDR_ANY);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_request_addr);
|
||||
|
||||
@@ -152,6 +152,7 @@ static const struct {
|
||||
{ HV_AVMA1_GUID },
|
||||
{ HV_AVMA2_GUID },
|
||||
{ HV_RDV_GUID },
|
||||
{ HV_IMC_GUID },
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -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
|
||||
* 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
|
||||
* 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)
|
||||
static int next_numa_node_id;
|
||||
|
||||
/*
|
||||
* Starting with Win8, we can statically distribute the incoming
|
||||
* channel interrupt load by binding a channel to VCPU.
|
||||
* We can statically distribute the incoming channel interrupt load
|
||||
* by binding a channel to VCPU.
|
||||
*
|
||||
* For pre-win8 hosts or non-performance critical channels we assign the
|
||||
* VMBUS_CONNECT_CPU.
|
||||
*
|
||||
* Starting with win8, performance critical channels will be distributed
|
||||
* evenly among all the available NUMA nodes. Once the node is assigned,
|
||||
* we will assign the CPU based on a simple round robin scheme.
|
||||
* For non-performance critical channels we assign the VMBUS_CONNECT_CPU.
|
||||
* Performance critical channels will be distributed 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)
|
||||
{
|
||||
@@ -732,13 +731,10 @@ static void init_vp_index(struct vmbus_channel *channel)
|
||||
u32 target_cpu;
|
||||
int numa_node;
|
||||
|
||||
if ((vmbus_proto_version == VERSION_WS2008) ||
|
||||
(vmbus_proto_version == VERSION_WIN7) || (!perf_chn) ||
|
||||
if (!perf_chn ||
|
||||
!alloc_cpumask_var(&available_mask, GFP_KERNEL)) {
|
||||
/*
|
||||
* Prior to win8, all channel interrupts are
|
||||
* delivered on VMBUS_CONNECT_CPU.
|
||||
* Also if the channel is not a performance critical
|
||||
* If the channel is not a performance critical
|
||||
* channel, bind it to VMBUS_CONNECT_CPU.
|
||||
* In case alloc_cpumask_var() fails, bind it to
|
||||
* VMBUS_CONNECT_CPU.
|
||||
@@ -931,11 +927,9 @@ static void vmbus_setup_channel_state(struct vmbus_channel *channel,
|
||||
*/
|
||||
channel->sig_event = VMBUS_EVENT_CONNECTION_ID;
|
||||
|
||||
if (vmbus_proto_version != VERSION_WS2008) {
|
||||
channel->is_dedicated_interrupt =
|
||||
(offer->is_dedicated_interrupt != 0);
|
||||
channel->sig_event = offer->connection_id;
|
||||
}
|
||||
channel->is_dedicated_interrupt =
|
||||
(offer->is_dedicated_interrupt != 0);
|
||||
channel->sig_event = offer->connection_id;
|
||||
|
||||
memcpy(&channel->offermsg, offer,
|
||||
sizeof(struct vmbus_channel_offer_channel));
|
||||
@@ -975,13 +969,17 @@ find_primary_channel_by_offer(const struct vmbus_channel_offer_channel *offer)
|
||||
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;
|
||||
|
||||
if (!hv_is_isolation_supported())
|
||||
return true;
|
||||
|
||||
if (is_hvsock_offer(offer))
|
||||
return true;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vmbus_devs); i++) {
|
||||
if (guid_equal(guid, &vmbus_devs[i].guid))
|
||||
return vmbus_devs[i].allowed_in_isolated;
|
||||
@@ -1003,7 +1001,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
|
||||
|
||||
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",
|
||||
offer->child_relid);
|
||||
atomic_dec(&vmbus_connection.offer_in_progress);
|
||||
|
||||
@@ -47,6 +47,8 @@ EXPORT_SYMBOL_GPL(vmbus_proto_version);
|
||||
|
||||
/*
|
||||
* 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[] = {
|
||||
VERSION_WIN10_V5_3,
|
||||
@@ -56,9 +58,7 @@ static __u32 vmbus_versions[] = {
|
||||
VERSION_WIN10_V4_1,
|
||||
VERSION_WIN10,
|
||||
VERSION_WIN8_1,
|
||||
VERSION_WIN8,
|
||||
VERSION_WIN7,
|
||||
VERSION_WS2008
|
||||
VERSION_WIN8
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1842,7 +1842,7 @@ static int balloon_probe(struct hv_device *dev,
|
||||
|
||||
ret = balloon_connect_vsp(dev);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
goto connect_error;
|
||||
|
||||
enable_page_reporting();
|
||||
dm_device.state = DM_INITIALIZED;
|
||||
@@ -1861,6 +1861,7 @@ probe_error:
|
||||
dm_device.thread = NULL;
|
||||
disable_page_reporting();
|
||||
vmbus_close(dev->channel);
|
||||
connect_error:
|
||||
#ifdef CONFIG_MEMORY_HOTPLUG
|
||||
unregister_memory_notifier(&hv_memory_nb);
|
||||
restore_online_page_callback(&hv_online_page);
|
||||
@@ -1882,12 +1883,21 @@ static int balloon_remove(struct hv_device *dev)
|
||||
cancel_work_sync(&dm->ha_wrk.wrk);
|
||||
|
||||
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
|
||||
unregister_memory_notifier(&hv_memory_nb);
|
||||
restore_online_page_callback(&hv_online_page);
|
||||
unregister_memory_notifier(&hv_memory_nb);
|
||||
restore_online_page_callback(&hv_online_page);
|
||||
#endif
|
||||
}
|
||||
|
||||
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(gap, tmp_gap, &has->gap_list, list) {
|
||||
@@ -1948,6 +1958,7 @@ close_channel:
|
||||
vmbus_close(dev->channel);
|
||||
out:
|
||||
dm_device.state = DM_INIT_ERROR;
|
||||
disable_page_reporting();
|
||||
#ifdef CONFIG_MEMORY_HOTPLUG
|
||||
unregister_memory_notifier(&hv_memory_nb);
|
||||
restore_online_page_callback(&hv_online_page);
|
||||
|
||||
@@ -181,7 +181,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
|
||||
|
||||
int hv_ringbuffer_write(struct vmbus_channel *channel,
|
||||
const struct kvec *kv_list, u32 kv_count,
|
||||
u64 requestid);
|
||||
u64 requestid, u64 *trans_id);
|
||||
|
||||
int hv_ringbuffer_read(struct vmbus_channel *channel,
|
||||
void *buffer, u32 buflen, u32 *buffer_actual_len,
|
||||
|
||||
@@ -283,7 +283,7 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
|
||||
/* Write to the ring buffer. */
|
||||
int hv_ringbuffer_write(struct vmbus_channel *channel,
|
||||
const struct kvec *kv_list, u32 kv_count,
|
||||
u64 requestid)
|
||||
u64 requestid, u64 *trans_id)
|
||||
{
|
||||
int i;
|
||||
u32 bytes_avail_towrite;
|
||||
@@ -294,7 +294,7 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
|
||||
unsigned long flags;
|
||||
struct hv_ring_buffer_info *outring_info = &channel->outbound;
|
||||
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)
|
||||
return -ENODEV;
|
||||
@@ -353,7 +353,15 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
|
||||
}
|
||||
}
|
||||
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 */
|
||||
prev_indices = hv_get_ring_bufferindices(outring_info);
|
||||
@@ -421,7 +429,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
|
||||
memcpy(buffer, (const char *)desc + offset, packetlen);
|
||||
|
||||
/* Advance ring index to next packet descriptor */
|
||||
__hv_pkt_iter_next(channel, desc, true);
|
||||
__hv_pkt_iter_next(channel, desc);
|
||||
|
||||
/* Notify host of update */
|
||||
hv_pkt_iter_close(channel);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
@@ -483,11 +475,14 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
|
||||
struct vmpacket_descriptor *desc, *desc_copy;
|
||||
u32 bytes_avail, pkt_len, pkt_offset;
|
||||
|
||||
desc = hv_pkt_iter_first_raw(channel);
|
||||
if (!desc)
|
||||
return NULL;
|
||||
hv_debug_delay_test(channel, MESSAGE_DELAY);
|
||||
|
||||
bytes_avail = min(rbi->pkt_buffer_size, hv_pkt_iter_avail(rbi));
|
||||
bytes_avail = hv_pkt_iter_avail(rbi);
|
||||
if (bytes_avail < sizeof(struct vmpacket_descriptor))
|
||||
return NULL;
|
||||
bytes_avail = min(rbi->pkt_buffer_size, bytes_avail);
|
||||
|
||||
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
|
||||
@@ -534,8 +529,7 @@ EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
|
||||
*/
|
||||
struct vmpacket_descriptor *
|
||||
__hv_pkt_iter_next(struct vmbus_channel *channel,
|
||||
const struct vmpacket_descriptor *desc,
|
||||
bool copy)
|
||||
const struct vmpacket_descriptor *desc)
|
||||
{
|
||||
struct hv_ring_buffer_info *rbi = &channel->inbound;
|
||||
u32 packetlen = desc->len8 << 3;
|
||||
@@ -548,7 +542,7 @@ __hv_pkt_iter_next(struct vmbus_channel *channel,
|
||||
rbi->priv_read_index -= dsize;
|
||||
|
||||
/* 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);
|
||||
|
||||
|
||||
@@ -1263,23 +1263,17 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu)
|
||||
unsigned long *recv_int_page;
|
||||
u32 maxbits, relid;
|
||||
|
||||
if (vmbus_proto_version < VERSION_WIN8) {
|
||||
maxbits = MAX_NUM_CHANNELS_SUPPORTED;
|
||||
recv_int_page = vmbus_connection.recv_int_page;
|
||||
} else {
|
||||
/*
|
||||
* When the host is win8 and beyond, the event page
|
||||
* can be directly checked to get the id of the channel
|
||||
* that has the interrupt pending.
|
||||
*/
|
||||
void *page_addr = hv_cpu->synic_event_page;
|
||||
union hv_synic_event_flags *event
|
||||
= (union hv_synic_event_flags *)page_addr +
|
||||
VMBUS_MESSAGE_SINT;
|
||||
/*
|
||||
* The event page can be directly checked to get the id of
|
||||
* the channel that has the interrupt pending.
|
||||
*/
|
||||
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;
|
||||
recv_int_page = event->flags;
|
||||
}
|
||||
maxbits = HV_EVENT_FLAGS_COUNT;
|
||||
recv_int_page = event->flags;
|
||||
|
||||
if (unlikely(!recv_int_page))
|
||||
return;
|
||||
@@ -1351,40 +1345,10 @@ static void vmbus_isr(void)
|
||||
{
|
||||
struct hv_per_cpu_context *hv_cpu
|
||||
= this_cpu_ptr(hv_context.cpu_context);
|
||||
void *page_addr = hv_cpu->synic_event_page;
|
||||
void *page_addr;
|
||||
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;
|
||||
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -54,7 +54,6 @@
|
||||
|
||||
#define VMSTOR_PROTO_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \
|
||||
(((MINOR_) & 0xff)))
|
||||
|
||||
#define VMSTOR_PROTO_VERSION_WIN6 VMSTOR_PROTO_VERSION(2, 0)
|
||||
#define VMSTOR_PROTO_VERSION_WIN7 VMSTOR_PROTO_VERSION(4, 2)
|
||||
#define VMSTOR_PROTO_VERSION_WIN8 VMSTOR_PROTO_VERSION(5, 1)
|
||||
@@ -136,20 +135,10 @@ struct hv_fc_wwn_packet {
|
||||
*/
|
||||
#define STORVSC_MAX_CMD_LEN 0x10
|
||||
|
||||
#define POST_WIN7_STORVSC_SENSE_BUFFER_SIZE 0x14
|
||||
#define PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE 0x12
|
||||
|
||||
/* Sense buffer size is the same for all versions since Windows 8 */
|
||||
#define STORVSC_SENSE_BUFFER_SIZE 0x14
|
||||
#define STORVSC_MAX_BUF_LEN_WITH_PADDING 0x14
|
||||
|
||||
/*
|
||||
* Sense buffer size changed in win8; have a run-time
|
||||
* variable to track the size we should use. This value will
|
||||
* likely change during protocol negotiation but it is valid
|
||||
* to start by assuming pre-Win8.
|
||||
*/
|
||||
static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
|
||||
|
||||
/*
|
||||
* The storage protocol version is determined during the
|
||||
* initial exchange with the host. It will indicate which
|
||||
@@ -177,18 +166,6 @@ do { \
|
||||
dev_warn(&(dev)->device, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
struct vmscsi_win8_extension {
|
||||
/*
|
||||
* The following were added in Windows 8
|
||||
*/
|
||||
u16 reserve;
|
||||
u8 queue_tag;
|
||||
u8 queue_action;
|
||||
u32 srb_flags;
|
||||
u32 time_out_value;
|
||||
u32 queue_sort_ey;
|
||||
} __packed;
|
||||
|
||||
struct vmscsi_request {
|
||||
u16 length;
|
||||
u8 srb_status;
|
||||
@@ -214,46 +191,23 @@ struct vmscsi_request {
|
||||
/*
|
||||
* The following was added in win8.
|
||||
*/
|
||||
struct vmscsi_win8_extension win8_extension;
|
||||
u16 reserve;
|
||||
u8 queue_tag;
|
||||
u8 queue_action;
|
||||
u32 srb_flags;
|
||||
u32 time_out_value;
|
||||
u32 queue_sort_ey;
|
||||
|
||||
} __attribute((packed));
|
||||
|
||||
/*
|
||||
* The list of storage protocols in order of preference.
|
||||
* The list of windows version in order of preference.
|
||||
*/
|
||||
struct vmstor_protocol {
|
||||
int protocol_version;
|
||||
int sense_buffer_size;
|
||||
int vmscsi_size_delta;
|
||||
};
|
||||
|
||||
|
||||
static const struct vmstor_protocol vmstor_protocols[] = {
|
||||
{
|
||||
static const int protocol_version[] = {
|
||||
VMSTOR_PROTO_VERSION_WIN10,
|
||||
POST_WIN7_STORVSC_SENSE_BUFFER_SIZE,
|
||||
0
|
||||
},
|
||||
{
|
||||
VMSTOR_PROTO_VERSION_WIN8_1,
|
||||
POST_WIN7_STORVSC_SENSE_BUFFER_SIZE,
|
||||
0
|
||||
},
|
||||
{
|
||||
VMSTOR_PROTO_VERSION_WIN8,
|
||||
POST_WIN7_STORVSC_SENSE_BUFFER_SIZE,
|
||||
0
|
||||
},
|
||||
{
|
||||
VMSTOR_PROTO_VERSION_WIN7,
|
||||
PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE,
|
||||
sizeof(struct vmscsi_win8_extension),
|
||||
},
|
||||
{
|
||||
VMSTOR_PROTO_VERSION_WIN6,
|
||||
PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE,
|
||||
sizeof(struct vmscsi_win8_extension),
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -409,9 +363,7 @@ static void storvsc_on_channel_callback(void *context);
|
||||
#define STORVSC_IDE_MAX_CHANNELS 1
|
||||
|
||||
/*
|
||||
* Upper bound on the size of a storvsc packet. vmscsi_size_delta is not
|
||||
* included in the calculation because it is set after STORVSC_MAX_PKT_SIZE
|
||||
* is used in storvsc_connect_to_vsp
|
||||
* Upper bound on the size of a storvsc packet.
|
||||
*/
|
||||
#define STORVSC_MAX_PKT_SIZE (sizeof(struct vmpacket_descriptor) +\
|
||||
sizeof(struct vstor_packet))
|
||||
@@ -452,17 +404,6 @@ struct storvsc_device {
|
||||
unsigned char path_id;
|
||||
unsigned char target_id;
|
||||
|
||||
/*
|
||||
* The size of the vmscsi_request has changed in win8. The
|
||||
* additional size is because of new elements added to the
|
||||
* structure. These elements are valid only when we are talking
|
||||
* to a win8 host.
|
||||
* Track the correction to size we need to apply. This value
|
||||
* will likely change during protocol negotiation but it is
|
||||
* valid to start by assuming pre-Win8.
|
||||
*/
|
||||
int vmscsi_size_delta;
|
||||
|
||||
/*
|
||||
* Max I/O, the device can support.
|
||||
*/
|
||||
@@ -795,8 +736,7 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns)
|
||||
vstor_packet->sub_channel_count = num_sc;
|
||||
|
||||
ret = vmbus_sendpacket(device->channel, vstor_packet,
|
||||
(sizeof(struct vstor_packet) -
|
||||
stor_device->vmscsi_size_delta),
|
||||
sizeof(struct vstor_packet),
|
||||
VMBUS_RQST_INIT,
|
||||
VM_PKT_DATA_INBAND,
|
||||
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
|
||||
@@ -864,8 +804,7 @@ static int storvsc_execute_vstor_op(struct hv_device *device,
|
||||
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
|
||||
|
||||
ret = vmbus_sendpacket(device->channel, vstor_packet,
|
||||
(sizeof(struct vstor_packet) -
|
||||
stor_device->vmscsi_size_delta),
|
||||
sizeof(struct vstor_packet),
|
||||
VMBUS_RQST_INIT,
|
||||
VM_PKT_DATA_INBAND,
|
||||
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
|
||||
@@ -915,14 +854,13 @@ static int storvsc_channel_init(struct hv_device *device, bool is_fc)
|
||||
* Query host supported protocol version.
|
||||
*/
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(protocol_version); i++) {
|
||||
/* reuse the packet for version range supported */
|
||||
memset(vstor_packet, 0, sizeof(struct vstor_packet));
|
||||
vstor_packet->operation =
|
||||
VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
|
||||
|
||||
vstor_packet->version.major_minor =
|
||||
vmstor_protocols[i].protocol_version;
|
||||
vstor_packet->version.major_minor = protocol_version[i];
|
||||
|
||||
/*
|
||||
* The revision number is only used in Windows; set it to 0.
|
||||
@@ -936,21 +874,16 @@ static int storvsc_channel_init(struct hv_device *device, bool is_fc)
|
||||
return -EINVAL;
|
||||
|
||||
if (vstor_packet->status == 0) {
|
||||
vmstor_proto_version =
|
||||
vmstor_protocols[i].protocol_version;
|
||||
|
||||
sense_buffer_size =
|
||||
vmstor_protocols[i].sense_buffer_size;
|
||||
|
||||
stor_device->vmscsi_size_delta =
|
||||
vmstor_protocols[i].vmscsi_size_delta;
|
||||
vmstor_proto_version = protocol_version[i];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vstor_packet->status != 0)
|
||||
if (vstor_packet->status != 0) {
|
||||
dev_err(&device->device, "Obsolete Hyper-V version\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
memset(vstor_packet, 0, sizeof(struct vstor_packet));
|
||||
@@ -986,11 +919,10 @@ static int storvsc_channel_init(struct hv_device *device, bool is_fc)
|
||||
cpumask_set_cpu(device->channel->target_cpu,
|
||||
&stor_device->alloced_cpus);
|
||||
|
||||
if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN8) {
|
||||
if (vstor_packet->storage_channel_properties.flags &
|
||||
STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL)
|
||||
process_sub_channels = true;
|
||||
}
|
||||
if (vstor_packet->storage_channel_properties.flags &
|
||||
STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL)
|
||||
process_sub_channels = true;
|
||||
|
||||
stor_device->max_transfer_bytes =
|
||||
vstor_packet->storage_channel_properties.max_transfer_bytes;
|
||||
|
||||
@@ -1197,7 +1129,7 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device,
|
||||
* Copy over the sense_info_length, but limit to the known max
|
||||
* size if Hyper-V returns a bad value.
|
||||
*/
|
||||
stor_pkt->vm_srb.sense_info_length = min_t(u8, sense_buffer_size,
|
||||
stor_pkt->vm_srb.sense_info_length = min_t(u8, STORVSC_SENSE_BUFFER_SIZE,
|
||||
vstor_packet->vm_srb.sense_info_length);
|
||||
|
||||
if (vstor_packet->vm_srb.scsi_status != 0 ||
|
||||
@@ -1289,8 +1221,8 @@ static void storvsc_on_channel_callback(void *context)
|
||||
struct storvsc_cmd_request *request = NULL;
|
||||
u32 pktlen = hv_pkt_datalen(desc);
|
||||
u64 rqst_id = desc->trans_id;
|
||||
u32 minlen = rqst_id ? sizeof(struct vstor_packet) -
|
||||
stor_device->vmscsi_size_delta : sizeof(enum vstor_packet_operation);
|
||||
u32 minlen = rqst_id ? sizeof(struct vstor_packet) :
|
||||
sizeof(enum vstor_packet_operation);
|
||||
|
||||
if (pktlen < minlen) {
|
||||
dev_err(&device->device,
|
||||
@@ -1346,7 +1278,7 @@ static void storvsc_on_channel_callback(void *context)
|
||||
}
|
||||
|
||||
memcpy(&request->vstor_packet, packet,
|
||||
(sizeof(struct vstor_packet) - stor_device->vmscsi_size_delta));
|
||||
sizeof(struct vstor_packet));
|
||||
complete(&request->wait_event);
|
||||
}
|
||||
}
|
||||
@@ -1557,11 +1489,10 @@ static int storvsc_do_io(struct hv_device *device,
|
||||
found_channel:
|
||||
vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
|
||||
|
||||
vstor_packet->vm_srb.length = (sizeof(struct vmscsi_request) -
|
||||
stor_device->vmscsi_size_delta);
|
||||
vstor_packet->vm_srb.length = sizeof(struct vmscsi_request);
|
||||
|
||||
|
||||
vstor_packet->vm_srb.sense_info_length = sense_buffer_size;
|
||||
vstor_packet->vm_srb.sense_info_length = STORVSC_SENSE_BUFFER_SIZE;
|
||||
|
||||
|
||||
vstor_packet->vm_srb.data_transfer_length =
|
||||
@@ -1574,13 +1505,11 @@ found_channel:
|
||||
ret = vmbus_sendpacket_mpb_desc(outgoing_channel,
|
||||
request->payload, request->payload_sz,
|
||||
vstor_packet,
|
||||
(sizeof(struct vstor_packet) -
|
||||
stor_device->vmscsi_size_delta),
|
||||
sizeof(struct vstor_packet),
|
||||
(unsigned long)request);
|
||||
} else {
|
||||
ret = vmbus_sendpacket(outgoing_channel, vstor_packet,
|
||||
(sizeof(struct vstor_packet) -
|
||||
stor_device->vmscsi_size_delta),
|
||||
sizeof(struct vstor_packet),
|
||||
(unsigned long)request,
|
||||
VM_PKT_DATA_INBAND,
|
||||
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
|
||||
@@ -1684,8 +1613,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
|
||||
vstor_packet->vm_srb.path_id = stor_device->path_id;
|
||||
|
||||
ret = vmbus_sendpacket(device->channel, vstor_packet,
|
||||
(sizeof(struct vstor_packet) -
|
||||
stor_device->vmscsi_size_delta),
|
||||
sizeof(struct vstor_packet),
|
||||
VMBUS_RQST_RESET,
|
||||
VM_PKT_DATA_INBAND,
|
||||
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
|
||||
@@ -1778,31 +1706,31 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
|
||||
|
||||
memset(&cmd_request->vstor_packet, 0, sizeof(struct vstor_packet));
|
||||
vm_srb = &cmd_request->vstor_packet.vm_srb;
|
||||
vm_srb->win8_extension.time_out_value = 60;
|
||||
vm_srb->time_out_value = 60;
|
||||
|
||||
vm_srb->win8_extension.srb_flags |=
|
||||
vm_srb->srb_flags |=
|
||||
SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
|
||||
|
||||
if (scmnd->device->tagged_supported) {
|
||||
vm_srb->win8_extension.srb_flags |=
|
||||
vm_srb->srb_flags |=
|
||||
(SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE);
|
||||
vm_srb->win8_extension.queue_tag = SP_UNTAGGED;
|
||||
vm_srb->win8_extension.queue_action = SRB_SIMPLE_TAG_REQUEST;
|
||||
vm_srb->queue_tag = SP_UNTAGGED;
|
||||
vm_srb->queue_action = SRB_SIMPLE_TAG_REQUEST;
|
||||
}
|
||||
|
||||
/* Build the SRB */
|
||||
switch (scmnd->sc_data_direction) {
|
||||
case DMA_TO_DEVICE:
|
||||
vm_srb->data_in = WRITE_TYPE;
|
||||
vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DATA_OUT;
|
||||
vm_srb->srb_flags |= SRB_FLAGS_DATA_OUT;
|
||||
break;
|
||||
case DMA_FROM_DEVICE:
|
||||
vm_srb->data_in = READ_TYPE;
|
||||
vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DATA_IN;
|
||||
vm_srb->srb_flags |= SRB_FLAGS_DATA_IN;
|
||||
break;
|
||||
case DMA_NONE:
|
||||
vm_srb->data_in = UNKNOWN_TYPE;
|
||||
vm_srb->win8_extension.srb_flags |= SRB_FLAGS_NO_DATA_TRANSFER;
|
||||
vm_srb->srb_flags |= SRB_FLAGS_NO_DATA_TRANSFER;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
@@ -1966,34 +1894,16 @@ static int storvsc_probe(struct hv_device *device,
|
||||
bool is_fc = ((dev_id->driver_data == SFC_GUID) ? true : false);
|
||||
int target = 0;
|
||||
struct storvsc_device *stor_device;
|
||||
int max_luns_per_target;
|
||||
int max_targets;
|
||||
int max_channels;
|
||||
int max_sub_channels = 0;
|
||||
|
||||
/*
|
||||
* Based on the windows host we are running on,
|
||||
* set state to properly communicate with the host.
|
||||
* We support sub-channels for storage on SCSI and FC controllers.
|
||||
* The number of sub-channels offerred is based on the number of
|
||||
* VCPUs in the guest.
|
||||
*/
|
||||
|
||||
if (vmbus_proto_version < VERSION_WIN8) {
|
||||
max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET;
|
||||
max_targets = STORVSC_IDE_MAX_TARGETS;
|
||||
max_channels = STORVSC_IDE_MAX_CHANNELS;
|
||||
} else {
|
||||
max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET;
|
||||
max_targets = STORVSC_MAX_TARGETS;
|
||||
max_channels = STORVSC_MAX_CHANNELS;
|
||||
/*
|
||||
* On Windows8 and above, we support sub-channels for storage
|
||||
* on SCSI and FC controllers.
|
||||
* The number of sub-channels offerred is based on the number of
|
||||
* VCPUs in the guest.
|
||||
*/
|
||||
if (!dev_is_ide)
|
||||
max_sub_channels =
|
||||
(num_cpus - 1) / storvsc_vcpus_per_sub_channel;
|
||||
}
|
||||
if (!dev_is_ide)
|
||||
max_sub_channels =
|
||||
(num_cpus - 1) / storvsc_vcpus_per_sub_channel;
|
||||
|
||||
scsi_driver.can_queue = max_outstanding_req_per_channel *
|
||||
(max_sub_channels + 1) *
|
||||
@@ -2022,7 +1932,6 @@ static int storvsc_probe(struct hv_device *device,
|
||||
init_waitqueue_head(&stor_device->waiting_to_drain);
|
||||
stor_device->device = device;
|
||||
stor_device->host = host;
|
||||
stor_device->vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
|
||||
spin_lock_init(&stor_device->lock);
|
||||
hv_set_drvdata(device, stor_device);
|
||||
dma_set_min_align_mask(&device->device, HV_HYP_PAGE_SIZE - 1);
|
||||
@@ -2046,9 +1955,9 @@ static int storvsc_probe(struct hv_device *device,
|
||||
break;
|
||||
|
||||
case SCSI_GUID:
|
||||
host->max_lun = max_luns_per_target;
|
||||
host->max_id = max_targets;
|
||||
host->max_channel = max_channels - 1;
|
||||
host->max_lun = STORVSC_MAX_LUNS_PER_TARGET;
|
||||
host->max_id = STORVSC_MAX_TARGETS;
|
||||
host->max_channel = STORVSC_MAX_CHANNELS - 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2235,10 +2144,6 @@ static int __init storvsc_drv_init(void)
|
||||
* than the ring buffer size since that page is reserved for
|
||||
* the ring buffer indices) by the max request size (which is
|
||||
* vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
|
||||
*
|
||||
* The computation underestimates max_outstanding_req_per_channel
|
||||
* for Win7 and older hosts because it does not take into account
|
||||
* the vmscsi_size_delta correction to the max request size.
|
||||
*/
|
||||
max_outstanding_req_per_channel =
|
||||
((storvsc_ringbuffer_size - PAGE_SIZE) /
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#define MAX_VMBUS_PKT_SIZE 0x4000
|
||||
|
||||
#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_WIN8 SYNTHVID_VERSION(3, 2)
|
||||
#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
|
||||
@@ -70,13 +71,7 @@
|
||||
#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
|
||||
#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
|
||||
|
||||
#define SYNTHVID_DEPTH_WIN7 16
|
||||
#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 PCI_VENDOR_ID_MICROSOFT 0x1414
|
||||
@@ -643,12 +638,6 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
|
||||
case VERSION_WIN8:
|
||||
case VERSION_WIN8_1:
|
||||
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;
|
||||
default:
|
||||
ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
|
||||
@@ -660,11 +649,7 @@ static int synthvid_connect_vsp(struct hv_device *hdev)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (par->synthvid_version == SYNTHVID_VERSION_WIN7)
|
||||
screen_depth = SYNTHVID_DEPTH_WIN7;
|
||||
else
|
||||
screen_depth = SYNTHVID_DEPTH_WIN8;
|
||||
|
||||
screen_depth = SYNTHVID_DEPTH_WIN8;
|
||||
if (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10)) {
|
||||
ret = synthvid_get_supported_resolution(hdev);
|
||||
if (ret)
|
||||
@@ -933,9 +918,7 @@ static void hvfb_get_option(struct fb_info *info)
|
||||
(synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) &&
|
||||
(x * y * screen_depth / 8 > screen_fb_size)) ||
|
||||
(par->synthvid_version == SYNTHVID_VERSION_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))) {
|
||||
x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8)) {
|
||||
pr_err("Screen resolution option is out of range: skipped\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -230,15 +230,19 @@ static inline u32 hv_get_avail_to_write_percent(
|
||||
* two 16 bit quantities: major_number. minor_number.
|
||||
*
|
||||
* 0 . 13 (Windows Server 2008)
|
||||
* 1 . 1 (Windows 7)
|
||||
* 2 . 4 (Windows 8)
|
||||
* 3 . 0 (Windows 8 R2)
|
||||
* 1 . 1 (Windows 7, WS2008 R2)
|
||||
* 2 . 4 (Windows 8, WS2012)
|
||||
* 3 . 0 (Windows 8.1, WS2012 R2)
|
||||
* 4 . 0 (Windows 10)
|
||||
* 4 . 1 (Windows 10 RS3)
|
||||
* 5 . 0 (Newer Windows 10)
|
||||
* 5 . 1 (Windows 10 RS4)
|
||||
* 5 . 2 (Windows Server 2019, RS5)
|
||||
* 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))
|
||||
@@ -788,6 +792,7 @@ struct vmbus_requestor {
|
||||
|
||||
#define VMBUS_NO_RQSTOR U64_MAX
|
||||
#define VMBUS_RQST_ERROR (U64_MAX - 1)
|
||||
#define VMBUS_RQST_ADDR_ANY U64_MAX
|
||||
/* NetVSC-specific */
|
||||
#define VMBUS_RQST_ID_NO_RESPONSE (U64_MAX - 2)
|
||||
/* StorVSC-specific */
|
||||
@@ -1041,13 +1046,36 @@ struct vmbus_channel {
|
||||
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_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);
|
||||
|
||||
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)
|
||||
{
|
||||
return !!(c->offermsg.offer.chn_flags &
|
||||
VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER);
|
||||
return is_hvsock_offer(&c->offermsg);
|
||||
}
|
||||
|
||||
static inline bool is_sub_channel(const struct vmbus_channel *c)
|
||||
@@ -1161,6 +1189,13 @@ extern int vmbus_open(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,
|
||||
void *buffer,
|
||||
u32 bufferLen,
|
||||
@@ -1451,12 +1486,14 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size);
|
||||
0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f)
|
||||
|
||||
/*
|
||||
* Linux doesn't support the 3 devices: the first two are for
|
||||
* Automatic Virtual Machine Activation, and the third is for
|
||||
* Remote Desktop Virtualization.
|
||||
* Linux doesn't support these 4 devices: the first two are for
|
||||
* Automatic Virtual Machine Activation, the third is for
|
||||
* Remote Desktop Virtualization, and the fourth is Initial
|
||||
* Machine Configuration (IMC) used only by Windows guests.
|
||||
* {f8e65716-3cb3-4a06-9a60-1889c5cccab5}
|
||||
* {3375baf4-9e15-4b30-b765-67acb10d607b}
|
||||
* {276aacf4-ac15-426c-98dd-7521ad3f01fe}
|
||||
* {c376c1c3-d276-48d2-90a9-c04748072c60}
|
||||
*/
|
||||
|
||||
#define HV_AVMA1_GUID \
|
||||
@@ -1471,6 +1508,10 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size);
|
||||
.guid = GUID_INIT(0x276aacf4, 0xac15, 0x426c, 0x98, 0xdd, \
|
||||
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
|
||||
*/
|
||||
@@ -1663,56 +1704,34 @@ static inline u32 hv_pkt_datalen(const struct vmpacket_descriptor *desc)
|
||||
return (desc->len8 << 3) - (desc->offset8 << 3);
|
||||
}
|
||||
|
||||
|
||||
struct vmpacket_descriptor *
|
||||
hv_pkt_iter_first_raw(struct vmbus_channel *channel);
|
||||
/* Get packet length associated with descriptor */
|
||||
static inline u32 hv_pkt_len(const struct vmpacket_descriptor *desc)
|
||||
{
|
||||
return desc->len8 << 3;
|
||||
}
|
||||
|
||||
struct vmpacket_descriptor *
|
||||
hv_pkt_iter_first(struct vmbus_channel *channel);
|
||||
|
||||
struct vmpacket_descriptor *
|
||||
__hv_pkt_iter_next(struct vmbus_channel *channel,
|
||||
const struct vmpacket_descriptor *pkt,
|
||||
bool copy);
|
||||
const struct vmpacket_descriptor *pkt);
|
||||
|
||||
void hv_pkt_iter_close(struct vmbus_channel *channel);
|
||||
|
||||
static inline struct vmpacket_descriptor *
|
||||
hv_pkt_iter_next_pkt(struct vmbus_channel *channel,
|
||||
const struct vmpacket_descriptor *pkt,
|
||||
bool copy)
|
||||
hv_pkt_iter_next(struct vmbus_channel *channel,
|
||||
const struct vmpacket_descriptor *pkt)
|
||||
{
|
||||
struct vmpacket_descriptor *nxt;
|
||||
|
||||
nxt = __hv_pkt_iter_next(channel, pkt, copy);
|
||||
nxt = __hv_pkt_iter_next(channel, pkt);
|
||||
if (!nxt)
|
||||
hv_pkt_iter_close(channel);
|
||||
|
||||
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) \
|
||||
for (pkt = hv_pkt_iter_first(channel); pkt; \
|
||||
pkt = hv_pkt_iter_next(channel, pkt))
|
||||
|
||||
@@ -78,6 +78,9 @@ struct hvs_send_buf {
|
||||
ALIGN((payload_len), 8) + \
|
||||
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 {
|
||||
guid_t srv_id;
|
||||
|
||||
@@ -378,6 +381,8 @@ static void hvs_open_connection(struct vmbus_channel *chan)
|
||||
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,
|
||||
conn_from_host ? new : sk);
|
||||
if (ret != 0) {
|
||||
@@ -572,12 +577,18 @@ static bool hvs_dgram_allow(u32 cid, u32 port)
|
||||
static int hvs_update_recv_data(struct hvsock *hvs)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
|
||||
if (payload_len == 0)
|
||||
@@ -602,7 +613,9 @@ static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg,
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -616,7 +629,7 @@ static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg,
|
||||
|
||||
hvs->recv_data_len -= to_read;
|
||||
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) {
|
||||
ret = hvs_update_recv_data(hvs);
|
||||
if (ret)
|
||||
|
||||
Reference in New Issue
Block a user