Skip to content

Commit be55287

Browse files
author
Ben Skeggs
committed
drm/nouveau/imem/nv50: embed nvkm_instobj directly into nv04_instobj
This is not as simple as it was for earlier GPUs, due to the need to swap accessor functions depending on whether BAR2 is usable or not. We were previously protected by nvkm_instobj's accessor functions keeping an object mapped permanently, with some unclear magic that managed to hit the slow-path where needed even if an object was marked as mapped. That's been replaced here by reference counting maps (some objects, like page tables can be accessed concurrently), and swapping the functions as necessary. Signed-off-by: Ben Skeggs <[email protected]>
1 parent af515ec commit be55287

File tree

1 file changed

+102
-32
lines changed
  • drivers/gpu/drm/nouveau/nvkm/subdev/instmem

1 file changed

+102
-32
lines changed

drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c

+102-32
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@ struct nv50_instmem {
3737
/******************************************************************************
3838
* instmem object implementation
3939
*****************************************************************************/
40-
#define nv50_instobj(p) container_of((p), struct nv50_instobj, memory)
40+
#define nv50_instobj(p) container_of((p), struct nv50_instobj, base.memory)
4141

4242
struct nv50_instobj {
43-
struct nvkm_memory memory;
43+
struct nvkm_instobj base;
4444
struct nv50_instmem *imem;
4545
struct nvkm_mem *mem;
4646
struct nvkm_vma bar;
47+
refcount_t maps;
4748
void *map;
4849
};
4950

@@ -93,31 +94,59 @@ nv50_instobj_slow = {
9394
.wr32 = nv50_instobj_wr32_slow,
9495
};
9596

97+
static void
98+
nv50_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data)
99+
{
100+
iowrite32_native(data, nv50_instobj(memory)->map + offset);
101+
}
102+
103+
static u32
104+
nv50_instobj_rd32(struct nvkm_memory *memory, u64 offset)
105+
{
106+
return ioread32_native(nv50_instobj(memory)->map + offset);
107+
}
108+
109+
static const struct nvkm_memory_ptrs
110+
nv50_instobj_fast = {
111+
.rd32 = nv50_instobj_rd32,
112+
.wr32 = nv50_instobj_wr32,
113+
};
114+
96115
static void
97116
nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm)
98117
{
99-
struct nvkm_memory *memory = &iobj->memory;
100-
struct nvkm_subdev *subdev = &iobj->imem->base.subdev;
118+
struct nv50_instmem *imem = iobj->imem;
119+
struct nvkm_memory *memory = &iobj->base.memory;
120+
struct nvkm_subdev *subdev = &imem->base.subdev;
101121
struct nvkm_device *device = subdev->device;
122+
struct nvkm_vma bar = {};
102123
u64 size = nvkm_memory_size(memory);
103-
void __iomem *map;
104124
int ret;
105125

106-
iobj->map = ERR_PTR(-ENOMEM);
107-
108-
ret = nvkm_vm_get(vmm, size, 12, NV_MEM_ACCESS_RW, &iobj->bar);
109-
if (ret == 0) {
110-
map = ioremap(device->func->resource_addr(device, 3) +
111-
(u32)iobj->bar.offset, size);
112-
if (map) {
113-
nvkm_memory_map(memory, &iobj->bar, 0);
114-
iobj->map = map;
115-
} else {
116-
nvkm_warn(subdev, "PRAMIN ioremap failed\n");
117-
nvkm_vm_put(&iobj->bar);
118-
}
119-
} else {
120-
nvkm_warn(subdev, "PRAMIN exhausted\n");
126+
/* Attempt to allocate BAR2 address-space and map the object
127+
* into it. The lock has to be dropped while doing this due
128+
* to the possibility of recursion for page table allocation.
129+
*/
130+
mutex_unlock(&subdev->mutex);
131+
ret = nvkm_vm_get(vmm, size, 12, NV_MEM_ACCESS_RW, &bar);
132+
if (ret == 0)
133+
nvkm_memory_map(memory, &bar, 0);
134+
mutex_lock(&subdev->mutex);
135+
if (ret || iobj->bar.node) {
136+
/* We either failed, or another thread beat us. */
137+
mutex_unlock(&subdev->mutex);
138+
nvkm_vm_put(&bar);
139+
mutex_lock(&subdev->mutex);
140+
return;
141+
}
142+
143+
/* Make the mapping visible to the host. */
144+
iobj->bar = bar;
145+
iobj->map = ioremap(device->func->resource_addr(device, 3) +
146+
(u32)iobj->bar.offset, size);
147+
if (!iobj->map) {
148+
nvkm_warn(subdev, "PRAMIN ioremap failed\n");
149+
nvkm_vm_put(&iobj->bar);
121150
}
122151
}
123152

@@ -131,28 +160,66 @@ nv50_instobj_map(struct nvkm_memory *memory, struct nvkm_vma *vma, u64 offset)
131160
static void
132161
nv50_instobj_release(struct nvkm_memory *memory)
133162
{
163+
struct nv50_instobj *iobj = nv50_instobj(memory);
164+
struct nv50_instmem *imem = iobj->imem;
165+
struct nvkm_subdev *subdev = &imem->base.subdev;
166+
167+
nvkm_bar_flush(subdev->device->bar);
168+
169+
if (refcount_dec_and_mutex_lock(&iobj->maps, &subdev->mutex)) {
170+
/* Switch back to NULL accessors when last map is gone. */
171+
iobj->base.memory.ptrs = &nv50_instobj_slow;
172+
mutex_unlock(&subdev->mutex);
173+
}
134174
}
135175

136176
static void __iomem *
137177
nv50_instobj_acquire(struct nvkm_memory *memory)
138178
{
139179
struct nv50_instobj *iobj = nv50_instobj(memory);
140-
struct nv50_instmem *imem = iobj->imem;
141-
struct nvkm_vm *vm;
180+
struct nvkm_instmem *imem = &iobj->imem->base;
181+
struct nvkm_vmm *vmm;
182+
void __iomem *map = NULL;
142183

143-
if (!iobj->map && (vm = nvkm_bar_bar2_vmm(imem->base.subdev.device)))
144-
nv50_instobj_kmap(iobj, vm);
145-
if (!IS_ERR_OR_NULL(iobj->map))
184+
/* Already mapped? */
185+
if (refcount_inc_not_zero(&iobj->maps))
146186
return iobj->map;
147187

148-
return NULL;
188+
/* Take the lock, and re-check that another thread hasn't
189+
* already mapped the object in the meantime.
190+
*/
191+
mutex_lock(&imem->subdev.mutex);
192+
if (refcount_inc_not_zero(&iobj->maps)) {
193+
mutex_unlock(&imem->subdev.mutex);
194+
return iobj->map;
195+
}
196+
197+
/* Attempt to get a direct CPU mapping of the object. */
198+
if (!iobj->map && (vmm = nvkm_bar_bar2_vmm(imem->subdev.device)))
199+
nv50_instobj_kmap(iobj, vmm);
200+
map = iobj->map;
201+
202+
if (!refcount_inc_not_zero(&iobj->maps)) {
203+
if (map)
204+
iobj->base.memory.ptrs = &nv50_instobj_fast;
205+
else
206+
iobj->base.memory.ptrs = &nv50_instobj_slow;
207+
refcount_inc(&iobj->maps);
208+
}
209+
210+
mutex_unlock(&imem->subdev.mutex);
211+
return map;
149212
}
150213

151214
static void
152215
nv50_instobj_boot(struct nvkm_memory *memory, struct nvkm_vmm *vmm)
153216
{
154217
struct nv50_instobj *iobj = nv50_instobj(memory);
218+
struct nvkm_instmem *imem = &iobj->imem->base;
219+
220+
mutex_lock(&imem->subdev.mutex);
155221
nv50_instobj_kmap(iobj, vmm);
222+
mutex_unlock(&imem->subdev.mutex);
156223
}
157224

158225
static u64
@@ -177,12 +244,14 @@ static void *
177244
nv50_instobj_dtor(struct nvkm_memory *memory)
178245
{
179246
struct nv50_instobj *iobj = nv50_instobj(memory);
180-
struct nvkm_ram *ram = iobj->imem->base.subdev.device->fb->ram;
181-
if (!IS_ERR_OR_NULL(iobj->map)) {
247+
struct nvkm_instmem *imem = &iobj->imem->base;
248+
struct nvkm_ram *ram = imem->subdev.device->fb->ram;
249+
if (iobj->map) {
182250
iounmap(iobj->map);
183251
nvkm_vm_put(&iobj->bar);
184252
}
185253
ram->func->put(ram, &iobj->mem);
254+
nvkm_instobj_dtor(imem, &iobj->base);
186255
return iobj;
187256
}
188257

@@ -209,11 +278,12 @@ nv50_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero,
209278

210279
if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL)))
211280
return -ENOMEM;
212-
*pmemory = &iobj->memory;
281+
*pmemory = &iobj->base.memory;
213282

214-
nvkm_memory_ctor(&nv50_instobj_func, &iobj->memory);
215-
iobj->memory.ptrs = &nv50_instobj_slow;
283+
nvkm_instobj_ctor(&nv50_instobj_func, &imem->base, &iobj->base);
284+
iobj->base.memory.ptrs = &nv50_instobj_slow;
216285
iobj->imem = imem;
286+
refcount_set(&iobj->maps, 0);
217287

218288
size = max((size + 4095) & ~4095, (u32)4096);
219289
align = max((align + 4095) & ~4095, (u32)4096);
@@ -240,7 +310,7 @@ static const struct nvkm_instmem_func
240310
nv50_instmem = {
241311
.fini = nv50_instmem_fini,
242312
.memory_new = nv50_instobj_new,
243-
.persistent = false,
313+
.persistent = true,
244314
.zero = false,
245315
};
246316

0 commit comments

Comments
 (0)