1/* 2 * Copyright 2010 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 */ 24 25#include "drmP.h" 26 27#include "nouveau_drv.h" 28#include "nouveau_vm.h" 29 30struct nvc0_instmem_priv { 31 struct nouveau_gpuobj *bar1_pgd; 32 struct nouveau_channel *bar1; 33 struct nouveau_gpuobj *bar3_pgd; 34 struct nouveau_channel *bar3; 35}; 36 37int 38nvc0_instmem_suspend(struct drm_device *dev) 39{ 40 struct drm_nouveau_private *dev_priv = dev->dev_private; 41 42 dev_priv->ramin_available = false; 43 return 0; 44} 45 46void 47nvc0_instmem_resume(struct drm_device *dev) 48{ 49 struct drm_nouveau_private *dev_priv = dev->dev_private; 50 struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; 51 52 nv_mask(dev, 0x100c80, 0x00000001, 0x00000000); 53 nv_wr32(dev, 0x001704, 0x80000000 | priv->bar1->ramin->vinst >> 12); 54 nv_wr32(dev, 0x001714, 0xc0000000 | priv->bar3->ramin->vinst >> 12); 55 dev_priv->ramin_available = true; 56} 57 58static void 59nvc0_channel_del(struct nouveau_channel **pchan) 60{ 61 struct nouveau_channel *chan; 62 63 chan = *pchan; 64 *pchan = NULL; 65 if (!chan) 66 return; 67 68 nouveau_vm_ref(NULL, &chan->vm, NULL); 69 if (drm_mm_initialized(&chan->ramin_heap)) 70 drm_mm_takedown(&chan->ramin_heap); 71 nouveau_gpuobj_ref(NULL, &chan->ramin); 72 kfree(chan); 73} 74 75static int 76nvc0_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm, 77 struct nouveau_channel **pchan, 78 struct nouveau_gpuobj *pgd, u64 vm_size) 79{ 80 struct nouveau_channel *chan; 81 int ret; 82 83 chan = kzalloc(sizeof(*chan), GFP_KERNEL); 84 if (!chan) 85 return -ENOMEM; 86 chan->dev = dev; 87 88 ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); 89 if (ret) { 90 nvc0_channel_del(&chan); 91 return ret; 92 } 93 94 ret = drm_mm_init(&chan->ramin_heap, 0x1000, size - 0x1000); 95 if (ret) { 96 nvc0_channel_del(&chan); 97 return ret; 98 } 99 100 ret = nouveau_vm_ref(vm, &chan->vm, NULL); 101 if (ret) { 102 nvc0_channel_del(&chan); 103 return ret; 104 } 105 106 nv_wo32(chan->ramin, 0x0200, lower_32_bits(pgd->vinst)); 107 nv_wo32(chan->ramin, 0x0204, upper_32_bits(pgd->vinst)); 108 nv_wo32(chan->ramin, 0x0208, lower_32_bits(vm_size - 1)); 109 nv_wo32(chan->ramin, 0x020c, upper_32_bits(vm_size - 1)); 110 111 *pchan = chan; 112 return 0; 113} 114 115int 116nvc0_instmem_init(struct drm_device *dev) 117{ 118 struct drm_nouveau_private *dev_priv = dev->dev_private; 119 struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; 120 struct pci_dev *pdev = dev->pdev; 121 struct nvc0_instmem_priv *priv; 122 struct nouveau_vm *vm = NULL; 123 int ret; 124 125 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 126 if (!priv) 127 return -ENOMEM; 128 pinstmem->priv = priv; 129 130 /* BAR3 VM */ 131 ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 3), 0, 132 &dev_priv->bar3_vm); 133 if (ret) 134 goto error; 135 136 ret = nouveau_gpuobj_new(dev, NULL, 137 (pci_resource_len(pdev, 3) >> 12) * 8, 0, 138 NVOBJ_FLAG_DONT_MAP | 139 NVOBJ_FLAG_ZERO_ALLOC, 140 &dev_priv->bar3_vm->pgt[0].obj[0]); 141 if (ret) 142 goto error; 143 dev_priv->bar3_vm->pgt[0].refcount[0] = 1; 144 145 nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]); 146 147 ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, 148 NVOBJ_FLAG_ZERO_ALLOC, &priv->bar3_pgd); 149 if (ret) 150 goto error; 151 152 ret = nouveau_vm_ref(dev_priv->bar3_vm, &vm, priv->bar3_pgd); 153 if (ret) 154 goto error; 155 nouveau_vm_ref(NULL, &vm, NULL); 156 157 ret = nvc0_channel_new(dev, 8192, dev_priv->bar3_vm, &priv->bar3, 158 priv->bar3_pgd, pci_resource_len(dev->pdev, 3)); 159 if (ret) 160 goto error; 161 162 /* BAR1 VM */ 163 ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 1), 0, &vm); 164 if (ret) 165 goto error; 166 167 ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, 168 NVOBJ_FLAG_ZERO_ALLOC, &priv->bar1_pgd); 169 if (ret) 170 goto error; 171 172 ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, priv->bar1_pgd); 173 if (ret) 174 goto error; 175 nouveau_vm_ref(NULL, &vm, NULL); 176 177 ret = nvc0_channel_new(dev, 8192, dev_priv->bar1_vm, &priv->bar1, 178 priv->bar1_pgd, pci_resource_len(dev->pdev, 1)); 179 if (ret) 180 goto error; 181 182 /* channel vm */ 183 ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, 184 &dev_priv->chan_vm); 185 if (ret) 186 goto error; 187 188 nvc0_instmem_resume(dev); 189 return 0; 190error: 191 nvc0_instmem_takedown(dev); 192 return ret; 193} 194 195void 196nvc0_instmem_takedown(struct drm_device *dev) 197{ 198 struct drm_nouveau_private *dev_priv = dev->dev_private; 199 struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; 200 struct nouveau_vm *vm = NULL; 201 202 nvc0_instmem_suspend(dev); 203 204 nv_wr32(dev, 0x1704, 0x00000000); 205 nv_wr32(dev, 0x1714, 0x00000000); 206 207 nouveau_vm_ref(NULL, &dev_priv->chan_vm, NULL); 208 209 nvc0_channel_del(&priv->bar1); 210 nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd); 211 nouveau_gpuobj_ref(NULL, &priv->bar1_pgd); 212 213 nvc0_channel_del(&priv->bar3); 214 nouveau_vm_ref(dev_priv->bar3_vm, &vm, NULL); 215 nouveau_vm_ref(NULL, &vm, priv->bar3_pgd); 216 nouveau_gpuobj_ref(NULL, &priv->bar3_pgd); 217 nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]); 218 nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); 219 220 dev_priv->engine.instmem.priv = NULL; 221 kfree(priv); 222} 223 224