Skip to content

Commit 6f572a8

Browse files
committed
drm/nouveau/gsp: Use the sg allocator for level 2 of radix3
Currently we allocate all 3 levels of radix3 page tables using nvkm_gsp_mem_ctor(), which uses dma_alloc_coherent() for allocating all of the relevant memory. This can end up failing in scenarios where the system has very high memory fragmentation, and we can't find enough contiguous memory to allocate level 2 of the page table. Currently, this can result in runtime PM issues on systems where memory fragmentation is high - as we'll fail to allocate the page table for our suspend/resume buffer: kworker/10:2: page allocation failure: order:7, mode:0xcc0(GFP_KERNEL), nodemask=(null),cpuset=/,mems_allowed=0 CPU: 10 PID: 479809 Comm: kworker/10:2 Not tainted 6.8.6-201.ChopperV6.fc39.x86_64 #1 Hardware name: SLIMBOOK Executive/Executive, BIOS N.1.10GRU06 02/02/2024 Workqueue: pm pm_runtime_work Call Trace: <TASK> dump_stack_lvl+0x64/0x80 warn_alloc+0x165/0x1e0 ? __alloc_pages_direct_compact+0xb3/0x2b0 __alloc_pages_slowpath.constprop.0+0xd7d/0xde0 __alloc_pages+0x32d/0x350 __dma_direct_alloc_pages.isra.0+0x16a/0x2b0 dma_direct_alloc+0x70/0x270 nvkm_gsp_radix3_sg+0x5e/0x130 [nouveau] r535_gsp_fini+0x1d4/0x350 [nouveau] nvkm_subdev_fini+0x67/0x150 [nouveau] nvkm_device_fini+0x95/0x1e0 [nouveau] nvkm_udevice_fini+0x53/0x70 [nouveau] nvkm_object_fini+0xb9/0x240 [nouveau] nvkm_object_fini+0x75/0x240 [nouveau] nouveau_do_suspend+0xf5/0x280 [nouveau] nouveau_pmops_runtime_suspend+0x3e/0xb0 [nouveau] pci_pm_runtime_suspend+0x67/0x1e0 ? __pfx_pci_pm_runtime_suspend+0x10/0x10 __rpm_callback+0x41/0x170 ? __pfx_pci_pm_runtime_suspend+0x10/0x10 rpm_callback+0x5d/0x70 ? __pfx_pci_pm_runtime_suspend+0x10/0x10 rpm_suspend+0x120/0x6a0 pm_runtime_work+0x98/0xb0 process_one_work+0x171/0x340 worker_thread+0x27b/0x3a0 ? __pfx_worker_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x31/0x50 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1b/0x30 Luckily, we don't actually need to allocate coherent memory for the page table thanks to being able to pass the GPU a radix3 page table for suspend/resume data. So, let's rewrite nvkm_gsp_radix3_sg() to use the sg allocator for level 2. We continue using coherent allocations for lvl0 and 1, since they only take a single page. V2: * Don't forget to actually jump to the next scatterlist when we reach the end of the scatterlist we're currently on when writing out the page table for level 2 Signed-off-by: Lyude Paul <lyude@redhat.com> Cc: stable@vger.kernel.org Reviewed-by: Ben Skeggs <bskeggs@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240429182318.189668-2-lyude@redhat.com
1 parent 52a6947 commit 6f572a8

File tree

2 files changed

+54
-27
lines changed
  • drivers/gpu/drm/nouveau

2 files changed

+54
-27
lines changed

drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ struct nvkm_gsp_mem {
1515
};
1616

1717
struct nvkm_gsp_radix3 {
18-
struct nvkm_gsp_mem mem[3];
18+
struct nvkm_gsp_mem lvl0;
19+
struct nvkm_gsp_mem lvl1;
20+
struct sg_table lvl2;
1921
};
2022

2123
int nvkm_gsp_sg(struct nvkm_device *, u64 size, struct sg_table *);

drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,7 +1624,7 @@ r535_gsp_wpr_meta_init(struct nvkm_gsp *gsp)
16241624
meta->magic = GSP_FW_WPR_META_MAGIC;
16251625
meta->revision = GSP_FW_WPR_META_REVISION;
16261626

1627-
meta->sysmemAddrOfRadix3Elf = gsp->radix3.mem[0].addr;
1627+
meta->sysmemAddrOfRadix3Elf = gsp->radix3.lvl0.addr;
16281628
meta->sizeOfRadix3Elf = gsp->fb.wpr2.elf.size;
16291629

16301630
meta->sysmemAddrOfBootloader = gsp->boot.fw.addr;
@@ -1919,8 +1919,9 @@ nvkm_gsp_sg(struct nvkm_device *device, u64 size, struct sg_table *sgt)
19191919
static void
19201920
nvkm_gsp_radix3_dtor(struct nvkm_gsp *gsp, struct nvkm_gsp_radix3 *rx3)
19211921
{
1922-
for (int i = ARRAY_SIZE(rx3->mem) - 1; i >= 0; i--)
1923-
nvkm_gsp_mem_dtor(gsp, &rx3->mem[i]);
1922+
nvkm_gsp_sg_free(gsp->subdev.device, &rx3->lvl2);
1923+
nvkm_gsp_mem_dtor(gsp, &rx3->lvl1);
1924+
nvkm_gsp_mem_dtor(gsp, &rx3->lvl0);
19241925
}
19251926

