Re: [PATCH 06/17] mshv: SynIC port and connection hypercalls

From: Vitaly Kuznetsov
Date: Thu Jun 10 2021 - 08:19:39 EST


Vineeth Pillai <viremana@xxxxxxxxxxxxxxxxxxx> writes:

> Hyper-V enables inter-partition communication through the port and
> connection constructs. More details about ports and connections in
> TLFS chapter 11.
>
> Implement hypercalls related to ports and connections for enabling
> inter-partiion communication.
>
> Signed-off-by: Vineeth Pillai <viremana@xxxxxxxxxxxxxxxxxxx>
> ---
> drivers/hv/hv_call.c | 161 +++++++++++++++++++++++++
> drivers/hv/mshv.h | 12 ++
> include/asm-generic/hyperv-tlfs.h | 55 +++++++++
> include/linux/hyperv.h | 9 --
> include/uapi/asm-generic/hyperv-tlfs.h | 76 ++++++++++++
> 5 files changed, 304 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/hv/hv_call.c b/drivers/hv/hv_call.c
> index 025d4e2b892f..57db3a8ac94a 100644
> --- a/drivers/hv/hv_call.c
> +++ b/drivers/hv/hv_call.c
> @@ -742,3 +742,164 @@ int hv_call_translate_virtual_address(
> return hv_status_to_errno(status);
> }
>
> +
> +int
> +hv_call_create_port(u64 port_partition_id, union hv_port_id port_id,
> + u64 connection_partition_id,
> + struct hv_port_info *port_info,
> + u8 port_vtl, u8 min_connection_vtl, int node)
> +{
> + struct hv_create_port *input;
> + unsigned long flags;
> + int ret = 0;
> + int status;
> +
> + do {
> + local_irq_save(flags);
> + input = (struct hv_create_port *)(*this_cpu_ptr(
> + hyperv_pcpu_input_arg));
> + memset(input, 0, sizeof(*input));
> +
> + input->port_partition_id = port_partition_id;
> + input->port_id = port_id;
> + input->connection_partition_id = connection_partition_id;
> + input->port_info = *port_info;
> + input->port_vtl = port_vtl;
> + input->min_connection_vtl = min_connection_vtl;
> + input->proximity_domain_info =
> + numa_node_to_proximity_domain_info(node);
> + status = hv_do_hypercall(HVCALL_CREATE_PORT, input,
> + NULL) & HV_HYPERCALL_RESULT_MASK;
> + local_irq_restore(flags);
> + if (status == HV_STATUS_SUCCESS)
> + break;
> +
> + if (status != HV_STATUS_INSUFFICIENT_MEMORY) {
> + pr_err("%s: %s\n",
> + __func__, hv_status_to_string(status));
> + ret = -hv_status_to_errno(status);

In Nuno's "x86/hyperv: convert hyperv statuses to linux error codes"
patch, hv_status_to_errno() already returns negatives:

+int hv_status_to_errno(u64 hv_status)
+{
+ switch (hv_result(hv_status)) {
+ case HV_STATUS_SUCCESS:
+ return 0;
+ case HV_STATUS_INVALID_PARAMETER:
+ case HV_STATUS_UNKNOWN_PROPERTY:
+ case HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE:
+ case HV_STATUS_INVALID_VP_INDEX:
+ case HV_STATUS_INVALID_REGISTER_VALUE:
+ case HV_STATUS_INVALID_LP_INDEX:
+ return -EINVAL;
+ case HV_STATUS_ACCESS_DENIED:
+ case HV_STATUS_OPERATION_DENIED:
+ return -EACCES;
+ case HV_STATUS_NOT_ACKNOWLEDGED:
+ case HV_STATUS_INVALID_VP_STATE:
+ case HV_STATUS_INVALID_PARTITION_STATE:
+ return -EBADFD;
+ }
+ return -ENOTRECOVERABLE;
+}
+EXPORT_SYMBOL_GPL(hv_status_to_errno);
+

> + break;
> + }
> + ret = hv_call_deposit_pages(NUMA_NO_NODE,
> + port_partition_id, 1);
> +
> + } while (!ret);
> +
> + return ret;
> +}
> +
> +int
> +hv_call_delete_port(u64 port_partition_id, union hv_port_id port_id)
> +{
> + union hv_delete_port input = { 0 };
> + unsigned long flags;
> + int status;
> +
> + local_irq_save(flags);
> + input.port_partition_id = port_partition_id;
> + input.port_id = port_id;
> + status = hv_do_fast_hypercall16(HVCALL_DELETE_PORT,
> + input.as_uint64[0],
> + input.as_uint64[1]) &
> + HV_HYPERCALL_RESULT_MASK;
> + local_irq_restore(flags);
> +
> + if (status != HV_STATUS_SUCCESS) {
> + pr_err("%s: %s\n", __func__, hv_status_to_string(status));
> + return -hv_status_to_errno(status);
> + }
> +
> + return 0;
> +}
> +
> +int
> +hv_call_connect_port(u64 port_partition_id, union hv_port_id port_id,
> + u64 connection_partition_id,
> + union hv_connection_id connection_id,
> + struct hv_connection_info *connection_info,
> + u8 connection_vtl, int node)
> +{
> + struct hv_connect_port *input;
> + unsigned long flags;
> + int ret = 0, status;
> +
> + do {
> + local_irq_save(flags);
> + input = (struct hv_connect_port *)(*this_cpu_ptr(
> + hyperv_pcpu_input_arg));
> + memset(input, 0, sizeof(*input));
> + input->port_partition_id = port_partition_id;
> + input->port_id = port_id;
> + input->connection_partition_id = connection_partition_id;
> + input->connection_id = connection_id;
> + input->connection_info = *connection_info;
> + input->connection_vtl = connection_vtl;
> + input->proximity_domain_info =
> + numa_node_to_proximity_domain_info(node);
> + status = hv_do_hypercall(HVCALL_CONNECT_PORT, input,
> + NULL) & HV_HYPERCALL_RESULT_MASK;
> +
> + local_irq_restore(flags);
> + if (status == HV_STATUS_SUCCESS)
> + break;
> +
> + if (status != HV_STATUS_INSUFFICIENT_MEMORY) {
> + pr_err("%s: %s\n",
> + __func__, hv_status_to_string(status));
> + ret = -hv_status_to_errno(status);
> + break;
> + }
> + ret = hv_call_deposit_pages(NUMA_NO_NODE,
> + connection_partition_id, 1);
> + } while (!ret);
> +
> + return ret;
> +}
> +
> +int
> +hv_call_disconnect_port(u64 connection_partition_id,
> + union hv_connection_id connection_id)
> +{
> + union hv_disconnect_port input = { 0 };
> + unsigned long flags;
> + int status;
> +
> + local_irq_save(flags);
> + input.connection_partition_id = connection_partition_id;
> + input.connection_id = connection_id;
> + input.is_doorbell = 1;
> + status = hv_do_fast_hypercall16(HVCALL_DISCONNECT_PORT,
> + input.as_uint64[0],
> + input.as_uint64[1]) &
> + HV_HYPERCALL_RESULT_MASK;
> + local_irq_restore(flags);
> +
> + if (status != HV_STATUS_SUCCESS) {
> + pr_err("%s: %s\n", __func__, hv_status_to_string(status));
> + return -hv_status_to_errno(status);
> + }
> +
> + return 0;
> +}
> +
> +int
> +hv_call_notify_port_ring_empty(u32 sint_index)
> +{
> + union hv_notify_port_ring_empty input = { 0 };
> + unsigned long flags;
> + int status;
> +
> + local_irq_save(flags);
> + input.sint_index = sint_index;
> + status = hv_do_fast_hypercall8(HVCALL_NOTIFY_PORT_RING_EMPTY,
> + input.as_uint64) &
> + HV_HYPERCALL_RESULT_MASK;
> + local_irq_restore(flags);
> +
> + if (status != HV_STATUS_SUCCESS) {
> + pr_err("%s: %s\n", __func__, hv_status_to_string(status));
> + return -hv_status_to_errno(status);
> + }
> +
> + return 0;
> +}
> diff --git a/drivers/hv/mshv.h b/drivers/hv/mshv.h
> index 037291a0ad45..e16818e977b9 100644
> --- a/drivers/hv/mshv.h
> +++ b/drivers/hv/mshv.h
> @@ -117,4 +117,16 @@ int hv_call_translate_virtual_address(
> u64 *gpa,
> union hv_translate_gva_result *result);
>
> +int hv_call_create_port(u64 port_partition_id, union hv_port_id port_id,
> + u64 connection_partition_id, struct hv_port_info *port_info,
> + u8 port_vtl, u8 min_connection_vtl, int node);
> +int hv_call_delete_port(u64 port_partition_id, union hv_port_id port_id);
> +int hv_call_connect_port(u64 port_partition_id, union hv_port_id port_id,
> + u64 connection_partition_id,
> + union hv_connection_id connection_id,
> + struct hv_connection_info *connection_info,
> + u8 connection_vtl, int node);
> +int hv_call_disconnect_port(u64 connection_partition_id,
> + union hv_connection_id connection_id);
> +int hv_call_notify_port_ring_empty(u32 sint_index);
> #endif /* _MSHV_H */
> diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h
> index f70391a3320f..42e0237b0da8 100644
> --- a/include/asm-generic/hyperv-tlfs.h
> +++ b/include/asm-generic/hyperv-tlfs.h
> @@ -159,6 +159,8 @@ struct ms_hyperv_tsc_page {
> #define HVCALL_GET_VP_REGISTERS 0x0050
> #define HVCALL_SET_VP_REGISTERS 0x0051
> #define HVCALL_TRANSLATE_VIRTUAL_ADDRESS 0x0052
> +#define HVCALL_DELETE_PORT 0x0058
> +#define HVCALL_DISCONNECT_PORT 0x005b
> #define HVCALL_POST_MESSAGE 0x005c
> #define HVCALL_SIGNAL_EVENT 0x005d
> #define HVCALL_POST_DEBUG_DATA 0x0069
> @@ -168,7 +170,10 @@ struct ms_hyperv_tsc_page {
> #define HVCALL_MAP_DEVICE_INTERRUPT 0x007c
> #define HVCALL_UNMAP_DEVICE_INTERRUPT 0x007d
> #define HVCALL_RETARGET_INTERRUPT 0x007e
> +#define HVCALL_NOTIFY_PORT_RING_EMPTY 0x008b
> #define HVCALL_ASSERT_VIRTUAL_INTERRUPT 0x0094
> +#define HVCALL_CREATE_PORT 0x0095
> +#define HVCALL_CONNECT_PORT 0x0096
> #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
> #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
> #define HVCALL_MAP_VP_STATE_PAGE 0x00e1
> @@ -949,4 +954,54 @@ struct hv_translate_virtual_address_out {
> u64 gpa_page;
> } __packed;
>
> +struct hv_create_port {
> + u64 port_partition_id;
> + union hv_port_id port_id;
> + u8 port_vtl;
> + u8 min_connection_vtl;
> + u16 padding;
> + u64 connection_partition_id;
> + struct hv_port_info port_info;
> + union hv_proximity_domain_info proximity_domain_info;
> +} __packed;
> +
> +union hv_delete_port {
> + u64 as_uint64[2];
> + struct {
> + u64 port_partition_id;
> + union hv_port_id port_id;
> + u32 reserved;
> + } __packed;
> +};
> +
> +union hv_notify_port_ring_empty {
> + u64 as_uint64;
> + struct {
> + u32 sint_index;
> + u32 reserved;
> + } __packed;
> +};
> +
> +struct hv_connect_port {
> + u64 connection_partition_id;
> + union hv_connection_id connection_id;
> + u8 connection_vtl;
> + u8 rsvdz0;
> + u16 rsvdz1;
> + u64 port_partition_id;
> + union hv_port_id port_id;
> + u32 reserved2;
> + struct hv_connection_info connection_info;
> + union hv_proximity_domain_info proximity_domain_info;
> +} __packed;
> +
> +union hv_disconnect_port {
> + u64 as_uint64[2];
> + struct {
> + u64 connection_partition_id;
> + union hv_connection_id connection_id;
> + u32 is_doorbell: 1;
> + u32 reserved: 31;
> + } __packed;
> +};
> #endif
> diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
> index 2e859d2f9609..76ff26579622 100644
> --- a/include/linux/hyperv.h
> +++ b/include/linux/hyperv.h
> @@ -750,15 +750,6 @@ struct vmbus_close_msg {
> struct vmbus_channel_close_channel msg;
> };
>
> -/* Define connection identifier type. */
> -union hv_connection_id {
> - u32 asu32;
> - struct {
> - u32 id:24;
> - u32 reserved:8;
> - } u;
> -};
> -
> enum vmbus_device_type {
> HV_IDE = 0,
> HV_SCSI,
> diff --git a/include/uapi/asm-generic/hyperv-tlfs.h b/include/uapi/asm-generic/hyperv-tlfs.h
> index 388c4eb29212..2031115c6cce 100644
> --- a/include/uapi/asm-generic/hyperv-tlfs.h
> +++ b/include/uapi/asm-generic/hyperv-tlfs.h
> @@ -53,6 +53,25 @@ union hv_message_flags {
> } __packed;
> };
>
> +enum hv_port_type {
> + HV_PORT_TYPE_MESSAGE = 1,
> + HV_PORT_TYPE_EVENT = 2,
> + HV_PORT_TYPE_MONITOR = 3,
> + HV_PORT_TYPE_DOORBELL = 4 // Root Partition only
> +};
> +
> +
> +/*
> + * Doorbell connection_info flags.
> + */
> +#define HV_DOORBELL_FLAG_TRIGGER_SIZE_MASK 0x00000007
> +#define HV_DOORBELL_FLAG_TRIGGER_SIZE_ANY 0x00000000
> +#define HV_DOORBELL_FLAG_TRIGGER_SIZE_BYTE 0x00000001
> +#define HV_DOORBELL_FLAG_TRIGGER_SIZE_WORD 0x00000002
> +#define HV_DOORBELL_FLAG_TRIGGER_SIZE_DWORD 0x00000003
> +#define HV_DOORBELL_FLAG_TRIGGER_SIZE_QWORD 0x00000004
> +#define HV_DOORBELL_FLAG_TRIGGER_ANY_VALUE 0x80000000
> +
> /* Define port identifier type. */
> union hv_port_id {
> __u32 asu32;
> @@ -62,6 +81,63 @@ union hv_port_id {
> } __packed u;
> };
>
> +struct hv_port_info {
> + enum hv_port_type port_type;
> + __u32 padding;
> + union {
> + struct {
> + __u32 target_sint;
> + __u32 target_vp;
> + __u64 rsvdz;
> + } message_port_info;
> + struct {
> + __u32 target_sint;
> + __u32 target_vp;
> + __u16 base_flag_number;
> + __u16 flag_count;
> + __u32 rsvdz;
> + } event_port_info;
> + struct {
> + __u64 monitor_address;
> + __u64 rsvdz;
> + } monitor_port_info;
> + struct {
> + __u32 target_sint;
> + __u32 target_vp;
> + __u64 rsvdz;
> + } doorbell_port_info;
> + };
> +};
> +
> +union hv_connection_id {
> + __u32 asu32;
> + struct {
> + __u32 id:24;
> + __u32 reserved:8;
> + } u;
> +};
> +
> +struct hv_connection_info {
> + enum hv_port_type port_type;
> + __u32 padding;
> + union {
> + struct {
> + __u64 rsvdz;
> + } message_connection_info;
> + struct {
> + __u64 rsvdz;
> + } event_connection_info;
> + struct {
> + __u64 monitor_address;
> + } monitor_connection_info;
> + struct {
> + __u64 gpa;
> + __u64 trigger_value;
> + __u64 flags;
> + } doorbell_connection_info;
> + };
> +};
> +
> /* Define synthetic interrupt controller message header. */
> struct hv_message_header {
> __u32 message_type;

--
Vitaly