diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2012-07-19 18:17:34 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2012-10-02 23:12:56 -0400 |
commit | ebb945a94bba2ce8dff7b0942ff2b3f2a52a0a69 (patch) | |
tree | 07cad59be501458e6ae1304b7c0352e322ac3387 /drivers/gpu/drm/nouveau/nouveau_drm.c | |
parent | ac1499d9573f4aadd1d2beac11fe23af8ce90c24 (diff) |
drm/nouveau: port all engines to new engine module format
This is a HUGE commit, but it's not nearly as bad as it looks - any problems
can be isolated to a particular chipset and engine combination. It was
simply too difficult to port each one at a time, the compat layers are
*already* ridiculous.
Most of the changes here are simply to the glue, the process for each of the
engine modules was to start with a standard skeleton and copy+paste the old
code into the appropriate places, fixing up variable names etc as needed.
v2: Marcin Slusarz <marcin.slusarz@gmail.com>
- fix find/replace bug in license header
v3: Ben Skeggs <bskeggs@redhat.com>
- bump indirect pushbuf size to 8KiB, 4KiB barely enough for userspace and
left no space for kernel's requirements during GEM pushbuf submission.
- fix duplicate assignments noticed by clang
v4: Marcin Slusarz <marcin.slusarz@gmail.com>
- add sparse annotations to nv04_fifo_pause/nv04_fifo_start
- use ioread32_native/iowrite32_native for fifo control registers
v5: Ben Skeggs <bskeggs@redhat.com>
- rebase on v3.6-rc4, modified to keep copy engine fix intact
- nv10/fence: unmap fence bo before destroying
- fixed fermi regression when using nvidia gr fuc
- fixed typo in supported dma_mask checking
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 211 |
1 files changed, 204 insertions, 7 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 3b4e65d5122b..92ecf50a39d3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -27,12 +27,20 @@ | |||
27 | 27 | ||
28 | #include <core/device.h> | 28 | #include <core/device.h> |
29 | #include <core/client.h> | 29 | #include <core/client.h> |
30 | #include <core/gpuobj.h> | ||
30 | #include <core/class.h> | 31 | #include <core/class.h> |
31 | 32 | ||
32 | #include <subdev/device.h> | 33 | #include <subdev/device.h> |
34 | #include <subdev/vm.h> | ||
33 | 35 | ||
34 | #include "nouveau_drm.h" | 36 | #include "nouveau_drm.h" |
37 | #include "nouveau_dma.h" | ||
35 | #include "nouveau_agp.h" | 38 | #include "nouveau_agp.h" |
39 | #include "nouveau_abi16.h" | ||
40 | #include "nouveau_fbcon.h" | ||
41 | #include "nouveau_fence.h" | ||
42 | |||
43 | #include "nouveau_ttm.h" | ||
36 | 44 | ||
37 | int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *); | 45 | int __devinit nouveau_pci_probe(struct pci_dev *, const struct pci_device_id *); |
38 | void nouveau_pci_remove(struct pci_dev *); | 46 | void nouveau_pci_remove(struct pci_dev *); |
@@ -43,7 +51,6 @@ void __exit nouveau_exit(struct pci_driver *); | |||
43 | 51 | ||
44 | int nouveau_load(struct drm_device *, unsigned long); | 52 | int nouveau_load(struct drm_device *, unsigned long); |
45 | int nouveau_unload(struct drm_device *); | 53 | int nouveau_unload(struct drm_device *); |
46 | void *nouveau_newpriv(struct drm_device *); | ||
47 | 54 | ||
48 | MODULE_PARM_DESC(config, "option string to pass to driver core"); | 55 | MODULE_PARM_DESC(config, "option string to pass to driver core"); |
49 | static char *nouveau_config; | 56 | static char *nouveau_config; |
@@ -53,6 +60,10 @@ MODULE_PARM_DESC(debug, "debug string to pass to driver core"); | |||
53 | static char *nouveau_debug; | 60 | static char *nouveau_debug; |
54 | module_param_named(debug, nouveau_debug, charp, 0400); | 61 | module_param_named(debug, nouveau_debug, charp, 0400); |
55 | 62 | ||
63 | MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration"); | ||
64 | static int nouveau_noaccel = 0; | ||
65 | module_param_named(noaccel, nouveau_noaccel, int, 0400); | ||
66 | |||
56 | static u64 | 67 | static u64 |
57 | nouveau_name(struct pci_dev *pdev) | 68 | nouveau_name(struct pci_dev *pdev) |
58 | { | 69 | { |
@@ -82,17 +93,112 @@ static void | |||
82 | nouveau_cli_destroy(struct nouveau_cli *cli) | 93 | nouveau_cli_destroy(struct nouveau_cli *cli) |
83 | { | 94 | { |
84 | struct nouveau_object *client = nv_object(cli); | 95 | struct nouveau_object *client = nv_object(cli); |
96 | nouveau_vm_ref(NULL, &cli->base.vm, NULL); | ||
85 | nouveau_client_fini(&cli->base, false); | 97 | nouveau_client_fini(&cli->base, false); |
86 | atomic_set(&client->refcount, 1); | 98 | atomic_set(&client->refcount, 1); |
87 | nouveau_object_ref(NULL, &client); | 99 | nouveau_object_ref(NULL, &client); |
88 | } | 100 | } |
89 | 101 | ||
102 | static void | ||
103 | nouveau_accel_fini(struct nouveau_drm *drm) | ||
104 | { | ||
105 | nouveau_gpuobj_ref(NULL, &drm->notify); | ||
106 | nouveau_channel_del(&drm->channel); | ||
107 | if (drm->fence) | ||
108 | nouveau_fence(drm)->dtor(drm); | ||
109 | } | ||
110 | |||
111 | static void | ||
112 | nouveau_accel_init(struct nouveau_drm *drm) | ||
113 | { | ||
114 | struct nouveau_device *device = nv_device(drm->device); | ||
115 | struct nouveau_object *object; | ||
116 | int ret; | ||
117 | |||
118 | if (nouveau_noaccel) | ||
119 | return; | ||
120 | |||
121 | /* initialise synchronisation routines */ | ||
122 | if (device->card_type < NV_10) ret = nv04_fence_create(drm); | ||
123 | else if (device->chipset < 0x84) ret = nv10_fence_create(drm); | ||
124 | else if (device->card_type < NV_C0) ret = nv84_fence_create(drm); | ||
125 | else ret = nvc0_fence_create(drm); | ||
126 | if (ret) { | ||
127 | NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret); | ||
128 | nouveau_accel_fini(drm); | ||
129 | return; | ||
130 | } | ||
131 | |||
132 | ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, NVDRM_CHAN, | ||
133 | NvDmaFB, NvDmaTT, &drm->channel); | ||
134 | if (ret) { | ||
135 | NV_ERROR(drm, "failed to create kernel channel, %d\n", ret); | ||
136 | nouveau_accel_fini(drm); | ||
137 | return; | ||
138 | } | ||
139 | |||
140 | if (device->card_type < NV_C0) { | ||
141 | ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0, | ||
142 | &drm->notify); | ||
143 | if (ret) { | ||
144 | NV_ERROR(drm, "failed to allocate notifier, %d\n", ret); | ||
145 | nouveau_accel_fini(drm); | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | ret = nouveau_object_new(nv_object(drm), | ||
150 | drm->channel->handle, NvNotify0, | ||
151 | 0x003d, &(struct nv_dma_class) { | ||
152 | .flags = NV_DMA_TARGET_VRAM | | ||
153 | NV_DMA_ACCESS_RDWR, | ||
154 | .start = drm->notify->addr, | ||
155 | .limit = drm->notify->addr + 31 | ||
156 | }, sizeof(struct nv_dma_class), | ||
157 | &object); | ||
158 | if (ret) { | ||
159 | nouveau_accel_fini(drm); | ||
160 | return; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | |||
165 | nouveau_bo_move_init(drm->channel); | ||
166 | } | ||
167 | |||
90 | static int __devinit | 168 | static int __devinit |
91 | nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent) | 169 | nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent) |
92 | { | 170 | { |
93 | struct nouveau_device *device; | 171 | struct nouveau_device *device; |
172 | struct apertures_struct *aper; | ||
173 | bool boot = false; | ||
94 | int ret; | 174 | int ret; |
95 | 175 | ||
176 | /* remove conflicting drivers (vesafb, efifb etc) */ | ||
177 | aper = alloc_apertures(3); | ||
178 | if (!aper) | ||
179 | return -ENOMEM; | ||
180 | |||
181 | aper->ranges[0].base = pci_resource_start(pdev, 1); | ||
182 | aper->ranges[0].size = pci_resource_len(pdev, 1); | ||
183 | aper->count = 1; | ||
184 | |||
185 | if (pci_resource_len(pdev, 2)) { | ||
186 | aper->ranges[aper->count].base = pci_resource_start(pdev, 2); | ||
187 | aper->ranges[aper->count].size = pci_resource_len(pdev, 2); | ||
188 | aper->count++; | ||
189 | } | ||
190 | |||
191 | if (pci_resource_len(pdev, 3)) { | ||
192 | aper->ranges[aper->count].base = pci_resource_start(pdev, 3); | ||
193 | aper->ranges[aper->count].size = pci_resource_len(pdev, 3); | ||
194 | aper->count++; | ||
195 | } | ||
196 | |||
197 | #ifdef CONFIG_X86 | ||
198 | boot = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; | ||
199 | #endif | ||
200 | remove_conflicting_framebuffers(aper, "nouveaufb", boot); | ||
201 | |||
96 | ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev), | 202 | ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev), |
97 | nouveau_config, nouveau_debug, &device); | 203 | nouveau_config, nouveau_debug, &device); |
98 | if (ret) | 204 | if (ret) |
@@ -102,7 +208,7 @@ nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent) | |||
102 | 208 | ||
103 | ret = nouveau_pci_probe(pdev, pent); | 209 | ret = nouveau_pci_probe(pdev, pent); |
104 | if (ret) { | 210 | if (ret) { |
105 | nouveau_device_destroy(&device); | 211 | nouveau_object_ref(NULL, (struct nouveau_object **)&device); |
106 | return ret; | 212 | return ret; |
107 | } | 213 | } |
108 | 214 | ||
@@ -113,6 +219,7 @@ int | |||
113 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) | 219 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) |
114 | { | 220 | { |
115 | struct pci_dev *pdev = dev->pdev; | 221 | struct pci_dev *pdev = dev->pdev; |
222 | struct nouveau_device *device; | ||
116 | struct nouveau_drm *drm; | 223 | struct nouveau_drm *drm; |
117 | int ret; | 224 | int ret; |
118 | 225 | ||
@@ -122,6 +229,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
122 | return ret; | 229 | return ret; |
123 | 230 | ||
124 | INIT_LIST_HEAD(&drm->clients); | 231 | INIT_LIST_HEAD(&drm->clients); |
232 | spin_lock_init(&drm->tile.lock); | ||
125 | drm->dev = dev; | 233 | drm->dev = dev; |
126 | 234 | ||
127 | /* make sure AGP controller is in a consistent state before we | 235 | /* make sure AGP controller is in a consistent state before we |
@@ -142,7 +250,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
142 | }, sizeof(struct nv_device_class), | 250 | }, sizeof(struct nv_device_class), |
143 | &drm->device); | 251 | &drm->device); |
144 | if (ret) | 252 | if (ret) |
145 | return ret; | 253 | goto fail_device; |
146 | 254 | ||
147 | nouveau_agp_reset(drm); | 255 | nouveau_agp_reset(drm); |
148 | nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE); | 256 | nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE); |
@@ -158,15 +266,32 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
158 | if (ret) | 266 | if (ret) |
159 | goto fail_device; | 267 | goto fail_device; |
160 | 268 | ||
269 | device = nv_device(drm->device); | ||
270 | |||
161 | /* initialise AGP */ | 271 | /* initialise AGP */ |
162 | nouveau_agp_init(drm); | 272 | nouveau_agp_init(drm); |
163 | 273 | ||
164 | ret = nouveau_load(dev, flags); | 274 | if (device->card_type >= NV_50) { |
275 | ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40), | ||
276 | 0x1000, &drm->client.base.vm); | ||
277 | if (ret) | ||
278 | goto fail_device; | ||
279 | } | ||
280 | |||
281 | ret = nouveau_ttm_init(drm); | ||
165 | if (ret) | 282 | if (ret) |
166 | goto fail_device; | 283 | goto fail_device; |
167 | 284 | ||
285 | ret = nouveau_load(dev, flags); | ||
286 | if (ret) | ||
287 | goto fail_load; | ||
288 | |||
289 | nouveau_accel_init(drm); | ||
290 | nouveau_fbcon_init(dev); | ||
168 | return 0; | 291 | return 0; |
169 | 292 | ||
293 | fail_load: | ||
294 | nouveau_ttm_fini(drm); | ||
170 | fail_device: | 295 | fail_device: |
171 | nouveau_cli_destroy(&drm->client); | 296 | nouveau_cli_destroy(&drm->client); |
172 | return ret; | 297 | return ret; |
@@ -179,10 +304,14 @@ nouveau_drm_unload(struct drm_device *dev) | |||
179 | struct pci_dev *pdev = dev->pdev; | 304 | struct pci_dev *pdev = dev->pdev; |
180 | int ret; | 305 | int ret; |
181 | 306 | ||
307 | nouveau_fbcon_fini(dev); | ||
308 | nouveau_accel_fini(drm); | ||
309 | |||
182 | ret = nouveau_unload(dev); | 310 | ret = nouveau_unload(dev); |
183 | if (ret) | 311 | if (ret) |
184 | return ret; | 312 | return ret; |
185 | 313 | ||
314 | nouveau_ttm_fini(drm); | ||
186 | nouveau_agp_fini(drm); | 315 | nouveau_agp_fini(drm); |
187 | 316 | ||
188 | pci_set_drvdata(pdev, drm->client.base.device); | 317 | pci_set_drvdata(pdev, drm->client.base.device); |
@@ -193,10 +322,11 @@ nouveau_drm_unload(struct drm_device *dev) | |||
193 | static void | 322 | static void |
194 | nouveau_drm_remove(struct pci_dev *pdev) | 323 | nouveau_drm_remove(struct pci_dev *pdev) |
195 | { | 324 | { |
196 | struct nouveau_device *device; | 325 | struct nouveau_object *device; |
197 | nouveau_pci_remove(pdev); | 326 | nouveau_pci_remove(pdev); |
198 | device = pci_get_drvdata(pdev); | 327 | device = pci_get_drvdata(pdev); |
199 | nouveau_device_destroy(&device); | 328 | nouveau_object_ref(NULL, &device); |
329 | nouveau_object_debug(); | ||
200 | } | 330 | } |
201 | 331 | ||
202 | int | 332 | int |
@@ -211,10 +341,23 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state) | |||
211 | pm_state.event == PM_EVENT_PRETHAW) | 341 | pm_state.event == PM_EVENT_PRETHAW) |
212 | return 0; | 342 | return 0; |
213 | 343 | ||
344 | NV_INFO(drm, "suspending fbcon...\n"); | ||
345 | nouveau_fbcon_set_suspend(dev, 1); | ||
346 | |||
347 | NV_INFO(drm, "suspending drm...\n"); | ||
214 | ret = nouveau_pci_suspend(pdev, pm_state); | 348 | ret = nouveau_pci_suspend(pdev, pm_state); |
215 | if (ret) | 349 | if (ret) |
216 | return ret; | 350 | return ret; |
217 | 351 | ||
352 | NV_INFO(drm, "evicting buffers...\n"); | ||
353 | ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); | ||
354 | |||
355 | if (drm->fence && nouveau_fence(drm)->suspend) { | ||
356 | if (!nouveau_fence(drm)->suspend(drm)) | ||
357 | return -ENOMEM; | ||
358 | } | ||
359 | |||
360 | NV_INFO(drm, "suspending client object trees...\n"); | ||
218 | list_for_each_entry(cli, &drm->clients, head) { | 361 | list_for_each_entry(cli, &drm->clients, head) { |
219 | ret = nouveau_client_fini(&cli->base, true); | 362 | ret = nouveau_client_fini(&cli->base, true); |
220 | if (ret) | 363 | if (ret) |
@@ -255,6 +398,7 @@ nouveau_drm_resume(struct pci_dev *pdev) | |||
255 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) | 398 | if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) |
256 | return 0; | 399 | return 0; |
257 | 400 | ||
401 | NV_INFO(drm, "re-enabling device...\n"); | ||
258 | pci_set_power_state(pdev, PCI_D0); | 402 | pci_set_power_state(pdev, PCI_D0); |
259 | pci_restore_state(pdev); | 403 | pci_restore_state(pdev); |
260 | ret = pci_enable_device(pdev); | 404 | ret = pci_enable_device(pdev); |
@@ -264,17 +408,70 @@ nouveau_drm_resume(struct pci_dev *pdev) | |||
264 | 408 | ||
265 | nouveau_agp_reset(drm); | 409 | nouveau_agp_reset(drm); |
266 | 410 | ||
411 | NV_INFO(drm, "resuming client object trees...\n"); | ||
267 | nouveau_client_init(&drm->client.base); | 412 | nouveau_client_init(&drm->client.base); |
413 | nouveau_agp_init(drm); | ||
268 | 414 | ||
269 | list_for_each_entry(cli, &drm->clients, head) { | 415 | list_for_each_entry(cli, &drm->clients, head) { |
270 | nouveau_client_init(&cli->base); | 416 | nouveau_client_init(&cli->base); |
271 | } | 417 | } |
272 | 418 | ||
273 | nouveau_agp_init(drm); | 419 | if (drm->fence && nouveau_fence(drm)->resume) |
420 | nouveau_fence(drm)->resume(drm); | ||
274 | 421 | ||
275 | return nouveau_pci_resume(pdev); | 422 | return nouveau_pci_resume(pdev); |
276 | } | 423 | } |
277 | 424 | ||
425 | int | ||
426 | nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) | ||
427 | { | ||
428 | struct pci_dev *pdev = dev->pdev; | ||
429 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
430 | struct nouveau_cli *cli; | ||
431 | int ret; | ||
432 | |||
433 | ret = nouveau_cli_create(pdev, fpriv->pid, sizeof(*cli), (void **)&cli); | ||
434 | if (ret) | ||
435 | return ret; | ||
436 | |||
437 | if (nv_device(drm->device)->card_type >= NV_50) { | ||
438 | ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40), | ||
439 | 0x1000, &cli->base.vm); | ||
440 | if (ret) { | ||
441 | nouveau_cli_destroy(cli); | ||
442 | return ret; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | fpriv->driver_priv = cli; | ||
447 | |||
448 | mutex_lock(&drm->client.mutex); | ||
449 | list_add(&cli->head, &drm->clients); | ||
450 | mutex_unlock(&drm->client.mutex); | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | void | ||
455 | nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv) | ||
456 | { | ||
457 | struct nouveau_cli *cli = nouveau_cli(fpriv); | ||
458 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
459 | |||
460 | if (cli->abi16) | ||
461 | nouveau_abi16_fini(cli->abi16); | ||
462 | |||
463 | mutex_lock(&drm->client.mutex); | ||
464 | list_del(&cli->head); | ||
465 | mutex_unlock(&drm->client.mutex); | ||
466 | } | ||
467 | |||
468 | void | ||
469 | nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv) | ||
470 | { | ||
471 | struct nouveau_cli *cli = nouveau_cli(fpriv); | ||
472 | nouveau_cli_destroy(cli); | ||
473 | } | ||
474 | |||
278 | static struct pci_device_id | 475 | static struct pci_device_id |
279 | nouveau_drm_pci_table[] = { | 476 | nouveau_drm_pci_table[] = { |
280 | { | 477 | { |