RE: [PATCH v3] video: hyperv: hyperv_fb: Use physical memory for fb on HyperV Gen 1 VMs.
From: Michael Kelley <hidden>
Date: 2019-12-07 16:28:37
Also in:
dri-devel, linux-fbdev, lkml
From: Wei Hu <redacted> Sent: Friday, December 6, 2019 3:32 AM
On Hyper-V, Generation 1 VMs can directly use VM's physical memory for
their framebuffers. This can improve the efficiency of framebuffer and
overall performence for VM. The physical memory assigned to framebuffer
must be contiguous. We use CMA allocator to get contiguouse physicial
memory when the framebuffer size is greater than 4MB. For size under
4MB, we use alloc_pages to achieve this.
To enable framebuffer memory allocation from CMA, supply a kernel
parameter to give enough space to CMA allocator at boot time. For
example:
cma=130m
This gives 130MB memory to CAM allocator that can be allocated to
framebuffer. If this fails, we fall back to the old way of using
mmio for framebuffer.
Reported-by: kbuild test robot <redacted>
Signed-off-by: Wei Hu <redacted>
---[snip]
+/*
+ * Allocate enough contiguous physical memory.
+ * Return physical address if succeeded or -1 if failed.
+ */
+static phys_addr_t hvfb_get_phymem(struct hv_device *hdev,
+ unsigned int request_size)
+{
+ struct page *page = NULL;
+ dma_addr_t dma_handle;
+ void *vmem;
+ unsigned int request_pages;
+ phys_addr_t paddr = 0;
+ unsigned int order = get_order(request_size);
+
+ if (request_size == 0)
+ return -1;
+
+ if (order < MAX_ORDER) {
+ /* Call alloc_pages if the size is less than 2^MAX_ORDER */
+ page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+ if (!page)
+ return -1;
+
+ paddr = (page_to_pfn(page) << PAGE_SHIFT);
+ request_pages = (1 << order);The above line is no longer needed. request_pages was previously an argument to a pr_info() statement, but that statement has appropriately been removed.
+ } else {
+ /* Allocate from CMA */
+ hdev->device.coherent_dma_mask = DMA_BIT_MASK(64);
+
+ request_pages = (round_up(request_size, PAGE_SIZE) >>
+ PAGE_SHIFT);
+
+ vmem = dma_alloc_coherent(&hdev->device,
+ request_pages * PAGE_SIZE,
+ &dma_handle,
+ GFP_KERNEL | __GFP_NOWARN);With the request_pages value no longer being needed, there's wasted motion in doing a PAGE_SHIFT shift to calculate request_pages, and then multiplying by PAGE_SIZE. The second argument above could just be round_up(request_size, PAGE_SIZE). Then it would be exactly parallel to the second argument to dma_free_coherent() below in hvfb_release_phymem(). The request_pages variable can be eliminated entirely.
+
+ if (!vmem)
+ return -1;
+
+ paddr = virt_to_phys(vmem);
+ }
+
+ return paddr;
+}
+
+/* Release contiguous physical memory */
+static void hvfb_release_phymem(struct hv_device *hdev,
+ phys_addr_t paddr, unsigned int size)
+{
+ unsigned int order = get_order(size);
+
+ if (order < MAX_ORDER)
+ __free_pages(pfn_to_page(paddr >> PAGE_SHIFT), order);
+ else
+ dma_free_coherent(&hdev->device,
+ round_up(size, PAGE_SIZE),
+ phys_to_virt(paddr),
+ paddr);
+}
+Everything else looks good. The most recent changes to hvfb_getmem() worked out very nicely. Michael