diff options
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/sim.c')
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/sim.c | 314 |
1 files changed, 39 insertions, 275 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/sim.c b/drivers/gpu/nvgpu/common/linux/sim.c index 8f016e58..5406035b 100644 --- a/drivers/gpu/nvgpu/common/linux/sim.c +++ b/drivers/gpu/nvgpu/common/linux/sim.c | |||
@@ -23,310 +23,74 @@ | |||
23 | #include <nvgpu/bitops.h> | 23 | #include <nvgpu/bitops.h> |
24 | #include <nvgpu/nvgpu_mem.h> | 24 | #include <nvgpu/nvgpu_mem.h> |
25 | #include <nvgpu/dma.h> | 25 | #include <nvgpu/dma.h> |
26 | #include <nvgpu/soc.h> | ||
27 | #include <nvgpu/hw_sim.h> | ||
26 | #include "gk20a/gk20a.h" | 28 | #include "gk20a/gk20a.h" |
27 | #include "sim.h" | 29 | #include "platform_gk20a.h" |
30 | #include "os_linux.h" | ||
31 | #include "module.h" | ||
32 | #include "sim.h" /* will be removed in next patch */ | ||
28 | 33 | ||
29 | #include <nvgpu/hw/gk20a/hw_sim_gk20a.h> | 34 | void sim_writel(struct sim_nvgpu *sim, u32 r, u32 v) |
30 | |||
31 | static inline void sim_writel(struct sim_gk20a *sim, u32 r, u32 v) | ||
32 | { | 35 | { |
33 | struct sim_gk20a_linux *sim_linux = | 36 | struct sim_nvgpu_linux *sim_linux = |
34 | container_of(sim, struct sim_gk20a_linux, sim); | 37 | container_of(sim, struct sim_nvgpu_linux, sim); |
35 | 38 | ||
36 | writel(v, sim_linux->regs + r); | 39 | writel(v, sim_linux->regs + r); |
37 | } | 40 | } |
38 | 41 | ||
39 | static inline u32 sim_readl(struct sim_gk20a *sim, u32 r) | 42 | u32 sim_readl(struct sim_nvgpu *sim, u32 r) |
40 | { | 43 | { |
41 | struct sim_gk20a_linux *sim_linux = | 44 | struct sim_nvgpu_linux *sim_linux = |
42 | container_of(sim, struct sim_gk20a_linux, sim); | 45 | container_of(sim, struct sim_nvgpu_linux, sim); |
43 | 46 | ||
44 | return readl(sim_linux->regs + r); | 47 | return readl(sim_linux->regs + r); |
45 | } | 48 | } |
46 | 49 | ||
47 | static int gk20a_alloc_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | 50 | void nvgpu_remove_sim_support_linux(struct gk20a *g) |
48 | { | 51 | { |
49 | int err; | 52 | struct sim_nvgpu_linux *sim_linux; |
50 | |||
51 | err = nvgpu_dma_alloc(g, PAGE_SIZE, mem); | ||
52 | |||
53 | if (err) | ||
54 | return err; | ||
55 | /* | ||
56 | * create a valid cpu_va mapping | ||
57 | */ | ||
58 | nvgpu_mem_begin(g, mem); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | 53 | ||
63 | static void gk20a_free_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | 54 | if (!g->sim) { |
64 | { | 55 | nvgpu_warn(g, "sim not allocated or not in sim_mode"); |
65 | if (nvgpu_mem_is_valid(mem)) { | 56 | return; |
66 | /* | ||
67 | * invalidate the cpu_va mapping | ||
68 | */ | ||
69 | nvgpu_mem_end(g, mem); | ||
70 | nvgpu_dma_free(g, mem); | ||
71 | } | 57 | } |
72 | 58 | sim_linux = container_of(g->sim, struct sim_nvgpu_linux, sim); | |
73 | memset(mem, 0, sizeof(*mem)); | ||
74 | } | ||
75 | |||
76 | static void gk20a_free_sim_support(struct gk20a *g) | ||
77 | { | ||
78 | gk20a_free_sim_buffer(g, &g->sim->send_bfr); | ||
79 | gk20a_free_sim_buffer(g, &g->sim->recv_bfr); | ||
80 | gk20a_free_sim_buffer(g, &g->sim->msg_bfr); | ||
81 | } | ||
82 | |||
83 | static void gk20a_remove_sim_support(struct sim_gk20a *s) | ||
84 | { | ||
85 | struct gk20a *g = s->g; | ||
86 | struct sim_gk20a_linux *sim_linux = | ||
87 | container_of(g->sim, struct sim_gk20a_linux, sim); | ||
88 | |||
89 | if (sim_linux->regs) | ||
90 | sim_writel(s, sim_config_r(), sim_config_mode_disabled_v()); | ||
91 | |||
92 | if (sim_linux->regs) { | 59 | if (sim_linux->regs) { |
60 | sim_writel(g->sim, sim_config_r(), sim_config_mode_disabled_v()); | ||
93 | iounmap(sim_linux->regs); | 61 | iounmap(sim_linux->regs); |
94 | sim_linux->regs = NULL; | 62 | sim_linux->regs = NULL; |
95 | } | 63 | } |
96 | gk20a_free_sim_support(g); | ||
97 | |||
98 | nvgpu_kfree(g, sim_linux); | 64 | nvgpu_kfree(g, sim_linux); |
99 | g->sim = NULL; | 65 | g->sim = NULL; |
100 | } | 66 | } |
101 | 67 | ||
102 | static inline u32 sim_msg_header_size(void) | 68 | int nvgpu_init_sim_support_linux(struct gk20a *g, |
103 | { | 69 | struct platform_device *dev) |
104 | return 24;/*TBD: fix the header to gt this from NV_VGPU_MSG_HEADER*/ | ||
105 | } | ||
106 | |||
107 | static inline u32 *sim_msg_bfr(struct gk20a *g, u32 byte_offset) | ||
108 | { | ||
109 | u8 *cpu_va; | ||
110 | |||
111 | cpu_va = (u8 *)sim_linux->msg_bfr.cpu_va; | ||
112 | |||
113 | return (u32 *)(cpu_va + byte_offset); | ||
114 | } | ||
115 | |||
116 | static inline u32 *sim_msg_hdr(struct gk20a *g, u32 byte_offset) | ||
117 | { | ||
118 | return sim_msg_bfr(g, byte_offset); /*starts at 0*/ | ||
119 | } | ||
120 | |||
121 | static inline u32 *sim_msg_param(struct gk20a *g, u32 byte_offset) | ||
122 | { | ||
123 | /*starts after msg header/cmn*/ | ||
124 | return sim_msg_bfr(g, byte_offset + sim_msg_header_size()); | ||
125 | } | ||
126 | |||
127 | static inline void sim_write_hdr(struct gk20a *g, u32 func, u32 size) | ||
128 | { | ||
129 | /*memset(g->sim->msg_bfr.kvaddr,0,min(PAGE_SIZE,size));*/ | ||
130 | *sim_msg_hdr(g, sim_msg_signature_r()) = sim_msg_signature_valid_v(); | ||
131 | *sim_msg_hdr(g, sim_msg_result_r()) = sim_msg_result_rpc_pending_v(); | ||
132 | *sim_msg_hdr(g, sim_msg_spare_r()) = sim_msg_spare__init_v(); | ||
133 | *sim_msg_hdr(g, sim_msg_function_r()) = func; | ||
134 | *sim_msg_hdr(g, sim_msg_length_r()) = size + sim_msg_header_size(); | ||
135 | } | ||
136 | |||
137 | static inline u32 sim_escape_read_hdr_size(void) | ||
138 | { | ||
139 | return 12; /*TBD: fix NV_VGPU_SIM_ESCAPE_READ_HEADER*/ | ||
140 | } | ||
141 | |||
142 | static u32 *sim_send_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
143 | { | ||
144 | u8 *cpu_va; | ||
145 | |||
146 | cpu_va = (u8 *)sim_linux->send_bfr.cpu_va; | ||
147 | |||
148 | return (u32 *)(cpu_va + byte_offset); | ||
149 | } | ||
150 | |||
151 | static int rpc_send_message(struct gk20a *g) | ||
152 | { | ||
153 | /* calculations done in units of u32s */ | ||
154 | u32 send_base = sim_send_put_pointer_v(g->sim->send_ring_put) * 2; | ||
155 | u32 dma_offset = send_base + sim_dma_r()/sizeof(u32); | ||
156 | u32 dma_hi_offset = send_base + sim_dma_hi_r()/sizeof(u32); | ||
157 | |||
158 | *sim_send_ring_bfr(g, dma_offset*sizeof(u32)) = | ||
159 | sim_dma_target_phys_pci_coherent_f() | | ||
160 | sim_dma_status_valid_f() | | ||
161 | sim_dma_size_4kb_f() | | ||
162 | sim_dma_addr_lo_f(nvgpu_mem_get_addr(g, &sim_linux->msg_bfr) >> PAGE_SHIFT); | ||
163 | |||
164 | *sim_send_ring_bfr(g, dma_hi_offset*sizeof(u32)) = | ||
165 | u64_hi32(nvgpu_mem_get_addr(g, &g->sim->msg_bfr)); | ||
166 | |||
167 | *sim_msg_hdr(g, sim_msg_sequence_r()) = g->sim->sequence_base++; | ||
168 | |||
169 | g->sim->send_ring_put = (g->sim->send_ring_put + 2 * sizeof(u32)) % PAGE_SIZE; | ||
170 | |||
171 | /* Update the put pointer. This will trap into the host. */ | ||
172 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static inline u32 *sim_recv_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
178 | { | 70 | { |
179 | u8 *cpu_va; | 71 | struct sim_nvgpu_linux *sim_linux; |
180 | 72 | int err = -ENOMEM; | |
181 | cpu_va = (u8 *)sim_linux->recv_bfr.cpu_va; | ||
182 | |||
183 | return (u32 *)(cpu_va + byte_offset); | ||
184 | } | ||
185 | |||
186 | static int rpc_recv_poll(struct gk20a *g) | ||
187 | { | ||
188 | u64 recv_phys_addr; | ||
189 | |||
190 | /* XXX This read is not required (?) */ | ||
191 | /*pVGpu->recv_ring_get = VGPU_REG_RD32(pGpu, NV_VGPU_RECV_GET);*/ | ||
192 | |||
193 | /* Poll the recv ring get pointer in an infinite loop*/ | ||
194 | do { | ||
195 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
196 | } while (g->sim->recv_ring_put == g->sim->recv_ring_get); | ||
197 | |||
198 | /* process all replies */ | ||
199 | while (g->sim->recv_ring_put != g->sim->recv_ring_get) { | ||
200 | /* these are in u32 offsets*/ | ||
201 | u32 dma_lo_offset = | ||
202 | sim_recv_put_pointer_v(g->sim->recv_ring_get)*2 + 0; | ||
203 | u32 dma_hi_offset = dma_lo_offset + 1; | ||
204 | u32 recv_phys_addr_lo = sim_dma_addr_lo_v( | ||
205 | *sim_recv_ring_bfr(g, dma_lo_offset*4)); | ||
206 | u32 recv_phys_addr_hi = sim_dma_hi_addr_v( | ||
207 | *sim_recv_ring_bfr(g, dma_hi_offset*4)); | ||
208 | |||
209 | recv_phys_addr = (u64)recv_phys_addr_hi << 32 | | ||
210 | (u64)recv_phys_addr_lo << PAGE_SHIFT; | ||
211 | 73 | ||
212 | if (recv_phys_addr != | 74 | if (!nvgpu_platform_is_simulation(g)) |
213 | nvgpu_mem_get_addr(g, &g->sim->msg_bfr)) { | 75 | return 0; |
214 | nvgpu_err(g, "%s Error in RPC reply", | ||
215 | __func__); | ||
216 | return -1; | ||
217 | } | ||
218 | |||
219 | /* Update GET pointer */ | ||
220 | g->sim->recv_ring_get = (g->sim->recv_ring_get + 2*sizeof(u32)) % PAGE_SIZE; | ||
221 | |||
222 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
223 | |||
224 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int issue_rpc_and_wait(struct gk20a *g) | ||
231 | { | ||
232 | int err; | ||
233 | |||
234 | err = rpc_send_message(g); | ||
235 | if (err) { | ||
236 | nvgpu_err(g, "%s failed rpc_send_message", | ||
237 | __func__); | ||
238 | return err; | ||
239 | } | ||
240 | 76 | ||
241 | err = rpc_recv_poll(g); | 77 | sim_linux = nvgpu_kzalloc(g, sizeof(*sim_linux)); |
242 | if (err) { | 78 | if (!sim_linux) |
243 | nvgpu_err(g, "%s failed rpc_recv_poll", | ||
244 | __func__); | ||
245 | return err; | 79 | return err; |
246 | } | 80 | g->sim = &sim_linux->sim; |
247 | 81 | g->sim->g = g; | |
248 | /* Now check if RPC really succeeded */ | 82 | sim_linux->regs = nvgpu_ioremap_resource(dev, |
249 | if (*sim_msg_hdr(g, sim_msg_result_r()) != sim_msg_result_success_v()) { | 83 | GK20A_SIM_IORESOURCE_MEM, |
250 | nvgpu_err(g, "%s received failed status!", | 84 | &sim_linux->reg_mem); |
251 | __func__); | 85 | if (IS_ERR(sim_linux->regs)) { |
252 | return -(*sim_msg_hdr(g, sim_msg_result_r())); | 86 | nvgpu_err(g, "failed to remap gk20a sim regs"); |
253 | } | 87 | err = PTR_ERR(sim_linux->regs); |
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int gk20a_sim_esc_readl(struct gk20a *g, char *path, u32 index, u32 *data) | ||
258 | { | ||
259 | int err; | ||
260 | size_t pathlen = strlen(path); | ||
261 | u32 data_offset; | ||
262 | |||
263 | sim_write_hdr(g, sim_msg_function_sim_escape_read_v(), | ||
264 | sim_escape_read_hdr_size()); | ||
265 | *sim_msg_param(g, 0) = index; | ||
266 | *sim_msg_param(g, 4) = sizeof(u32); | ||
267 | data_offset = roundup(0xc + pathlen + 1, sizeof(u32)); | ||
268 | *sim_msg_param(g, 8) = data_offset; | ||
269 | strcpy((char *)sim_msg_param(g, 0xc), path); | ||
270 | |||
271 | err = issue_rpc_and_wait(g); | ||
272 | |||
273 | if (!err) | ||
274 | memcpy(data, sim_msg_param(g, data_offset), sizeof(u32)); | ||
275 | return err; | ||
276 | } | ||
277 | |||
278 | |||
279 | int gk20a_init_sim_support(struct gk20a *g) | ||
280 | { | ||
281 | int err = 0; | ||
282 | u64 phys; | ||
283 | |||
284 | /* allocate sim event/msg buffers */ | ||
285 | err = gk20a_alloc_sim_buffer(g, &g->sim->send_bfr); | ||
286 | err = err || gk20a_alloc_sim_buffer(g, &g->sim->recv_bfr); | ||
287 | err = err || gk20a_alloc_sim_buffer(g, &g->sim->msg_bfr); | ||
288 | |||
289 | if (err) | ||
290 | goto fail; | 88 | goto fail; |
291 | /*mark send ring invalid*/ | 89 | } |
292 | sim_writel(g->sim, sim_send_ring_r(), sim_send_ring_status_invalid_f()); | 90 | sim_linux->remove_support_linux = nvgpu_remove_sim_support_linux; |
293 | |||
294 | /*read get pointer and make equal to put*/ | ||
295 | g->sim->send_ring_put = sim_readl(g->sim, sim_send_get_r()); | ||
296 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
297 | |||
298 | /*write send ring address and make it valid*/ | ||
299 | phys = nvgpu_mem_get_addr(g, &g->sim->send_bfr); | ||
300 | sim_writel(g->sim, sim_send_ring_hi_r(), | ||
301 | sim_send_ring_hi_addr_f(u64_hi32(phys))); | ||
302 | sim_writel(g->sim, sim_send_ring_r(), | ||
303 | sim_send_ring_status_valid_f() | | ||
304 | sim_send_ring_target_phys_pci_coherent_f() | | ||
305 | sim_send_ring_size_4kb_f() | | ||
306 | sim_send_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
307 | |||
308 | /*repeat for recv ring (but swap put,get as roles are opposite) */ | ||
309 | sim_writel(g->sim, sim_recv_ring_r(), sim_recv_ring_status_invalid_f()); | ||
310 | |||
311 | /*read put pointer and make equal to get*/ | ||
312 | g->sim->recv_ring_get = sim_readl(g->sim, sim_recv_put_r()); | ||
313 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
314 | |||
315 | /*write send ring address and make it valid*/ | ||
316 | phys = nvgpu_mem_get_addr(g, &g->sim->recv_bfr); | ||
317 | sim_writel(g->sim, sim_recv_ring_hi_r(), | ||
318 | sim_recv_ring_hi_addr_f(u64_hi32(phys))); | ||
319 | sim_writel(g->sim, sim_recv_ring_r(), | ||
320 | sim_recv_ring_status_valid_f() | | ||
321 | sim_recv_ring_target_phys_pci_coherent_f() | | ||
322 | sim_recv_ring_size_4kb_f() | | ||
323 | sim_recv_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
324 | |||
325 | g->sim->remove_support = gk20a_remove_sim_support; | ||
326 | g->sim->esc_readl = gk20a_sim_esc_readl; | ||
327 | return 0; | 91 | return 0; |
328 | 92 | ||
329 | fail: | 93 | fail: |
330 | gk20a_free_sim_support(g); | 94 | nvgpu_remove_sim_support_linux(g); |
331 | return err; | 95 | return err; |
332 | } | 96 | } |