diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 112 |
1 files changed, 84 insertions, 28 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 7c758b2f8d0e..051e7104106d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -150,29 +150,58 @@ nouveau_accel_fini(struct nouveau_drm *drm) static void nouveau_accel_init(struct nouveau_drm *drm) { - struct nouveau_device *device = nv_device(drm->device); + struct nvif_device *device = &drm->device; struct nouveau_object *object; u32 arg0, arg1; - int ret; + u32 sclass[16]; + int ret, i; - if (nouveau_noaccel || !nouveau_fifo(device) /*XXX*/) + if (nouveau_noaccel) return; /* initialise synchronisation routines */ - if (device->card_type < NV_10) ret = nv04_fence_create(drm); - else if (device->card_type < NV_11 || - device->chipset < 0x17) ret = nv10_fence_create(drm); - else if (device->card_type < NV_50) ret = nv17_fence_create(drm); - else if (device->chipset < 0x84) ret = nv50_fence_create(drm); - else if (device->card_type < NV_C0) ret = nv84_fence_create(drm); - else ret = nvc0_fence_create(drm); + /*XXX: this is crap, but the fence/channel stuff is a little + * backwards in some places. this will be fixed. + */ + ret = nouveau_parent_lclass(nvkm_object(device), sclass, + ARRAY_SIZE(sclass)); + if (ret < 0) + return; + + for (ret = -ENOSYS, i = 0; ret && i < ARRAY_SIZE(sclass); i++) { + switch (sclass[i]) { + case NV03_CHANNEL_DMA_CLASS: + ret = nv04_fence_create(drm); + break; + case NV10_CHANNEL_DMA_CLASS: + ret = nv10_fence_create(drm); + break; + case NV17_CHANNEL_DMA_CLASS: + case NV40_CHANNEL_DMA_CLASS: + ret = nv17_fence_create(drm); + break; + case NV50_CHANNEL_IND_CLASS: + ret = nv50_fence_create(drm); + break; + case NV84_CHANNEL_IND_CLASS: + ret = nv84_fence_create(drm); + break; + case NVC0_CHANNEL_IND_CLASS: + case NVE0_CHANNEL_IND_CLASS: + ret = nvc0_fence_create(drm); + break; + default: + break; + } + } + if (ret) { NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret); nouveau_accel_fini(drm); return; } - if (device->card_type >= NV_E0) { + if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, NVDRM_CHAN + 1, NVE0_CHANNEL_IND_ENGINE_CE0 | @@ -184,9 +213,9 @@ nouveau_accel_init(struct nouveau_drm *drm) arg0 = NVE0_CHANNEL_IND_ENGINE_GR; arg1 = 1; } else - if (device->chipset >= 0xa3 && - device->chipset != 0xaa && - device->chipset != 0xac) { + if (device->info.chipset >= 0xa3 && + device->info.chipset != 0xaa && + device->info.chipset != 0xac) { ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, NVDRM_CHAN + 1, NvDmaFB, NvDmaTT, &drm->cechan); @@ -214,11 +243,11 @@ nouveau_accel_init(struct nouveau_drm *drm) struct nouveau_software_chan *swch = (void *)object->parent; ret = RING_SPACE(drm->channel, 2); if (ret == 0) { - if (device->card_type < NV_C0) { + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { BEGIN_NV04(drm->channel, NvSubSw, 0, 1); OUT_RING (drm->channel, NVDRM_NVSW); } else - if (device->card_type < NV_E0) { + if (device->info.family < NV_DEVICE_INFO_V0_KEPLER) { BEGIN_NVC0(drm->channel, FermiSw, 0, 1); OUT_RING (drm->channel, 0x001f0000); } @@ -234,9 +263,9 @@ nouveau_accel_init(struct nouveau_drm *drm) return; } - if (device->card_type < NV_C0) { - ret = nouveau_gpuobj_new(drm->device, NULL, 32, 0, 0, - &drm->notify); + if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { + ret = nouveau_gpuobj_new(nvkm_object(&drm->device), NULL, 32, + 0, 0, &drm->notify); if (ret) { NV_ERROR(drm, "failed to allocate notifier, %d\n", ret); nouveau_accel_fini(drm); @@ -344,6 +373,27 @@ nouveau_get_hdmi_dev(struct nouveau_drm *drm) } } +void +nouveau_drm_hack_device(struct nouveau_drm *drm, struct nvif_device *device) +{ + drm->device.info.chipset = nvkm_device(&drm->device)->chipset; + switch (nvkm_device(&drm->device)->card_type) { + case NV_04: device->info.family = NV_DEVICE_INFO_V0_TNT; break; + case NV_10: device->info.family = NV_DEVICE_INFO_V0_CELSIUS; break; + case NV_11: device->info.family = NV_DEVICE_INFO_V0_CELSIUS; break; + case NV_20: device->info.family = NV_DEVICE_INFO_V0_KELVIN; break; + case NV_30: device->info.family = NV_DEVICE_INFO_V0_RANKINE; break; + case NV_40: device->info.family = NV_DEVICE_INFO_V0_CURIE; break; + case NV_50: device->info.family = NV_DEVICE_INFO_V0_TESLA; break; + case NV_C0: device->info.family = NV_DEVICE_INFO_V0_FERMI; break; + case NV_E0: device->info.family = NV_DEVICE_INFO_V0_KEPLER; break; + case GM100: device->info.family = NV_DEVICE_INFO_V0_MAXWELL; break; + default: + BUG_ON(1); + break; + } +} + static int nouveau_drm_load(struct drm_device *dev, unsigned long flags) { @@ -381,10 +431,13 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) NV_DEVICE_DISABLE_IDENTIFY), .debug0 = ~0, }, sizeof(struct nv_device_class), - &drm->device); + (struct nouveau_object **) + &drm->device.object); if (ret) goto fail_device; + nouveau_drm_hack_device(drm, &drm->device); + nouveau_agp_reset(drm); nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE); } @@ -395,24 +448,27 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) .disable = 0, .debug0 = 0, }, sizeof(struct nv_device_class), - &drm->device); + (struct nouveau_object **) + &drm->device.object); if (ret) goto fail_device; + nouveau_drm_hack_device(drm, &drm->device); + dev->irq_enabled = true; /* workaround an odd issue on nvc1 by disabling the device's * nosnoop capability. hopefully won't cause issues until a * better fix is found - assuming there is one... */ - if (nv_device(drm->device)->chipset == 0xc1) - nvif_mask(drm->device, 0x00088080, 0x00000800, 0x00000000); + if (drm->device.info.chipset == 0xc1) + nvif_mask(&drm->device, 0x00088080, 0x00000800, 0x00000000); nouveau_vga_init(drm); nouveau_agp_init(drm); - if (nv_device(drm->device)->card_type >= NV_50) { - ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40), + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40), 0x1000, &drm->client.vm); if (ret) goto fail_device; @@ -723,8 +779,8 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) if (ret) goto out_suspend; - if (nv_device(drm->device)->card_type >= NV_50) { - ret = nouveau_vm_new(nv_device(drm->device), 0, (1ULL << 40), + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { + ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40), 0x1000, &cli->vm); if (ret) { nouveau_cli_destroy(cli); @@ -930,7 +986,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - struct nouveau_object *device = nouveau_drm(drm_dev)->device; + struct nvif_device *device = &nouveau_drm(drm_dev)->device; int ret; if (nouveau_runtime_pm == 0) |