Commit ec8e2d38 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'vfio-v6.13-rc3' of https://github.com/awilliam/linux-vfio

Pull vfio fix from Alex Williamson:

 - Fix migration dirty page tracking support in the mlx5-vfio-pci
   variant driver in configurations where the system page size exceeds
   the device maximum message size, and anticipate device updates where
   the opposite may also be required (Yishai Hadas)

* tag 'vfio-v6.13-rc3' of https://github.com/awilliam/linux-vfio:
  vfio/mlx5: Align the page tracking max message size with the device capability
parents becb337c 9c7c5430
Loading
Loading
Loading
Loading
+35 −12
Original line number Diff line number Diff line
@@ -1517,7 +1517,8 @@ int mlx5vf_start_page_tracker(struct vfio_device *vdev,
	struct mlx5_vhca_qp *host_qp;
	struct mlx5_vhca_qp *fw_qp;
	struct mlx5_core_dev *mdev;
	u32 max_msg_size = PAGE_SIZE;
	u32 log_max_msg_size;
	u32 max_msg_size;
	u64 rq_size = SZ_2M;
	u32 max_recv_wr;
	int err;
@@ -1534,6 +1535,12 @@ int mlx5vf_start_page_tracker(struct vfio_device *vdev,
	}

	mdev = mvdev->mdev;
	log_max_msg_size = MLX5_CAP_ADV_VIRTUALIZATION(mdev, pg_track_log_max_msg_size);
	max_msg_size = (1ULL << log_max_msg_size);
	/* The RQ must hold at least 4 WQEs/messages for successful QP creation */
	if (rq_size < 4 * max_msg_size)
		rq_size = 4 * max_msg_size;

	memset(tracker, 0, sizeof(*tracker));
	tracker->uar = mlx5_get_uars_page(mdev);
	if (IS_ERR(tracker->uar)) {
@@ -1623,25 +1630,41 @@ set_report_output(u32 size, int index, struct mlx5_vhca_qp *qp,
{
	u32 entry_size = MLX5_ST_SZ_BYTES(page_track_report_entry);
	u32 nent = size / entry_size;
	u32 nent_in_page;
	u32 nent_to_set;
	struct page *page;
	u32 page_offset;
	u32 page_index;
	u32 buf_offset;
	void *kaddr;
	u64 addr;
	u64 *buf;
	int i;

	if (WARN_ON(index >= qp->recv_buf.npages ||
	buf_offset = index * qp->max_msg_size;
	if (WARN_ON(buf_offset + size >= qp->recv_buf.npages * PAGE_SIZE ||
		    (nent > qp->max_msg_size / entry_size)))
		return;

	page = qp->recv_buf.page_list[index];
	buf = kmap_local_page(page);
	for (i = 0; i < nent; i++) {
	do {
		page_index = buf_offset / PAGE_SIZE;
		page_offset = buf_offset % PAGE_SIZE;
		nent_in_page = (PAGE_SIZE - page_offset) / entry_size;
		page = qp->recv_buf.page_list[page_index];
		kaddr = kmap_local_page(page);
		buf = kaddr + page_offset;
		nent_to_set = min(nent, nent_in_page);
		for (i = 0; i < nent_to_set; i++) {
			addr = MLX5_GET(page_track_report_entry, buf + i,
					dirty_address_low);
			addr |= (u64)MLX5_GET(page_track_report_entry, buf + i,
					      dirty_address_high) << 32;
			iova_bitmap_set(dirty, addr, qp->tracked_page_size);
		}
	kunmap_local(buf);
		kunmap_local(kaddr);
		buf_offset += (nent_to_set * entry_size);
		nent -= nent_to_set;
	} while (nent);
}

static void