diff options
author | Alexandre Courbot <acourbot@nvidia.com> | 2015-02-20 04:23:00 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2015-04-14 03:00:42 -0400 |
commit | a6ff85d386368da8180828e5948ec38b39f4a226 (patch) | |
tree | 77233ae77f8e9022f801d20520040b8af08073e5 | |
parent | eaecf0326f096faaba462eae48a3b30bcb1f7009 (diff) |
drm/nouveau/instmem/gk20a: move memory allocation to instmem
GK20A does not have dedicated RAM, thus having a RAM device for it does
not make sense. Move the contiguous physical memory allocation to
instmem.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
5 files changed, 216 insertions, 85 deletions
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index d104c1aac807..1bcb763cfca0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h | |||
@@ -45,4 +45,5 @@ nvkm_instmem(void *obj) | |||
45 | extern struct nvkm_oclass *nv04_instmem_oclass; | 45 | extern struct nvkm_oclass *nv04_instmem_oclass; |
46 | extern struct nvkm_oclass *nv40_instmem_oclass; | 46 | extern struct nvkm_oclass *nv40_instmem_oclass; |
47 | extern struct nvkm_oclass *nv50_instmem_oclass; | 47 | extern struct nvkm_oclass *nv50_instmem_oclass; |
48 | extern struct nvkm_oclass *gk20a_instmem_oclass; | ||
48 | #endif | 49 | #endif |
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index bf5893458a47..8f266a9a34a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c | |||
@@ -171,7 +171,7 @@ gk104_identify(struct nvkm_device *device) | |||
171 | device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass; | 171 | device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass; |
172 | device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; | 172 | device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; |
173 | device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; | 173 | device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; |
174 | device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; | 174 | device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; |
175 | device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; | 175 | device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; |
176 | device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass; | 176 | device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass; |
177 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; | 177 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; |
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c index 5f30db140b47..60d8e1cead61 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c | |||
@@ -23,99 +23,17 @@ | |||
23 | 23 | ||
24 | #include <core/device.h> | 24 | #include <core/device.h> |
25 | 25 | ||
26 | struct gk20a_mem { | ||
27 | struct nvkm_mem base; | ||
28 | void *cpuaddr; | ||
29 | dma_addr_t handle; | ||
30 | }; | ||
31 | #define to_gk20a_mem(m) container_of(m, struct gk20a_mem, base) | ||
32 | |||
33 | static void | 26 | static void |
34 | gk20a_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem) | 27 | gk20a_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem) |
35 | { | 28 | { |
36 | struct device *dev = nv_device_base(nv_device(pfb)); | 29 | BUG(); |
37 | struct gk20a_mem *mem = to_gk20a_mem(*pmem); | ||
38 | |||
39 | *pmem = NULL; | ||
40 | if (unlikely(mem == NULL)) | ||
41 | return; | ||
42 | |||
43 | if (likely(mem->cpuaddr)) | ||
44 | dma_free_coherent(dev, mem->base.size << PAGE_SHIFT, | ||
45 | mem->cpuaddr, mem->handle); | ||
46 | |||
47 | kfree(mem->base.pages); | ||
48 | kfree(mem); | ||
49 | } | 30 | } |
50 | 31 | ||
51 | static int | 32 | static int |
52 | gk20a_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, | 33 | gk20a_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, |
53 | u32 memtype, struct nvkm_mem **pmem) | 34 | u32 memtype, struct nvkm_mem **pmem) |
54 | { | 35 | { |
55 | struct device *dev = nv_device_base(nv_device(pfb)); | 36 | BUG(); |
56 | struct gk20a_mem *mem; | ||
57 | u32 type = memtype & 0xff; | ||
58 | u32 npages, order; | ||
59 | int i; | ||
60 | |||
61 | nv_debug(pfb, "%s: size: %llx align: %x, ncmin: %x\n", __func__, size, | ||
62 | align, ncmin); | ||
63 | |||
64 | npages = size >> PAGE_SHIFT; | ||
65 | if (npages == 0) | ||
66 | npages = 1; | ||
67 | |||
68 | if (align == 0) | ||
69 | align = PAGE_SIZE; | ||
70 | align >>= PAGE_SHIFT; | ||
71 | |||
72 | /* round alignment to the next power of 2, if needed */ | ||
73 | order = fls(align); | ||
74 | if ((align & (align - 1)) == 0) | ||
75 | order--; | ||
76 | align = BIT(order); | ||
77 | |||
78 | /* ensure returned address is correctly aligned */ | ||
79 | npages = max(align, npages); | ||
80 | |||
81 | mem = kzalloc(sizeof(*mem), GFP_KERNEL); | ||
82 | if (!mem) | ||
83 | return -ENOMEM; | ||
84 | |||
85 | mem->base.size = npages; | ||
86 | mem->base.memtype = type; | ||
87 | |||
88 | mem->base.pages = kzalloc(sizeof(dma_addr_t) * npages, GFP_KERNEL); | ||
89 | if (!mem->base.pages) { | ||
90 | kfree(mem); | ||
91 | return -ENOMEM; | ||
92 | } | ||
93 | |||
94 | *pmem = &mem->base; | ||
95 | |||
96 | mem->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT, | ||
97 | &mem->handle, GFP_KERNEL); | ||
98 | if (!mem->cpuaddr) { | ||
99 | nv_error(pfb, "%s: cannot allocate memory!\n", __func__); | ||
100 | gk20a_ram_put(pfb, pmem); | ||
101 | return -ENOMEM; | ||
102 | } | ||
103 | |||
104 | align <<= PAGE_SHIFT; | ||
105 | |||
106 | /* alignment check */ | ||
107 | if (unlikely(mem->handle & (align - 1))) | ||
108 | nv_warn(pfb, "memory not aligned as requested: %pad (0x%x)\n", | ||
109 | &mem->handle, align); | ||
110 | |||
111 | nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %pad, vaddr: %p\n", | ||
112 | npages << PAGE_SHIFT, align, &mem->handle, mem->cpuaddr); | ||
113 | |||
114 | for (i = 0; i < npages; i++) | ||
115 | mem->base.pages[i] = mem->handle + (PAGE_SIZE * i); | ||
116 | |||
117 | mem->base.offset = (u64)mem->base.pages[0]; | ||
118 | return 0; | ||
119 | } | 37 | } |
120 | 38 | ||
121 | static int | 39 | static int |
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild index e6f35abe7879..13bb7fc0a569 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild | |||
@@ -2,3 +2,4 @@ nvkm-y += nvkm/subdev/instmem/base.o | |||
2 | nvkm-y += nvkm/subdev/instmem/nv04.o | 2 | nvkm-y += nvkm/subdev/instmem/nv04.o |
3 | nvkm-y += nvkm/subdev/instmem/nv40.o | 3 | nvkm-y += nvkm/subdev/instmem/nv40.o |
4 | nvkm-y += nvkm/subdev/instmem/nv50.o | 4 | nvkm-y += nvkm/subdev/instmem/nv50.o |
5 | nvkm-y += nvkm/subdev/instmem/gk20a.o | ||
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c new file mode 100644 index 000000000000..9a1fc8404ace --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. | ||
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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <subdev/fb.h> | ||
24 | #include <core/mm.h> | ||
25 | #include <core/device.h> | ||
26 | |||
27 | #include "priv.h" | ||
28 | |||
29 | struct gk20a_instobj_priv { | ||
30 | struct nvkm_instobj base; | ||
31 | /* Must be second member here - see nouveau_gpuobj_map_vm() */ | ||
32 | struct nvkm_mem *mem; | ||
33 | /* Pointed by mem */ | ||
34 | struct nvkm_mem _mem; | ||
35 | void *cpuaddr; | ||
36 | dma_addr_t handle; | ||
37 | struct nvkm_mm_node r; | ||
38 | }; | ||
39 | |||
40 | struct gk20a_instmem_priv { | ||
41 | struct nvkm_instmem base; | ||
42 | spinlock_t lock; | ||
43 | u64 addr; | ||
44 | }; | ||
45 | |||
46 | static u32 | ||
47 | gk20a_instobj_rd32(struct nvkm_object *object, u64 offset) | ||
48 | { | ||
49 | struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(object); | ||
50 | struct gk20a_instobj_priv *node = (void *)object; | ||
51 | unsigned long flags; | ||
52 | u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; | ||
53 | u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; | ||
54 | u32 data; | ||
55 | |||
56 | spin_lock_irqsave(&priv->lock, flags); | ||
57 | if (unlikely(priv->addr != base)) { | ||
58 | nv_wr32(priv, 0x001700, base >> 16); | ||
59 | priv->addr = base; | ||
60 | } | ||
61 | data = nv_rd32(priv, 0x700000 + addr); | ||
62 | spin_unlock_irqrestore(&priv->lock, flags); | ||
63 | return data; | ||
64 | } | ||
65 | |||
66 | static void | ||
67 | gk20a_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data) | ||
68 | { | ||
69 | struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(object); | ||
70 | struct gk20a_instobj_priv *node = (void *)object; | ||
71 | unsigned long flags; | ||
72 | u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; | ||
73 | u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; | ||
74 | |||
75 | spin_lock_irqsave(&priv->lock, flags); | ||
76 | if (unlikely(priv->addr != base)) { | ||
77 | nv_wr32(priv, 0x001700, base >> 16); | ||
78 | priv->addr = base; | ||
79 | } | ||
80 | nv_wr32(priv, 0x700000 + addr, data); | ||
81 | spin_unlock_irqrestore(&priv->lock, flags); | ||
82 | } | ||
83 | |||
84 | static void | ||
85 | gk20a_instobj_dtor(struct nvkm_object *object) | ||
86 | { | ||
87 | struct gk20a_instobj_priv *node = (void *)object; | ||
88 | struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node); | ||
89 | struct device *dev = nv_device_base(nv_device(priv)); | ||
90 | |||
91 | if (unlikely(!node->handle)) | ||
92 | return; | ||
93 | |||
94 | dma_free_coherent(dev, node->mem->size << PAGE_SHIFT, node->cpuaddr, | ||
95 | node->handle); | ||
96 | |||
97 | nvkm_instobj_destroy(&node->base); | ||
98 | } | ||
99 | |||
100 | static int | ||
101 | gk20a_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, | ||
102 | struct nvkm_oclass *oclass, void *data, u32 _size, | ||
103 | struct nvkm_object **pobject) | ||
104 | { | ||
105 | struct nvkm_instobj_args *args = data; | ||
106 | struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent); | ||
107 | struct device *dev = nv_device_base(nv_device(priv)); | ||
108 | struct gk20a_instobj_priv *node; | ||
109 | u32 size, align; | ||
110 | u32 npages; | ||
111 | int ret; | ||
112 | |||
113 | nv_debug(parent, "%s: size: %x align: %x\n", __func__, | ||
114 | args->size, args->align); | ||
115 | |||
116 | size = max((args->size + 4095) & ~4095, (u32)4096); | ||
117 | align = max((args->align + 4095) & ~4095, (u32)4096); | ||
118 | |||
119 | npages = size >> PAGE_SHIFT; | ||
120 | |||
121 | ret = nvkm_instobj_create_(parent, engine, oclass, sizeof(*node), | ||
122 | (void **)&node); | ||
123 | *pobject = nv_object(node); | ||
124 | if (ret) | ||
125 | return ret; | ||
126 | |||
127 | node->mem = &node->_mem; | ||
128 | |||
129 | node->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT, | ||
130 | &node->handle, GFP_KERNEL); | ||
131 | if (!node->cpuaddr) { | ||
132 | nv_error(priv, "cannot allocate DMA memory\n"); | ||
133 | return -ENOMEM; | ||
134 | } | ||
135 | |||
136 | /* alignment check */ | ||
137 | if (unlikely(node->handle & (align - 1))) | ||
138 | nv_warn(priv, "memory not aligned as requested: %pad (0x%x)\n", | ||
139 | &node->handle, align); | ||
140 | |||
141 | node->mem->offset = node->handle; | ||
142 | node->mem->size = size >> 12; | ||
143 | node->mem->memtype = 0; | ||
144 | node->mem->page_shift = 12; | ||
145 | INIT_LIST_HEAD(&node->mem->regions); | ||
146 | |||
147 | node->r.type = 12; | ||
148 | node->r.offset = node->handle >> 12; | ||
149 | node->r.length = npages; | ||
150 | list_add_tail(&node->r.rl_entry, &node->mem->regions); | ||
151 | |||
152 | node->base.addr = node->mem->offset; | ||
153 | node->base.size = size; | ||
154 | |||
155 | nv_debug(parent, "alloc size: 0x%x, align: 0x%x, gaddr: 0x%llx\n", | ||
156 | size, align, node->mem->offset); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static struct nvkm_instobj_impl | ||
162 | gk20a_instobj_oclass = { | ||
163 | .base.ofuncs = &(struct nvkm_ofuncs) { | ||
164 | .ctor = gk20a_instobj_ctor, | ||
165 | .dtor = gk20a_instobj_dtor, | ||
166 | .init = _nvkm_instobj_init, | ||
167 | .fini = _nvkm_instobj_fini, | ||
168 | .rd32 = gk20a_instobj_rd32, | ||
169 | .wr32 = gk20a_instobj_wr32, | ||
170 | }, | ||
171 | }; | ||
172 | |||
173 | |||
174 | |||
175 | static int | ||
176 | gk20a_instmem_fini(struct nvkm_object *object, bool suspend) | ||
177 | { | ||
178 | struct gk20a_instmem_priv *priv = (void *)object; | ||
179 | priv->addr = ~0ULL; | ||
180 | return nvkm_instmem_fini(&priv->base, suspend); | ||
181 | } | ||
182 | |||
183 | static int | ||
184 | gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, | ||
185 | struct nvkm_oclass *oclass, void *data, u32 size, | ||
186 | struct nvkm_object **pobject) | ||
187 | { | ||
188 | struct gk20a_instmem_priv *priv; | ||
189 | int ret; | ||
190 | |||
191 | ret = nvkm_instmem_create(parent, engine, oclass, &priv); | ||
192 | *pobject = nv_object(priv); | ||
193 | if (ret) | ||
194 | return ret; | ||
195 | |||
196 | spin_lock_init(&priv->lock); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | struct nvkm_oclass * | ||
202 | gk20a_instmem_oclass = &(struct nvkm_instmem_impl) { | ||
203 | .base.handle = NV_SUBDEV(INSTMEM, 0xea), | ||
204 | .base.ofuncs = &(struct nvkm_ofuncs) { | ||
205 | .ctor = gk20a_instmem_ctor, | ||
206 | .dtor = _nvkm_instmem_dtor, | ||
207 | .init = _nvkm_instmem_init, | ||
208 | .fini = gk20a_instmem_fini, | ||
209 | }, | ||
210 | .instobj = &gk20a_instobj_oclass.base, | ||
211 | }.base; | ||