Commit 4f98616b authored by Michael Kelley's avatar Michael Kelley Committed by Jakub Kicinski
Browse files

hv_netvsc: Use vmbus_sendpacket_mpb_desc() to send VMBus messages



netvsc currently uses vmbus_sendpacket_pagebuffer() to send VMBus
messages. This function creates a series of GPA ranges, each of which
contains a single PFN. However, if the rndis header in the VMBus
message crosses a page boundary, the netvsc protocol with the host
requires that both PFNs for the rndis header must be in a single "GPA
range" data structure, which isn't possible with
vmbus_sendpacket_pagebuffer(). As the first step in fixing this, add a
new function netvsc_build_mpb_array() to build a VMBus message with
multiple GPA ranges, each of which may contain multiple PFNs. Use
vmbus_sendpacket_mpb_desc() to send this VMBus message to the host.

There's no functional change since higher levels of netvsc don't
maintain or propagate knowledge of contiguous PFNs. Based on its
input, netvsc_build_mpb_array() still produces a separate GPA range
for each PFN and the behavior is the same as with
vmbus_sendpacket_pagebuffer(). But the groundwork is laid for a
subsequent patch to provide the necessary grouping.

Cc: <stable@vger.kernel.org> # 6.1.x
Signed-off-by: default avatarMichael Kelley <mhklinux@outlook.com>
Link: https://patch.msgid.link/20250513000604.1396-3-mhklinux@outlook.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 380b75d3
Loading
Loading
Loading
Loading
+45 −5
Original line number Diff line number Diff line
@@ -1055,6 +1055,42 @@ static int netvsc_dma_map(struct hv_device *hv_dev,
	return 0;
}

/* Build an "array" of mpb entries describing the data to be transferred
 * over VMBus. After the desc header fields, each "array" entry is variable
 * size, and each entry starts after the end of the previous entry. The
 * "offset" and "len" fields for each entry imply the size of the entry.
 *
 * The pfns are in HV_HYP_PAGE_SIZE, because all communication with Hyper-V
 * uses that granularity, even if the system page size of the guest is larger.
 * Each entry in the input "pb" array must describe a contiguous range of
 * guest physical memory so that the pfns are sequential if the range crosses
 * a page boundary. The offset field must be < HV_HYP_PAGE_SIZE.
 */
static inline void netvsc_build_mpb_array(struct hv_page_buffer *pb,
				u32 page_buffer_count,
				struct vmbus_packet_mpb_array *desc,
				u32 *desc_size)
{
	struct hv_mpb_array *mpb_entry = &desc->range;
	int i, j;

	for (i = 0; i < page_buffer_count; i++) {
		u32 offset = pb[i].offset;
		u32 len = pb[i].len;

		mpb_entry->offset = offset;
		mpb_entry->len = len;

		for (j = 0; j < HVPFN_UP(offset + len); j++)
			mpb_entry->pfn_array[j] = pb[i].pfn + j;

		mpb_entry = (struct hv_mpb_array *)&mpb_entry->pfn_array[j];
	}

	desc->rangecount = page_buffer_count;
	*desc_size = (char *)mpb_entry - (char *)desc;
}

static inline int netvsc_send_pkt(
	struct hv_device *device,
	struct hv_netvsc_packet *packet,
@@ -1097,6 +1133,9 @@ static inline int netvsc_send_pkt(

	packet->dma_range = NULL;
	if (packet->page_buf_cnt) {
		struct vmbus_channel_packet_page_buffer desc;
		u32 desc_size;

		if (packet->cp_partial)
			pb += packet->rmsg_pgcnt;

@@ -1106,11 +1145,12 @@ static inline int netvsc_send_pkt(
			goto exit;
		}

		ret = vmbus_sendpacket_pagebuffer(out_channel,
						  pb, packet->page_buf_cnt,
						  &nvmsg, sizeof(nvmsg),
						  req_id);

		netvsc_build_mpb_array(pb, packet->page_buf_cnt,
				(struct vmbus_packet_mpb_array *)&desc,
				 &desc_size);
		ret = vmbus_sendpacket_mpb_desc(out_channel,
				(struct vmbus_packet_mpb_array *)&desc,
				desc_size, &nvmsg, sizeof(nvmsg), req_id);
		if (ret)
			netvsc_dma_unmap(ndev_ctx->device_ctx, packet);
	} else {