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 
30 struct 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 
37 int
nvc0_instmem_suspend(struct drm_device * dev)38 nvc0_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 
46 void
nvc0_instmem_resume(struct drm_device * dev)47 nvc0_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 
58 static void
nvc0_channel_del(struct nouveau_channel ** pchan)59 nvc0_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 
75 static int
nvc0_channel_new(struct drm_device * dev,u32 size,struct nouveau_vm * vm,struct nouveau_channel ** pchan,struct nouveau_gpuobj * pgd,u64 vm_size)76 nvc0_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 
115 int
nvc0_instmem_init(struct drm_device * dev)116 nvc0_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;
190 error:
191 	nvc0_instmem_takedown(dev);
192 	return ret;
193 }
194 
195 void
nvc0_instmem_takedown(struct drm_device * dev)196 nvc0_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