Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2012 Red Hat Inc. |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 5 | * copy of this software and associated documentation files (the "Software"), |
| 6 | * to deal in the Software without restriction, including without limitation |
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 8 | * and/or sell copies of the Software, and to permit persons to whom the |
| 9 | * Software is furnished to do so, subject to the following conditions: |
| 10 | * |
| 11 | * The above copyright notice and this permission notice shall be included in |
| 12 | * all copies or substantial portions of the Software. |
| 13 | * |
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 20 | * OTHER DEALINGS IN THE SOFTWARE. |
| 21 | * |
| 22 | * Authors: Ben Skeggs |
| 23 | */ |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 24 | #include "gf100.h" |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 25 | |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 26 | #include <core/gpuobj.h> |
| 27 | #include <subdev/fb.h> |
| 28 | #include <subdev/mmu.h> |
| 29 | |
Ben Skeggs | d8e8399 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 30 | static struct nvkm_vm * |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 31 | gf100_bar_kmap(struct nvkm_bar *base) |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 32 | { |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 33 | return gf100_bar(base)->bar[0].vm; |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 34 | } |
| 35 | |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 36 | int |
| 37 | gf100_bar_umap(struct nvkm_bar *base, u64 size, int type, struct nvkm_vma *vma) |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 38 | { |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 39 | struct gf100_bar *bar = gf100_bar(base); |
Ben Skeggs | d8e8399 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 40 | return nvkm_vm_get(bar->bar[1].vm, size, type, NV_MEM_ACCESS_RW, vma); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 41 | } |
| 42 | |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 43 | static int |
Ben Skeggs | 5b0c189 | 2015-08-20 14:54:06 +1000 | [diff] [blame] | 44 | gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, |
Ben Skeggs | 1de6856 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 45 | struct lock_class_key *key, int bar_nr) |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 46 | { |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 47 | struct nvkm_device *device = bar->base.subdev.device; |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 48 | struct nvkm_vm *vm; |
| 49 | resource_size_t bar_len; |
| 50 | int ret; |
| 51 | |
Ben Skeggs | adb53d2 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 52 | ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0, false, |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 53 | &bar_vm->mem); |
| 54 | if (ret) |
| 55 | return ret; |
| 56 | |
Ben Skeggs | f027f49 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 57 | ret = nvkm_gpuobj_new(device, 0x8000, 0, false, NULL, &bar_vm->pgd); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 58 | if (ret) |
| 59 | return ret; |
| 60 | |
Ben Skeggs | 7e8820f | 2015-08-20 14:54:23 +1000 | [diff] [blame] | 61 | bar_len = device->func->resource_size(device, bar_nr); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 62 | |
Ben Skeggs | 1de6856 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 63 | ret = nvkm_vm_new(device, 0, bar_len, 0, key, &vm); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 64 | if (ret) |
| 65 | return ret; |
| 66 | |
Ben Skeggs | 68f3f70 | 2015-08-20 14:54:22 +1000 | [diff] [blame] | 67 | atomic_inc(&vm->engref[NVKM_SUBDEV_BAR]); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 68 | |
| 69 | /* |
| 70 | * Bootstrap page table lookup. |
| 71 | */ |
| 72 | if (bar_nr == 3) { |
Ben Skeggs | d8e8399 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 73 | ret = nvkm_vm_boot(vm, bar_len); |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 74 | if (ret) { |
| 75 | nvkm_vm_ref(NULL, &vm, NULL); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 76 | return ret; |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 77 | } |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 78 | } |
| 79 | |
| 80 | ret = nvkm_vm_ref(vm, &bar_vm->vm, bar_vm->pgd); |
| 81 | nvkm_vm_ref(NULL, &vm, NULL); |
| 82 | if (ret) |
| 83 | return ret; |
| 84 | |
Ben Skeggs | 1918707 | 2015-08-20 14:54:14 +1000 | [diff] [blame] | 85 | nvkm_kmap(bar_vm->mem); |
| 86 | nvkm_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr)); |
| 87 | nvkm_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr)); |
| 88 | nvkm_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1)); |
| 89 | nvkm_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1)); |
| 90 | nvkm_done(bar_vm->mem); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 91 | return 0; |
| 92 | } |
| 93 | |
| 94 | int |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 95 | gf100_bar_oneinit(struct nvkm_bar *base) |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 96 | { |
Ben Skeggs | 1de6856 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 97 | static struct lock_class_key bar1_lock; |
| 98 | static struct lock_class_key bar3_lock; |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 99 | struct gf100_bar *bar = gf100_bar(base); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 100 | int ret; |
| 101 | |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 102 | /* BAR3 */ |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 103 | if (bar->base.func->kmap) { |
Ben Skeggs | 1de6856 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 104 | ret = gf100_bar_ctor_vm(bar, &bar->bar[0], &bar3_lock, 3); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 105 | if (ret) |
| 106 | return ret; |
| 107 | } |
| 108 | |
| 109 | /* BAR1 */ |
Ben Skeggs | 1de6856 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 110 | ret = gf100_bar_ctor_vm(bar, &bar->bar[1], &bar1_lock, 1); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 111 | if (ret) |
| 112 | return ret; |
| 113 | |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 114 | return 0; |
| 115 | } |
| 116 | |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 117 | int |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 118 | gf100_bar_init(struct nvkm_bar *base) |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 119 | { |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 120 | struct gf100_bar *bar = gf100_bar(base); |
Ben Skeggs | 9155c162 | 2015-08-20 14:54:08 +1000 | [diff] [blame] | 121 | struct nvkm_device *device = bar->base.subdev.device; |
Ben Skeggs | adb53d2 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 122 | u32 addr; |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 123 | |
Ben Skeggs | 9155c162 | 2015-08-20 14:54:08 +1000 | [diff] [blame] | 124 | nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); |
| 125 | nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 126 | |
Ben Skeggs | adb53d2 | 2015-08-20 14:54:17 +1000 | [diff] [blame] | 127 | addr = nvkm_memory_addr(bar->bar[1].mem) >> 12; |
| 128 | nvkm_wr32(device, 0x001704, 0x80000000 | addr); |
| 129 | |
| 130 | if (bar->bar[0].mem) { |
| 131 | addr = nvkm_memory_addr(bar->bar[0].mem) >> 12; |
| 132 | nvkm_wr32(device, 0x001714, 0xc0000000 | addr); |
| 133 | } |
| 134 | |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 135 | return 0; |
| 136 | } |
| 137 | |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 138 | void * |
| 139 | gf100_bar_dtor(struct nvkm_bar *base) |
| 140 | { |
| 141 | struct gf100_bar *bar = gf100_bar(base); |
| 142 | |
| 143 | nvkm_vm_ref(NULL, &bar->bar[1].vm, bar->bar[1].pgd); |
| 144 | nvkm_gpuobj_del(&bar->bar[1].pgd); |
| 145 | nvkm_memory_del(&bar->bar[1].mem); |
| 146 | |
| 147 | if (bar->bar[0].vm) { |
| 148 | nvkm_memory_del(&bar->bar[0].vm->pgt[0].mem[0]); |
| 149 | nvkm_vm_ref(NULL, &bar->bar[0].vm, bar->bar[0].pgd); |
| 150 | } |
| 151 | nvkm_gpuobj_del(&bar->bar[0].pgd); |
| 152 | nvkm_memory_del(&bar->bar[0].mem); |
| 153 | return bar; |
| 154 | } |
| 155 | |
| 156 | int |
| 157 | gf100_bar_new_(const struct nvkm_bar_func *func, struct nvkm_device *device, |
| 158 | int index, struct nvkm_bar **pbar) |
| 159 | { |
| 160 | struct gf100_bar *bar; |
| 161 | if (!(bar = kzalloc(sizeof(*bar), GFP_KERNEL))) |
| 162 | return -ENOMEM; |
| 163 | nvkm_bar_ctor(func, device, index, &bar->base); |
| 164 | *pbar = &bar->base; |
| 165 | return 0; |
| 166 | } |
| 167 | |
| 168 | static const struct nvkm_bar_func |
| 169 | gf100_bar_func = { |
| 170 | .dtor = gf100_bar_dtor, |
| 171 | .oneinit = gf100_bar_oneinit, |
| 172 | .init = gf100_bar_init, |
| 173 | .kmap = gf100_bar_kmap, |
| 174 | .umap = gf100_bar_umap, |
| 175 | .flush = g84_bar_flush, |
Ben Skeggs | 245dcfe | 2015-01-14 14:35:35 +1000 | [diff] [blame] | 176 | }; |
Ben Skeggs | 3293228 | 2015-08-20 14:54:20 +1000 | [diff] [blame] | 177 | |
| 178 | int |
| 179 | gf100_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar) |
| 180 | { |
| 181 | return gf100_bar_new_(&gf100_bar_func, device, index, pbar); |
| 182 | } |