@@ -37,13 +37,14 @@ struct nv50_instmem {
37
37
/******************************************************************************
38
38
* instmem object implementation
39
39
*****************************************************************************/
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)
41
41
42
42
struct nv50_instobj {
43
- struct nvkm_memory memory ;
43
+ struct nvkm_instobj base ;
44
44
struct nv50_instmem * imem ;
45
45
struct nvkm_mem * mem ;
46
46
struct nvkm_vma bar ;
47
+ refcount_t maps ;
47
48
void * map ;
48
49
};
49
50
@@ -93,31 +94,59 @@ nv50_instobj_slow = {
93
94
.wr32 = nv50_instobj_wr32_slow ,
94
95
};
95
96
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
+
96
115
static void
97
116
nv50_instobj_kmap (struct nv50_instobj * iobj , struct nvkm_vmm * vmm )
98
117
{
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 ;
101
121
struct nvkm_device * device = subdev -> device ;
122
+ struct nvkm_vma bar = {};
102
123
u64 size = nvkm_memory_size (memory );
103
- void __iomem * map ;
104
124
int ret ;
105
125
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 );
121
150
}
122
151
}
123
152
@@ -131,28 +160,66 @@ nv50_instobj_map(struct nvkm_memory *memory, struct nvkm_vma *vma, u64 offset)
131
160
static void
132
161
nv50_instobj_release (struct nvkm_memory * memory )
133
162
{
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
+ }
134
174
}
135
175
136
176
static void __iomem *
137
177
nv50_instobj_acquire (struct nvkm_memory * memory )
138
178
{
139
179
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 ;
142
183
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 ))
146
186
return iobj -> map ;
147
187
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 ;
149
212
}
150
213
151
214
static void
152
215
nv50_instobj_boot (struct nvkm_memory * memory , struct nvkm_vmm * vmm )
153
216
{
154
217
struct nv50_instobj * iobj = nv50_instobj (memory );
218
+ struct nvkm_instmem * imem = & iobj -> imem -> base ;
219
+
220
+ mutex_lock (& imem -> subdev .mutex );
155
221
nv50_instobj_kmap (iobj , vmm );
222
+ mutex_unlock (& imem -> subdev .mutex );
156
223
}
157
224
158
225
static u64
@@ -177,12 +244,14 @@ static void *
177
244
nv50_instobj_dtor (struct nvkm_memory * memory )
178
245
{
179
246
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 ) {
182
250
iounmap (iobj -> map );
183
251
nvkm_vm_put (& iobj -> bar );
184
252
}
185
253
ram -> func -> put (ram , & iobj -> mem );
254
+ nvkm_instobj_dtor (imem , & iobj -> base );
186
255
return iobj ;
187
256
}
188
257
@@ -209,11 +278,12 @@ nv50_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero,
209
278
210
279
if (!(iobj = kzalloc (sizeof (* iobj ), GFP_KERNEL )))
211
280
return - ENOMEM ;
212
- * pmemory = & iobj -> memory ;
281
+ * pmemory = & iobj -> base . memory ;
213
282
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 ;
216
285
iobj -> imem = imem ;
286
+ refcount_set (& iobj -> maps , 0 );
217
287
218
288
size = max ((size + 4095 ) & ~4095 , (u32 )4096 );
219
289
align = max ((align + 4095 ) & ~4095 , (u32 )4096 );
@@ -240,7 +310,7 @@ static const struct nvkm_instmem_func
240
310
nv50_instmem = {
241
311
.fini = nv50_instmem_fini ,
242
312
.memory_new = nv50_instobj_new ,
243
- .persistent = false ,
313
+ .persistent = true ,
244
314
.zero = false,
245
315
};
246
316
0 commit comments