19261927
/**
@@ -1960,36 +1961,60 @@ static int
19601961
nvkm_gsp_radix3_sg(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size,
19611962
struct nvkm_gsp_radix3 *rx3)
19621963
{
1963-
u64 addr;
1964+
struct sg_dma_page_iter sg_dma_iter;
1965+
struct scatterlist *sg;
1966+
size_t bufsize;
1967+
u64 *pte;
1968+
int ret, i, page_idx = 0;
19641969

1965-
for (int i = ARRAY_SIZE(rx3->mem) - 1; i >= 0; i--) {
1966-
u64 *ptes;
1967-
size_t bufsize;
1968-
int ret, idx;
1970+
ret = nvkm_gsp_mem_ctor(gsp, GSP_PAGE_SIZE, &rx3->lvl0);
1971+
if (ret)
1972+
return ret;
19691973

1970-
bufsize = ALIGN((size / GSP_PAGE_SIZE) * sizeof(u64), GSP_PAGE_SIZE);
1971-
ret = nvkm_gsp_mem_ctor(gsp, bufsize, &rx3->mem[i]);
1972-
if (ret)
1973-
return ret;
1974+
ret = nvkm_gsp_mem_ctor(gsp, GSP_PAGE_SIZE, &rx3->lvl1);
1975+
if (ret)
1976+
goto lvl1_fail;
19741977

1975-
ptes = rx3->mem[i].data;
1976-
if (i == 2) {
1977-
struct scatterlist *sgl;
1978+
// Allocate level 2
1979+
bufsize = ALIGN((size / GSP_PAGE_SIZE) * sizeof(u64), GSP_PAGE_SIZE);
1980+
ret = nvkm_gsp_sg(gsp->subdev.device, bufsize, &rx3->lvl2);
1981+
if (ret)
1982+
goto lvl2_fail;
19781983

1979-
for_each_sgtable_dma_sg(sgt, sgl, idx) {
1980-
for (int j = 0; j < sg_dma_len(sgl) / GSP_PAGE_SIZE; j++)
1981-
*ptes++ = sg_dma_address(sgl) + (GSP_PAGE_SIZE * j);
1982-
}
1983-
} else {
1984-
for (int j = 0; j < size / GSP_PAGE_SIZE; j++)
1985-
*ptes++ = addr + GSP_PAGE_SIZE * j;
1984+
// Write the bus address of level 1 to level 0
1985+
pte = rx3->lvl0.data;
1986+
*pte = rx3->lvl1.addr;
1987+
1988+
// Write the bus address of each page in level 2 to level 1
1989+
pte = rx3->lvl1.data;
1990+
for_each_sgtable_dma_page(&rx3->lvl2, &sg_dma_iter, 0)
1991+
*pte++ = sg_page_iter_dma_address(&sg_dma_iter);
1992+
1993+
// Finally, write the bus address of each page in sgt to level 2
1994+
for_each_sgtable_sg(&rx3->lvl2, sg, i) {
1995+
void *sgl_end;
1996+
1997+
pte = sg_virt(sg);
1998+
sgl_end = (void *)pte + sg->length;
1999+
2000+
for_each_sgtable_dma_page(sgt, &sg_dma_iter, page_idx) {
2001+
*pte++ = sg_page_iter_dma_address(&sg_dma_iter);
2002+
page_idx++;
2003+
2004+
// Go to the next scatterlist for level 2 if we've reached the end
2005+
if ((void *)pte >= sgl_end)
2006+
break;
19862007
}
2008+
}
19872009

1988-
size = rx3->mem[i].size;
1989-
addr = rx3->mem[i].addr;
2010+
if (ret) {
2011+
lvl2_fail:
2012+
nvkm_gsp_mem_dtor(gsp, &rx3->lvl1);
2013+
lvl1_fail:
2014+
nvkm_gsp_mem_dtor(gsp, &rx3->lvl0);
19902015
}
19912016

1992-
return 0;
2017+
return ret;
19932018
}
19942019

19952020
int
@@ -2021,7 +2046,7 @@ r535_gsp_fini(struct nvkm_gsp *gsp, bool suspend)
20212046
sr = gsp->sr.meta.data;
20222047
sr->magic = GSP_FW_SR_META_MAGIC;
20232048
sr->revision = GSP_FW_SR_META_REVISION;
2024-
sr->sysmemAddrOfSuspendResumeData = gsp->sr.radix3.mem[0].addr;
2049+
sr->sysmemAddrOfSuspendResumeData = gsp->sr.radix3.lvl0.addr;
20252050
sr->sizeOfSuspendResumeData = len;
20262051

20272052
mbox0 = lower_32_bits(gsp->sr.meta.addr);

0 commit comments

Comments
 (0)