diff options
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/sim_pci.c')
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/sim_pci.c | 326 |
1 files changed, 31 insertions, 295 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/sim_pci.c b/drivers/gpu/nvgpu/common/linux/sim_pci.c index 1ab8c57c..9dac630c 100644 --- a/drivers/gpu/nvgpu/common/linux/sim_pci.c +++ b/drivers/gpu/nvgpu/common/linux/sim_pci.c | |||
@@ -23,276 +23,58 @@ | |||
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/hw_sim_pci.h> | ||
26 | #include "gk20a/gk20a.h" | 27 | #include "gk20a/gk20a.h" |
27 | #include "os_linux.h" | 28 | #include "os_linux.h" |
28 | #include "sim.h" | 29 | #include "module.h" |
29 | #include "hw_sim_pci.h" | 30 | #include "sim.h" /* will be removed in subsequent patches */ |
31 | #include "sim_pci.h"/* will be removed in subsequent patches */ | ||
30 | 32 | ||
31 | static inline void sim_writel(struct sim_gk20a *sim, u32 r, u32 v) | 33 | static bool _nvgpu_pci_is_simulation(struct gk20a *g, u32 sim_base) |
32 | { | 34 | { |
33 | struct sim_gk20a_linux *sim_linux = | 35 | u32 cfg; |
34 | container_of(sim, struct sim_gk20a_linux, sim); | 36 | bool is_simulation = false; |
35 | |||
36 | writel(v, sim_linux->regs + r); | ||
37 | } | ||
38 | 37 | ||
39 | static inline u32 sim_readl(struct sim_gk20a *sim, u32 r) | 38 | cfg = nvgpu_readl(g, sim_base + sim_config_r()); |
40 | { | 39 | if (sim_config_mode_v(cfg) == sim_config_mode_enabled_v()) |
41 | struct sim_gk20a_linux *sim_linux = | 40 | is_simulation = true; |
42 | container_of(sim, struct sim_gk20a_linux, sim); | ||
43 | 41 | ||
44 | return readl(sim_linux->regs + r); | 42 | return is_simulation; |
45 | } | 43 | } |
46 | 44 | ||
47 | static int gk20a_alloc_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | 45 | void nvgpu_remove_sim_support_linux_pci(struct gk20a *g) |
48 | { | 46 | { |
49 | int err; | 47 | struct sim_nvgpu_linux *sim_linux; |
50 | 48 | bool is_simulation; | |
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 | 49 | ||
60 | return 0; | 50 | is_simulation = _nvgpu_pci_is_simulation(g, sim_r()); |
61 | } | ||
62 | 51 | ||
63 | static void gk20a_free_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | 52 | if (!is_simulation) { |
64 | { | 53 | nvgpu_warn(g, "not in sim_mode"); |
65 | if (nvgpu_mem_is_valid(mem)) { | 54 | return; |
66 | /* | ||
67 | * invalidate the cpu_va mapping | ||
68 | */ | ||
69 | nvgpu_mem_end(g, mem); | ||
70 | nvgpu_dma_free(g, mem); | ||
71 | } | 55 | } |
72 | 56 | ||
73 | memset(mem, 0, sizeof(*mem)); | 57 | if (!g->sim) { |
74 | } | 58 | nvgpu_warn(g, "sim_gk20a not allocated"); |
75 | 59 | return; | |
76 | static void gk20a_free_sim_support(struct gk20a *g) | 60 | } |
77 | { | 61 | sim_linux = container_of(g->sim, struct sim_nvgpu_linux, sim); |
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 | 62 | ||
92 | if (sim_linux->regs) { | 63 | if (sim_linux->regs) { |
93 | iounmap(sim_linux->regs); | 64 | sim_writel(g->sim, sim_config_r(), sim_config_mode_disabled_v()); |
94 | sim_linux->regs = NULL; | 65 | sim_linux->regs = NULL; |
95 | } | 66 | } |
96 | gk20a_free_sim_support(g); | ||
97 | |||
98 | nvgpu_kfree(g, sim_linux); | 67 | nvgpu_kfree(g, sim_linux); |
99 | g->sim = NULL; | 68 | g->sim = NULL; |
100 | } | 69 | } |
101 | 70 | ||
102 | static inline u32 sim_msg_header_size(void) | 71 | int nvgpu_init_sim_support_linux_pci(struct gk20a *g) |
103 | { | ||
104 | return 32U; | ||
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 | *sim_msg_hdr(g, sim_msg_header_version_r()) = | ||
130 | sim_msg_header_version_major_tot_v() | | ||
131 | sim_msg_header_version_minor_tot_v(); | ||
132 | *sim_msg_hdr(g, sim_msg_signature_r()) = sim_msg_signature_valid_v(); | ||
133 | *sim_msg_hdr(g, sim_msg_result_r()) = sim_msg_result_rpc_pending_v(); | ||
134 | *sim_msg_hdr(g, sim_msg_spare_r()) = sim_msg_spare__init_v(); | ||
135 | *sim_msg_hdr(g, sim_msg_function_r()) = func; | ||
136 | *sim_msg_hdr(g, sim_msg_length_r()) = size + sim_msg_header_size(); | ||
137 | } | ||
138 | |||
139 | static inline u32 sim_escape_read_hdr_size(void) | ||
140 | { | ||
141 | return 12U; | ||
142 | } | ||
143 | |||
144 | static u32 *sim_send_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
145 | { | ||
146 | u8 *cpu_va; | ||
147 | |||
148 | cpu_va = (u8 *)sim_linux->send_bfr.cpu_va; | ||
149 | |||
150 | return (u32 *)(cpu_va + byte_offset); | ||
151 | } | ||
152 | |||
153 | static int rpc_send_message(struct gk20a *g) | ||
154 | { | ||
155 | /* calculations done in units of u32s */ | ||
156 | u32 send_base = sim_send_put_pointer_v(g->sim->send_ring_put) * 2; | ||
157 | u32 dma_offset = send_base + sim_dma_r()/sizeof(u32); | ||
158 | u32 dma_hi_offset = send_base + sim_dma_hi_r()/sizeof(u32); | ||
159 | |||
160 | *sim_send_ring_bfr(g, dma_offset*sizeof(u32)) = | ||
161 | sim_dma_target_phys_pci_coherent_f() | | ||
162 | sim_dma_status_valid_f() | | ||
163 | sim_dma_size_4kb_f() | | ||
164 | sim_dma_addr_lo_f(nvgpu_mem_get_addr(g, &sim_linux->msg_bfr) >> PAGE_SHIFT); | ||
165 | |||
166 | *sim_send_ring_bfr(g, dma_hi_offset*sizeof(u32)) = | ||
167 | u64_hi32(nvgpu_mem_get_addr(g, &g->sim->msg_bfr)); | ||
168 | |||
169 | *sim_msg_hdr(g, sim_msg_sequence_r()) = g->sim->sequence_base++; | ||
170 | |||
171 | g->sim->send_ring_put = (g->sim->send_ring_put + 2 * sizeof(u32)) % | ||
172 | PAGE_SIZE; | ||
173 | |||
174 | /* Update the put pointer. This will trap into the host. */ | ||
175 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static inline u32 *sim_recv_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
181 | { | ||
182 | u8 *cpu_va; | ||
183 | |||
184 | cpu_va = (u8 *)sim_linux->recv_bfr.cpu_va; | ||
185 | |||
186 | return (u32 *)(cpu_va + byte_offset); | ||
187 | } | ||
188 | |||
189 | static int rpc_recv_poll(struct gk20a *g) | ||
190 | { | ||
191 | u64 recv_phys_addr; | ||
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 | |||
212 | if (recv_phys_addr != | ||
213 | nvgpu_mem_get_addr(g, &g->sim->msg_bfr)) { | ||
214 | nvgpu_err(g, "Error in RPC reply"); | ||
215 | return -EINVAL; | ||
216 | } | ||
217 | |||
218 | /* Update GET pointer */ | ||
219 | g->sim->recv_ring_get = (g->sim->recv_ring_get + 2*sizeof(u32)) | ||
220 | % 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, "failed rpc_send_message"); | ||
237 | return err; | ||
238 | } | ||
239 | |||
240 | err = rpc_recv_poll(g); | ||
241 | if (err) { | ||
242 | nvgpu_err(g, "failed rpc_recv_poll"); | ||
243 | return err; | ||
244 | } | ||
245 | |||
246 | /* Now check if RPC really succeeded */ | ||
247 | if (*sim_msg_hdr(g, sim_msg_result_r()) != sim_msg_result_success_v()) { | ||
248 | nvgpu_err(g, "received failed status!"); | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int gk20a_sim_esc_readl(struct gk20a *g, char *path, u32 index, u32 *data) | ||
255 | { | 72 | { |
256 | int err; | ||
257 | size_t pathlen = strlen(path); | ||
258 | u32 data_offset; | ||
259 | |||
260 | sim_write_hdr(g, sim_msg_function_sim_escape_read_v(), | ||
261 | sim_escape_read_hdr_size()); | ||
262 | *sim_msg_param(g, 0) = index; | ||
263 | *sim_msg_param(g, 4) = sizeof(u32); | ||
264 | data_offset = roundup(pathlen + 1, sizeof(u32)); | ||
265 | *sim_msg_param(g, 8) = data_offset; | ||
266 | strcpy((char *)sim_msg_param(g, 0xc), path); | ||
267 | |||
268 | err = issue_rpc_and_wait(g); | ||
269 | |||
270 | if (!err) | ||
271 | memcpy(data, sim_msg_param(g, data_offset + 0xc), sizeof(u32)); | ||
272 | return err; | ||
273 | } | ||
274 | |||
275 | static bool _nvgpu_pci_is_simulation(struct gk20a *g, u32 sim_base) | ||
276 | { | ||
277 | u32 cfg; | ||
278 | bool is_simulation = false; | ||
279 | |||
280 | cfg = nvgpu_readl(g, sim_base + sim_config_r()); | ||
281 | if (sim_config_mode_v(cfg) == sim_config_mode_enabled_v()) | ||
282 | is_simulation = true; | ||
283 | |||
284 | return is_simulation; | ||
285 | } | ||
286 | |||
287 | int nvgpu_pci_init_sim_support(struct gk20a *g) | ||
288 | { | ||
289 | int err = 0; | ||
290 | u64 phys; | ||
291 | struct sim_gk20a_linux *sim_linux; | ||
292 | bool is_simulation; | ||
293 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | 73 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); |
74 | struct sim_nvgpu_linux *sim_linux; | ||
75 | int err = -ENOMEM; | ||
76 | bool is_simulation; | ||
294 | 77 | ||
295 | /* initialize sim aperture */ | ||
296 | is_simulation = _nvgpu_pci_is_simulation(g, sim_r()); | 78 | is_simulation = _nvgpu_pci_is_simulation(g, sim_r()); |
297 | __nvgpu_set_enabled(g, NVGPU_IS_FMODEL, is_simulation); | 79 | __nvgpu_set_enabled(g, NVGPU_IS_FMODEL, is_simulation); |
298 | 80 | ||
@@ -301,57 +83,11 @@ int nvgpu_pci_init_sim_support(struct gk20a *g) | |||
301 | 83 | ||
302 | sim_linux = nvgpu_kzalloc(g, sizeof(*sim_linux)); | 84 | sim_linux = nvgpu_kzalloc(g, sizeof(*sim_linux)); |
303 | if (!sim_linux) | 85 | if (!sim_linux) |
304 | goto fail; | 86 | return err; |
305 | |||
306 | g->sim = &sim_linux->sim; | 87 | g->sim = &sim_linux->sim; |
88 | g->sim->g = g; | ||
307 | sim_linux->regs = l->regs + sim_r(); | 89 | sim_linux->regs = l->regs + sim_r(); |
90 | sim_linux->remove_support_linux = nvgpu_remove_sim_support_linux_pci; | ||
308 | 91 | ||
309 | /* allocate sim event/msg buffers */ | ||
310 | err = gk20a_alloc_sim_buffer(g, &g->sim->send_bfr); | ||
311 | err = err || gk20a_alloc_sim_buffer(g, &g->sim->recv_bfr); | ||
312 | err = err || gk20a_alloc_sim_buffer(g, &g->sim->msg_bfr); | ||
313 | |||
314 | if (err) | ||
315 | goto fail; | ||
316 | /* mark send ring invalid */ | ||
317 | sim_writel(g->sim, sim_send_ring_r(), sim_send_ring_status_invalid_f()); | ||
318 | |||
319 | /* read get pointer and make equal to put */ | ||
320 | g->sim->send_ring_put = sim_readl(g->sim, sim_send_get_r()); | ||
321 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
322 | |||
323 | /* write send ring address and make it valid */ | ||
324 | phys = nvgpu_mem_get_addr(g, &g->sim->send_bfr); | ||
325 | sim_writel(g->sim, sim_send_ring_hi_r(), | ||
326 | sim_send_ring_hi_addr_f(u64_hi32(phys))); | ||
327 | sim_writel(g->sim, sim_send_ring_r(), | ||
328 | sim_send_ring_status_valid_f() | | ||
329 | sim_send_ring_target_phys_pci_coherent_f() | | ||
330 | sim_send_ring_size_4kb_f() | | ||
331 | sim_send_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
332 | |||
333 | /* repeat for recv ring (but swap put,get as roles are opposite) */ | ||
334 | sim_writel(g->sim, sim_recv_ring_r(), sim_recv_ring_status_invalid_f()); | ||
335 | |||
336 | /* read put pointer and make equal to get */ | ||
337 | g->sim->recv_ring_get = sim_readl(g->sim, sim_recv_put_r()); | ||
338 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
339 | |||
340 | /* write send ring address and make it valid */ | ||
341 | phys = nvgpu_mem_get_addr(g, &g->sim->recv_bfr); | ||
342 | sim_writel(g->sim, sim_recv_ring_hi_r(), | ||
343 | sim_recv_ring_hi_addr_f(u64_hi32(phys))); | ||
344 | sim_writel(g->sim, sim_recv_ring_r(), | ||
345 | sim_recv_ring_status_valid_f() | | ||
346 | sim_recv_ring_target_phys_pci_coherent_f() | | ||
347 | sim_recv_ring_size_4kb_f() | | ||
348 | sim_recv_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
349 | |||
350 | g->sim->remove_support = gk20a_remove_sim_support; | ||
351 | g->sim->esc_readl = gk20a_sim_esc_readl; | ||
352 | return 0; | 92 | return 0; |
353 | |||
354 | fail: | ||
355 | gk20a_free_sim_support(g); | ||
356 | return err; | ||
357 | } | 93 | } |