Commit | Line | Data |
---|---|---|
800f879a AT |
1 | /* |
2 | * Copyright 2010-2017 Intel Corporation. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License, version 2, | |
6 | * as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * General Public License for more details. | |
12 | * | |
13 | * Disclaimer: The codes contained in these modules may be specific to | |
14 | * the Intel Software Development Platform codenamed Knights Ferry, | |
15 | * and the Intel product codenamed Knights Corner, and are not backward | |
16 | * compatible with other Intel products. Additionally, Intel will NOT | |
17 | * support the codes or instruction set in future products. | |
18 | * | |
19 | * Intel offers no warranty of any kind regarding the code. This code is | |
20 | * licensed on an "AS IS" basis and Intel is not obligated to provide | |
21 | * any support, assistance, installation, training, or other services | |
22 | * of any kind. Intel is also not obligated to provide any updates, | |
23 | * enhancements or extensions. Intel specifically disclaims any warranty | |
24 | * of merchantability, non-infringement, fitness for any particular | |
25 | * purpose, and any other warranty. | |
26 | * | |
27 | * Further, Intel disclaims all liability of any kind, including but | |
28 | * not limited to liability for infringement of any proprietary rights, | |
29 | * relating to the use of the code, even if Intel is notified of the | |
30 | * possibility of such liability. Except as expressly stated in an Intel | |
31 | * license agreement provided with this code and agreed upon with Intel, | |
32 | * no license, express or implied, by estoppel or otherwise, to any | |
33 | * intellectual property rights is granted herein. | |
34 | */ | |
35 | ||
36 | /* contains code to download uos on MIC card */ | |
37 | ||
38 | #include "mic_common.h" | |
39 | #include <mic/ringbuffer.h> | |
40 | #include "micint.h" | |
41 | #include <linux/virtio_ring.h> | |
42 | #include <linux/virtio_blk.h> | |
43 | #include "mic/mic_virtio.h" | |
44 | #include <linux/proc_fs.h> | |
45 | #include "mic/micveth.h" | |
46 | ||
47 | ||
48 | #define APERTURE_SEGMENT_SIZE ((1) * 1024 * 1024 * 1024ULL) | |
49 | ||
50 | #define UOS_RESERVE_SIZE_MIN ((128) * 1024 * 1024) | |
51 | #define OS_RESERVE_SIZE_MIN ((32) * 1024 * 1024) | |
52 | #define UOS_RESERVE_SIZE_MAX (((4) * 1024 * 1024 * 1024ULL) - ((4) * 1024)) | |
53 | #define UOS_RESERVE_PERCENT 50 | |
54 | ||
55 | #define UOS_WATCHDOG_TIMEOUT 5000 // default watchdog timeout in milliseconds | |
56 | ||
57 | #define PCIE_CLASS_CODE(x) ((x) >> 24 ) | |
58 | ||
59 | /* zombie class code as per the HAS is 0xFF | |
60 | * but on KNC, we found it as 0x03 | |
61 | */ | |
62 | #define ZOMBIE_CLASS_CODE 0x03 | |
63 | #define DISABLE_BAR 0x02 | |
64 | #define RESET_FAILED_F2 12870 | |
65 | #define RESET_FAILED_F4 13382 | |
66 | ||
67 | void ramoops_remove(mic_ctx_t *mic_ctx); | |
68 | ||
69 | static struct proc_dir_entry *ramoops_dir; | |
70 | struct proc_dir_entry *vmcore_dir; | |
71 | ||
72 | ||
73 | static void adapter_dpc(unsigned long dpc); | |
74 | extern int mic_vhost_blk_probe(bd_info_t *bd_info); | |
75 | extern void mic_vhost_blk_remove(bd_info_t *bd_info); | |
76 | ||
77 | /* driver wide global common data */ | |
78 | mic_data_t mic_data; | |
79 | extern int usagemode_param; | |
80 | extern bool mic_crash_dump_enabled; | |
81 | extern bool mic_watchdog_auto_reboot; | |
82 | ||
83 | static int64_t etc_comp = 0; | |
84 | ||
85 | static uint64_t | |
86 | etc_read(uint8_t *mmio_va) | |
87 | { | |
88 | uint32_t low; | |
89 | uint32_t hi1,hi2; | |
90 | ||
91 | do { | |
92 | hi1 = SBOX_READ(mmio_va, SBOX_ELAPSED_TIME_HIGH); | |
93 | low = SBOX_READ(mmio_va, SBOX_ELAPSED_TIME_LOW); | |
94 | hi2 = SBOX_READ(mmio_va, SBOX_ELAPSED_TIME_HIGH); | |
95 | } while(hi1 != hi2); | |
96 | ||
97 | return((uint64_t)((((uint64_t)hi1 << 32) | low) >> 5)); | |
98 | } | |
99 | ||
100 | static int64_t | |
101 | calc_deltaf(mic_ctx_t *mic_ctx) | |
102 | { | |
103 | const int64_t ETC_CLK_FREQ = 15625000; | |
104 | const uint32_t TIME_DELAY_IN_SEC = 10; | |
105 | const int64_t etc_cnt1 = ETC_CLK_FREQ * TIME_DELAY_IN_SEC; | |
106 | int64_t etc_cnt2; | |
107 | ||
108 | uint64_t cnt1, cnt2; | |
109 | int64_t deltaf_in_ppm, deltaf; | |
110 | ||
111 | /* | |
112 | * (etc_freq2 / etc_freq1) = (etc_count2 / etc_count1) | |
113 | * etc_freq1 = ETC_CLK_FREQ | |
114 | * => etc_count1 = TIME_DELAY_IN_SEC * ETC_CLK_FREQ | |
115 | * (etc_freq2 / etc_freq1) = (etc_count2 / etc_count1) | |
116 | * etc_freq2 = etc_freq1 * (etc_count2 / etc_count1) | |
117 | * etc_freq2 - etc_freq1 = etc_freq1((etc_count2 / etc_count1) - 1) | |
118 | * deltaf = etc_freq1(etc_count2 - etc_count1)/etc_count1 | |
119 | * deltaf_in_ppm = deltaf * 10 ^ 6 / etc_freq1 | |
120 | * deltaf_in_ppm = ((etc_count2 - etc_count1) * 10 ^ 6) / etc_count1 | |
121 | */ | |
122 | /* Need to implement the monotonic/irqsave logic for windows */ | |
123 | unsigned long flags; | |
124 | struct timespec ts1, ts2; | |
125 | int64_t mono_ns; | |
126 | int i = 0; | |
127 | do { | |
128 | local_irq_save(flags); | |
129 | cnt1 = etc_read(mic_ctx->mmio.va); | |
130 | getrawmonotonic(&ts1); | |
131 | local_irq_restore(flags); | |
132 | mdelay(TIME_DELAY_IN_SEC * 1000); | |
133 | local_irq_save(flags); | |
134 | cnt2 = etc_read(mic_ctx->mmio.va); | |
135 | getrawmonotonic(&ts2); | |
136 | local_irq_restore(flags); | |
137 | etc_cnt2 = cnt2 - cnt1; | |
138 | ts2 = timespec_sub(ts2, ts1); | |
139 | mono_ns = timespec_to_ns(&ts2); | |
140 | /* Recalculate etc_cnt2 based on getrawmonotonic */ | |
141 | etc_cnt2 = (etc_cnt2 * TIME_DELAY_IN_SEC * 1000 * 1000 * 1000) / mono_ns; | |
142 | deltaf = ( ETC_CLK_FREQ * (etc_cnt2 - etc_cnt1)) / etc_cnt1; | |
143 | deltaf_in_ppm = (1000 * 1000 * (etc_cnt2 - etc_cnt1)) / etc_cnt1; | |
144 | i++; | |
145 | /* | |
146 | * HSD #4844900 | |
147 | * On some of the systems deltaf_in_ppm is turning out | |
148 | * way higher than expected. The only reasons I can think of | |
149 | * are: | |
150 | * i) mmio traffic cauing variable delays for mmio read | |
151 | * ii) NMIs affecting this code | |
152 | */ | |
153 | } while (i < 10 && (deltaf_in_ppm > 2700 || deltaf_in_ppm < -2700)); | |
154 | ||
155 | pr_debug("etc deltaf: %lld\n", deltaf); | |
156 | /* | |
157 | * For intel chipsets, Spread Spectrum Clocking (SSC) (in the limit) | |
158 | * is downspread with a frequency of 30hz and an amplitude of 0.5% | |
159 | * which translates to 2500ppm. This is also the ppm observed on KNC + CrownPass | |
160 | * Hence, if ppm > 2500, the code would need to retry to eliminate any chance of error | |
161 | * Added an error margin of 1ppm (etc mmio reads can take really long time) | |
162 | */ | |
163 | if (deltaf_in_ppm > 2700 || deltaf_in_ppm < -2700) { | |
164 | printk(KERN_ERR "ETC timer compensation(%lldppm) is much higher" | |
165 | "than expected\n", deltaf_in_ppm); | |
166 | /* | |
167 | * HSD #4844900 | |
168 | * Clamp etc compensation to 2500ppm | |
169 | */ | |
170 | if (deltaf_in_ppm > 2700) | |
171 | deltaf_in_ppm = 2500; | |
172 | else | |
173 | deltaf_in_ppm = -2500; | |
174 | deltaf = (ETC_CLK_FREQ * deltaf_in_ppm) / (1000 * 1000); | |
175 | } | |
176 | if (deltaf > 0 && deltaf <= 10) | |
177 | deltaf = 0; | |
178 | return deltaf; | |
179 | } | |
180 | ||
181 | void | |
182 | calculate_etc_compensation(mic_ctx_t *mic_ctx) | |
183 | { | |
184 | if (mic_ctx->bi_family == FAMILY_KNC) { | |
185 | if (!etc_comp) | |
186 | etc_comp = calc_deltaf(mic_ctx); | |
187 | mic_ctx->etc_comp = etc_comp; | |
188 | } | |
189 | } | |
190 | ||
191 | /* | |
192 | DESCRIPTION:: waits for bootstrap loader is finished | |
193 | PARAMETERS:: | |
194 | [in]void *mmio_va - virtual address to access MMIO registers | |
195 | RETURN_VALUE:: 0 if successful, non-zero if failure | |
196 | */ | |
197 | int | |
198 | wait_for_bootstrap(uint8_t *mmio_va) | |
199 | { | |
200 | uint32_t scratch2 = 0; | |
201 | int count = 0; | |
202 | #ifdef MIC_IS_EMULATION | |
203 | int wait_time = 0; | |
204 | #endif | |
205 | ||
206 | // Wait until the boot loader is finished | |
207 | while (!SCRATCH2_DOWNLOAD_STATUS(scratch2)) { | |
208 | msleep(100); | |
209 | if (count == 600) { | |
210 | #ifndef MIC_IS_EMULATION | |
211 | printk("Firmware is not responding with ready bit\n"); | |
212 | return -EIO; | |
213 | #else | |
214 | /* We don't want to be polling too often on the emulator, it is SLOW! */ | |
215 | pr_debug("Wait for bootstrap: %d min(s) \n", wait_time++); | |
216 | count = 0; | |
217 | #endif | |
218 | } | |
219 | ||
220 | count++; | |
221 | scratch2 = SBOX_READ(mmio_va, SBOX_SCRATCH2); | |
222 | } | |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
227 | /* | |
228 | DESCRIPTION::gets adapter memory size. calculates size based on scratch register 0 | |
229 | PARAMETERS:: | |
230 | [in]void *mmio_va - virtual address to access MMIO registers | |
231 | [out]uint32_t *adapter_mem_size - adapter memory size | |
232 | RETURN_VALUE:: none | |
233 | */ | |
234 | void | |
235 | get_adapter_memsize(uint8_t *mmio_va, uint32_t *adapter_mem_size) | |
236 | { | |
237 | uint32_t memsize = 0; | |
238 | uint32_t scratch0 = {0}; | |
239 | ||
240 | scratch0 = SBOX_READ(mmio_va, SBOX_SCRATCH0); | |
241 | memsize = SCRATCH0_MEM_SIZE_KB(scratch0) * ((1) * 1024); | |
242 | ||
243 | // Adjust the memory size based on the memory usage | |
244 | switch (SCRATCH0_MEM_USAGE(scratch0)) { | |
245 | case SCR0_MEM_ALL: | |
246 | // Do nothing | |
247 | break; | |
248 | ||
249 | case SCR0_MEM_HALF: | |
250 | memsize /= 2; | |
251 | break; | |
252 | ||
253 | case SCR0_MEM_THIRD: | |
254 | memsize /= 3; | |
255 | break; | |
256 | ||
257 | case SCR0_MEM_FOURTH: | |
258 | memsize /= 4; | |
259 | break; | |
260 | ||
261 | default: | |
262 | // DBG_ASSERT_MSG(false, "Invalid memory usage specified by the bootstrap.\n"); | |
263 | break; | |
264 | } | |
265 | ||
266 | *adapter_mem_size = memsize; | |
267 | } | |
268 | ||
269 | /* | |
270 | DESCRIPTION:: gets uos load offset from scratch register 2 | |
271 | PARAMETERS:: | |
272 | [in]void *mmio_va - virtual address to access MMIO registers | |
273 | [out]uint32_t *uos_load_offset - offset at which uos will be loaded | |
274 | RETURN_VALUE:: none | |
275 | */ | |
276 | void | |
277 | get_uos_loadoffset(uint8_t *mmio_va, uint32_t *uos_load_offset) | |
278 | { | |
279 | uint32_t scratch2 = 0; | |
280 | ||
281 | scratch2 = SBOX_READ(mmio_va, SBOX_SCRATCH2); | |
282 | *uos_load_offset = SCRATCH2_DOWNLOAD_ADDR(scratch2); | |
283 | } | |
284 | ||
285 | /* | |
286 | DESCRIPTION:: gets reserved size for uos | |
287 | PARAMETERS:: | |
288 | [out]uint32_t *uos_reserve_size - reserved uos size | |
289 | RETURN_VALUE:: none | |
290 | */ | |
291 | void | |
292 | get_uos_reserved_size(uint8_t* mmio_va, uint32_t adapter_memsize, uint32_t *uos_reserve_size) | |
293 | { | |
294 | uint32_t reserve_size = 0; | |
295 | ||
296 | // Only calculate if not explicitly specified by the user | |
297 | reserve_size = (uint32_t)(adapter_memsize * UOS_RESERVE_PERCENT / 100); | |
298 | ||
299 | // Make sure there is at least WINDOWS_RESERVE_SIZE_MIN bytes | |
300 | reserve_size = GET_MIN(reserve_size, adapter_memsize - OS_RESERVE_SIZE_MIN); | |
301 | ||
302 | // Keep in mind maximum uos reserve size is uint32_t, so we never overflow | |
303 | reserve_size = GET_MIN(reserve_size, UOS_RESERVE_SIZE_MAX); | |
304 | reserve_size = GET_MAX(reserve_size, UOS_RESERVE_SIZE_MIN); | |
305 | ||
306 | // Always align uos reserve size to a page | |
307 | reserve_size = (uint32_t)AlignLow(reserve_size, ((4) * 1024)); | |
308 | ||
309 | *uos_reserve_size = reserve_size; | |
310 | } | |
311 | ||
312 | /* | |
313 | DESCRIPTION:: gets APIC ID from scratch register 2 | |
314 | PARAMETERS:: | |
315 | [in]void *mmio_va - virtual address to access MMIO registers | |
316 | [out]uint32_t *apic_id - apic id | |
317 | RETURN_VALUE:: none | |
318 | */ | |
319 | void | |
320 | get_apic_id(uint8_t *mmio_va, uint32_t *apic_id) | |
321 | { | |
322 | uint32_t scratch2 = 0; | |
323 | ||
324 | scratch2 = SBOX_READ(mmio_va, SBOX_SCRATCH2); | |
325 | *apic_id = SCRATCH2_APIC_ID(scratch2); | |
326 | } | |
327 | ||
328 | /* | |
329 | DESCRIPTION::program the PCI aperture as a contiguous window. (only supports upto 4GB memory) | |
330 | PARAMETERS:: | |
331 | [in]mic_ctx_t *mic_ctx - mic ctx | |
332 | [in]int gtt_index - beginning gtt entry index | |
333 | [in]uint64_t phy_addr - physical address for PCI aperture | |
334 | [in]uint32_t num_bytes - size of PCI aperture | |
335 | RETURN_VALUE:: None | |
336 | */ | |
337 | void | |
338 | set_pci_aperture(mic_ctx_t *mic_ctx, uint32_t gtt_index, uint64_t phy_addr, uint32_t num_bytes) | |
339 | { | |
340 | uint32_t num_pages; | |
341 | uint32_t gtt_entry; | |
342 | uint32_t i; | |
343 | ||
344 | num_pages = ALIGN(num_bytes, PAGE_SIZE) >> PAGE_SHIFT; | |
345 | ||
346 | for (i = 0; i < num_pages; i++) { | |
347 | ||
348 | gtt_entry = ((uint32_t)(phy_addr >> PAGE_SHIFT) + i) << 1 | 0x1u; | |
349 | GTT_WRITE(gtt_entry, mic_ctx->mmio.va, (gtt_index + i)*sizeof(gtt_entry)); | |
350 | } | |
351 | ||
352 | // XPU_RACE_CONDITION: | |
353 | // Writing GttTlbFlushReg DOES NOT flush all write transactions from SBOX to GDDR | |
354 | // because GttTlbFlushReg is an SBOX register and transaction terminates in SBOX | |
355 | // MMIO write must use MIC ringbus to be serializing. | |
356 | // Writing GTT itself DOES serialize: GTT is in MMIO space, and write goes to the ringbus | |
357 | // MemoryBarrier makes sure all writes make it to GDDR before tlbFlush write | |
358 | smp_mb(); // FIXME: only needs SFENCE | |
359 | ||
360 | // write any value to cause a flush | |
361 | SBOX_WRITE(1, mic_ctx->mmio.va, SBOX_TLB_FLUSH); | |
362 | } | |
363 | ||
364 | /* | |
365 | DESCRIPTION:: Programs a scratch register that the bootstrap reads to determine | |
366 | how large is uOS image. | |
367 | PARAMETERS:: | |
368 | [in]void *mmio_va - virtual address to mmio register, | |
369 | [in]uint32_t uos_size - size of uos image | |
370 | RETURN_VALUE:: none | |
371 | */ | |
372 | void | |
373 | set_uos_size(uint8_t *mmio_va, uint32_t uos_size) | |
374 | { | |
375 | uint32_t scratch5; | |
376 | ||
377 | scratch5 = uos_size; | |
378 | // XPU_RACE_CONDITION: write to MMIO space is uncached and flushes WC buffers | |
379 | SBOX_WRITE(scratch5, mmio_va, SBOX_SCRATCH5); | |
380 | } | |
381 | ||
382 | /* | |
383 | DESCRIPTION:: Programs a scratch register that the uOS reads to determine how | |
384 | much memory to reserve. | |
385 | PARAMETERS:: | |
386 | [in]void *mmio_va - virtual address to mmio register, | |
387 | [in]uint32_t uos_reserved_size - size of memory to be reserved by uos. | |
388 | RETURN_VALUE:: none | |
389 | */ | |
390 | void | |
391 | set_uos_reserved_size(uint8_t *mmio_va, uint32_t uos_reserved_size) | |
392 | { | |
393 | uint32_t scratch3; | |
394 | ||
395 | scratch3 = uos_reserved_size; | |
396 | // XPU_RACE_CONDITION: write to MMIO space is uncached and flushes WC buffers | |
397 | SBOX_WRITE(scratch3, mmio_va, SBOX_SCRATCH3); | |
398 | } | |
399 | ||
400 | /* | |
401 | DESCRIPTION:: . | |
402 | PARAMETERS:: | |
403 | [in]uint32_t device_id - device ID, | |
404 | RETURN_VALUE:: family type | |
405 | */ | |
406 | product_family_t | |
407 | get_product_family(uint32_t device_id) | |
408 | { | |
409 | product_family_t product_family; | |
410 | ||
411 | switch (device_id) { | |
412 | case PCI_DEVICE_ABR_2249: | |
413 | case PCI_DEVICE_ABR_224a: | |
414 | product_family = FAMILY_ABR; | |
415 | break; | |
416 | ||
417 | case PCI_DEVICE_KNC_2250: | |
418 | case PCI_DEVICE_KNC_2251: | |
419 | case PCI_DEVICE_KNC_2252: | |
420 | case PCI_DEVICE_KNC_2253: | |
421 | case PCI_DEVICE_KNC_2254: | |
422 | case PCI_DEVICE_KNC_2255: | |
423 | case PCI_DEVICE_KNC_2256: | |
424 | case PCI_DEVICE_KNC_2257: | |
425 | case PCI_DEVICE_KNC_2258: | |
426 | case PCI_DEVICE_KNC_2259: | |
427 | case PCI_DEVICE_KNC_225a: | |
428 | case PCI_DEVICE_KNC_225b: | |
429 | case PCI_DEVICE_KNC_225c: | |
430 | case PCI_DEVICE_KNC_225d: | |
431 | case PCI_DEVICE_KNC_225e: | |
432 | product_family = FAMILY_KNC; | |
433 | break; | |
434 | ||
435 | default: | |
436 | pr_debug( "Invalid/Unknown device ID %d\r\n", device_id); | |
437 | product_family = FAMILY_UNKNOWN; | |
438 | break; | |
439 | } | |
440 | ||
441 | return product_family; | |
442 | } | |
443 | ||
444 | /* | |
445 | DESCRIPTION:: loads uos image at given path into gddr | |
446 | PARAMETERS:: | |
447 | [in]mic_ctx_t *mic_ctx - mic context | |
448 | [in]imgname - file path for uos file to be loaded | |
449 | [out]uos_size - size of uos image | |
450 | */ | |
451 | int | |
452 | load_uos_into_gddr(mic_ctx_t *mic_ctx, char *imgname, uint32_t* uos_size, uint64_t *uos_cmd_offset) | |
453 | { | |
454 | void *aperture_va; | |
455 | uint8_t *mmio_va; | |
456 | uint32_t apic_id = 0; | |
457 | uint32_t uos_load_offset = 0; | |
458 | uint32_t adapter_memsize = 0; | |
459 | int status = 0; | |
460 | ||
461 | aperture_va = mic_ctx->aper.va; | |
462 | mmio_va = mic_ctx->mmio.va; | |
463 | ||
464 | if (mic_ctx->state != MIC_BOOT) { | |
465 | printk("Not in booting state\n"); | |
466 | return -EPERM; | |
467 | } | |
468 | ||
469 | status = mic_get_file_size(imgname, uos_size); | |
470 | ||
471 | if (status) { | |
472 | mic_ctx->state = MIC_BOOTFAIL; | |
473 | printk("Linux image not found at %s , status returned %d\n", imgname, status); | |
474 | return status; | |
475 | } | |
476 | ||
477 | get_uos_loadoffset(mmio_va, &uos_load_offset); | |
478 | // Determine the uOS reserve size after we have the m_pXpu interface | |
479 | get_adapter_memsize(mmio_va, &adapter_memsize); | |
480 | ||
481 | get_apic_id(mmio_va, &apic_id); | |
482 | // store apic_id in adapter context for later use | |
483 | mic_ctx->apic_id = apic_id; | |
484 | ||
485 | if (mic_ctx->bi_family == FAMILY_ABR){ | |
486 | // Program the PCI aperture as a contiguous window | |
487 | // Need an extra page to provide enough buffer space for command line arguments. | |
488 | set_pci_aperture(mic_ctx, 0, uos_load_offset, *uos_size + PAGE_SIZE); | |
489 | uos_load_offset = 0; | |
490 | } | |
491 | ||
492 | // transfer uOs image file to gddr | |
493 | status = mic_load_file(imgname, ((uint8_t*)aperture_va) + uos_load_offset, *uos_size); | |
494 | ||
495 | // for the emulator we want to skip "downloading" the file | |
496 | *uos_cmd_offset = (uint64_t)uos_load_offset + *uos_size; | |
497 | ||
498 | // This only applies to KNF bootstrap, it is NOT needed for KNC | |
499 | if (mic_ctx->bi_family == FAMILY_ABR) { | |
500 | // clear UOS load offset register after uOS was uploaded | |
501 | SBOX_WRITE(0, mmio_va, SBOX_SCRATCH2); | |
502 | SBOX_READ(mmio_va, SBOX_SCRATCH2); | |
503 | } | |
504 | ||
505 | return status; | |
506 | } | |
507 | ||
508 | /* | |
509 | DESCRIPTION:: loads uos initramfs image at given path into gddr for KNC. | |
510 | PARAMETERS:: | |
511 | [in]mic_ctx_t *mic_ctx - mic context | |
512 | [in]initramfsname - file path for uos initramfs file to be loaded | |
513 | */ | |
514 | int | |
515 | load_initramfs(mic_ctx_t *mic_ctx, char *initramfsname, uint32_t *initramfs_image, uint32_t *initramfs_size) | |
516 | { | |
517 | uint8_t *aperture_va; | |
518 | uint8_t *mmio_va; | |
519 | uint32_t apic_id = 0; | |
520 | uint32_t uos_load_offset = 0; | |
521 | uint32_t file_load_offset = 0; | |
522 | uint32_t adapter_memsize = 0; | |
523 | uint32_t file_size = 0; | |
524 | int status = 0; | |
525 | uint32_t *ramfs_addr_ptr; | |
526 | ||
527 | aperture_va = mic_ctx->aper.va; | |
528 | mmio_va = mic_ctx->mmio.va; | |
529 | ||
530 | if (mic_ctx->state != MIC_BOOT) { | |
531 | printk("Not in booting state\n"); | |
532 | return -EPERM; | |
533 | } | |
534 | ||
535 | status = mic_get_file_size(initramfsname, &file_size); | |
536 | ||
537 | if (status) { | |
538 | mic_ctx->state = MIC_BOOTFAIL; | |
539 | printk("Init ram disk image not found at %s , status returned %d\n", initramfsname, status); | |
540 | return status; | |
541 | } | |
542 | ||
543 | get_uos_loadoffset(mmio_va, &uos_load_offset); | |
544 | file_load_offset = uos_load_offset << 1; /* Place initramfs higher than kernel; 128MB is ok */ | |
545 | ||
546 | *initramfs_size = file_size; | |
547 | *initramfs_image = file_load_offset; | |
548 | ||
549 | // Determine the uOS reserve size after we have the m_pXpu interface | |
550 | get_adapter_memsize(mmio_va, &adapter_memsize); | |
551 | get_apic_id(mmio_va, &apic_id); | |
552 | ||
553 | // store apic_id in adapter context for later use | |
554 | mic_ctx->apic_id = apic_id; | |
555 | ||
556 | // transfer uOs image file to gddr | |
557 | status = mic_load_file(initramfsname, aperture_va + file_load_offset, file_size); | |
558 | ||
559 | // write the initramfs load address and size to the fields in the kernel header | |
560 | ramfs_addr_ptr = (uint32_t *)(aperture_va + uos_load_offset + 0x218); | |
561 | *ramfs_addr_ptr = file_load_offset; | |
562 | ramfs_addr_ptr = (uint32_t *)(aperture_va + uos_load_offset + 0x21c); | |
563 | *ramfs_addr_ptr = *initramfs_size; | |
564 | ||
565 | return status; | |
566 | } | |
567 | ||
568 | struct tmpqp { | |
569 | uint64_t ep; | |
570 | uint64_t magic; | |
571 | }; | |
572 | ||
573 | int | |
574 | load_command_line(mic_ctx_t *mic_ctx, uint64_t uos_cmd_offset) | |
575 | { | |
576 | void *cmd_line_va = mic_ctx->aper.va + uos_cmd_offset; | |
577 | uint32_t cmdlen = 0; | |
578 | char *buf = NULL; | |
579 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) || defined(RHEL_RELEASE_CODE) | |
580 | struct board_info *bi = mic_ctx->bd_info; | |
581 | #endif | |
582 | ||
583 | #ifdef USE_VCONSOLE | |
584 | micvcons_t *vcons = &mic_ctx->bi_vcons; | |
585 | dma_addr_t vc_hdr_dma_addr = 0; | |
586 | #endif | |
587 | ||
588 | /* | |
589 | * mic_ctx->boot_mem will also be set in IOCTL to boot the card in restricted memory | |
590 | * FIXME::This code is added to keep the backward compatibility with IOCTLs | |
591 | */ | |
592 | if (mic_ctx->bi_family == FAMILY_KNC) | |
593 | if (mic_ctx->boot_mem == 0 || mic_ctx->boot_mem > mic_ctx->aper.len >> 20) | |
594 | mic_ctx->boot_mem = (uint32_t)(mic_ctx->aper.len >> 20); | |
595 | if (!(buf = kzalloc(MIC_CMDLINE_BUFSIZE, GFP_KERNEL))) { | |
596 | printk(KERN_ERR "failed to allocate %d bytes for uOS command line\n", | |
597 | MIC_CMDLINE_BUFSIZE); | |
598 | return -ENOMEM; | |
599 | } | |
600 | ||
601 | cmdlen = snprintf(buf, MIC_CMDLINE_BUFSIZE, "card=%d vnet=%s scif_id=%d scif_addr=0x%llx", | |
602 | mic_ctx->bi_id, mic_vnet_modes[mic_vnet_mode], | |
603 | mic_ctx->bi_id + 1, mic_ctx->bi_scif.si_pa); | |
604 | ||
605 | if (mic_vnet_mode == VNET_MODE_DMA) { | |
606 | struct micvnet_info *vnet_info = mic_ctx->bi_vethinfo; | |
607 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
608 | " vnet_addr=0x%llx", vnet_info->vi_rp_phys); | |
609 | } | |
610 | ||
611 | #ifdef USE_VCONSOLE | |
612 | if (vcons->dc_enabled) | |
613 | vc_hdr_dma_addr = vcons->dc_hdr_dma_addr; | |
614 | ||
615 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
616 | " vcons_hdr_addr=0x%llx", vc_hdr_dma_addr); | |
617 | #endif | |
618 | ||
619 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) || defined(RHEL_RELEASE_CODE) | |
620 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, " virtio_addr=0x%llx", | |
621 | mic_ctx_map_single(mic_ctx, bi->bi_virtio, sizeof(struct vb_shared))); | |
622 | #endif | |
623 | ||
624 | if (mic_ctx->boot_mem) | |
625 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
626 | " mem=%dM", mic_ctx->boot_mem); | |
627 | mic_ctx->boot_mem = 0; | |
628 | ||
629 | if (mic_ctx->ramoops_size) | |
630 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
631 | " ramoops_size=%d ramoops_addr=0x%llx", | |
632 | mic_ctx->ramoops_size, mic_ctx->ramoops_pa[0]); | |
633 | ||
634 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
635 | " p2p=%d p2p_proxy=%d", mic_p2p_enable, mic_p2p_proxy_enable); | |
636 | ||
637 | if (mic_ctx->bi_family == FAMILY_KNC) | |
638 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
639 | " etc_comp=%lld", mic_ctx->etc_comp); | |
640 | ||
641 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
642 | " reg_cache=%d", mic_reg_cache_enable); | |
643 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
644 | " ulimit=%d", mic_ulimit_check); | |
645 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
646 | " huge_page=%d", mic_huge_page_enable); | |
647 | if (mic_crash_dump_enabled) | |
648 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
649 | " crashkernel=1M@80M"); | |
650 | /* | |
651 | * Limitations in the Intel Jaketown and Ivytown platforms require SCIF | |
652 | * to proxy P2P DMA read transfers in order to convert them into a P2P DMA | |
653 | * write for better performance. The SCIF module on MIC needs the | |
654 | * numa node the MIC is connected to on the host to make decisions | |
655 | * about whether to proxy P2P DMA reads or not based on whether the two MIC | |
656 | * devices are connected to the same QPI/socket/numa node or not. | |
657 | * The assumption here is that a socket/QPI will have a unique | |
658 | * numa node number. | |
659 | */ | |
660 | pr_debug("CPU family = %d, CPU model = %d\n", boot_cpu_data.x86, boot_cpu_data.x86_model); | |
661 | ||
662 | if (mic_p2p_proxy_enable && (boot_cpu_data.x86==6) && | |
663 | (boot_cpu_data.x86_model == 45 || boot_cpu_data.x86_model == 62)) { | |
664 | int numa_node = dev_to_node(&mic_ctx->bi_pdev->dev); | |
665 | if (-1 != numa_node) { | |
666 | if (boot_cpu_data.x86_model == 45) | |
667 | ms_info.mi_proxy_dma_threshold = SCIF_PROXY_DMA_THRESHOLD_JKT; | |
668 | if (boot_cpu_data.x86_model == 62) | |
669 | ms_info.mi_proxy_dma_threshold = SCIF_PROXY_DMA_THRESHOLD_IVT; | |
670 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
671 | " numa_node=%d", numa_node); | |
672 | cmdlen += snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
673 | " p2p_proxy_thresh=%lld", ms_info.mi_proxy_dma_threshold); | |
674 | } | |
675 | } | |
676 | ||
677 | if (mic_ctx->sysfs_info.cmdline != NULL) | |
678 | snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
679 | " %s", mic_ctx->sysfs_info.cmdline); | |
680 | else | |
681 | snprintf(buf + cmdlen, MIC_CMDLINE_BUFSIZE - cmdlen, | |
682 | " hostname=mic%d ipaddr=171.31.%d.2 quiet console=ttyS0,115200n8", | |
683 | mic_ctx->bi_id, mic_ctx->bi_id + 1); | |
684 | ||
685 | memcpy_toio(cmd_line_va, buf, strlen(buf) + 1); | |
686 | ||
687 | if (mic_ctx->sysfs_info.kernel_cmdline != NULL) | |
688 | kfree(mic_ctx->sysfs_info.kernel_cmdline); | |
689 | ||
690 | if ((mic_ctx->sysfs_info.kernel_cmdline = kmalloc(strlen(buf) + 1, GFP_KERNEL)) != NULL) | |
691 | strcpy(mic_ctx->sysfs_info.kernel_cmdline, buf); | |
692 | ||
693 | kfree(buf); | |
694 | return 0; | |
695 | } | |
696 | ||
697 | /* | |
698 | DESCRIPTION:: method responsible for programming scratch register with uos image size | |
699 | and notifying bootstrap to start booting uos | |
700 | PARAMETERS:: | |
701 | [in]mic_ctx_t *mic_ctx - mic context | |
702 | [in]uint32_t uos_size - size of uos image | |
703 | */ | |
704 | int | |
705 | notify_uosboot(mic_ctx_t *mic_ctx, uint32_t uos_size) | |
706 | { | |
707 | int status = 0; | |
708 | uint32_t adapter_memsize = 0; | |
709 | uint32_t uos_reserved_size = 0; | |
710 | uint8_t* mmio_va = mic_ctx->mmio.va; | |
711 | ||
712 | // Program the register with uOS image size for bootstrap | |
713 | set_uos_size(mmio_va, uos_size); | |
714 | ||
715 | get_adapter_memsize(mmio_va, &adapter_memsize); | |
716 | ||
717 | // Program the register to inform the uOS of how much space to reserve | |
718 | get_uos_reserved_size(mmio_va, adapter_memsize, &uos_reserved_size); | |
719 | set_uos_reserved_size(mmio_va, uos_reserved_size); | |
720 | ||
721 | mic_send_bootstrap_intr(mic_ctx); | |
722 | ||
723 | return status; | |
724 | } | |
725 | ||
726 | /* | |
727 | DESCRIPTION :: boots Linux OS on the card | |
728 | PARAMETERS :: | |
729 | [in]mic_ctx_t *mic_ctx - mic context | |
730 | [in]char *imgname - file path for uos image to be loaded on the card | |
731 | RETURN_VALUE:: 0 if successful, non-zero if failure | |
732 | */ | |
733 | int | |
734 | boot_linux_uos(mic_ctx_t *mic_ctx, char *imgname, char *initramfsname) | |
735 | { | |
736 | int status = 0; | |
737 | uint32_t uos_size = 0; | |
738 | uint64_t uos_cmd_offset = 0; | |
739 | uint32_t initramfs_image = 0; | |
740 | uint32_t initramfs_size = 0; | |
741 | ||
742 | printk("MIC %d Booting\n", mic_ctx->bi_id); | |
743 | ||
744 | if (mic_ctx->state != MIC_BOOT) { | |
745 | printk(KERN_ERR "MIC %d is not in offline mode\n", mic_ctx->bi_id); | |
746 | return -EPERM; | |
747 | } | |
748 | ||
749 | //loads uos image at given path into gddr | |
750 | if ((status = load_uos_into_gddr(mic_ctx, imgname, &uos_size, &uos_cmd_offset)) != 0) { | |
751 | printk("Cannot load uos in gddr\n"); | |
752 | return status; | |
753 | } | |
754 | ||
755 | if (initramfsname && (status = load_initramfs(mic_ctx, initramfsname, &initramfs_image, &initramfs_size)) != 0) { | |
756 | printk("Cannot load initramfs in gddr\n"); | |
757 | return status; | |
758 | } | |
759 | ||
760 | status = load_command_line(mic_ctx, uos_cmd_offset); | |
761 | ||
762 | //program scratch register with uos image size and notify bootstrap | |
763 | status = notify_uosboot(mic_ctx, uos_size); | |
764 | ||
765 | return status; | |
766 | } | |
767 | ||
768 | /* | |
769 | DESCRIPTION :: boots Maintenance mode handler on the card | |
770 | PARAMETERS :: | |
771 | [in]mic_ctx_t *mic_ctx - mic context | |
772 | [in]char *imgname - file path for uos image to be loaded on the card | |
773 | RETURN_VALUE:: 0 if successful, non-zero if failure | |
774 | */ | |
775 | int boot_micdev_app(mic_ctx_t *mic_ctx, char *imgname) | |
776 | { | |
777 | int status = 0; | |
778 | uint32_t uos_size = 0; | |
779 | uint8_t *mmio_va = 0; | |
780 | uint64_t uos_cmd_offset = 0; | |
781 | int32_t temp_scratch2 = 0; | |
782 | ||
783 | printk("MIC %d Booting\n", mic_ctx->bi_id); | |
784 | mmio_va = mic_ctx->mmio.va; | |
785 | status = load_uos_into_gddr(mic_ctx, imgname, &uos_size, &uos_cmd_offset); | |
786 | if(status) { | |
787 | printk("Cannot load uos in gddr\n"); | |
788 | goto exit; | |
789 | } | |
790 | ||
791 | temp_scratch2 = SBOX_READ(mmio_va, SBOX_SCRATCH2); | |
792 | /* clear download bit */ | |
793 | temp_scratch2 = SCRATCH2_CLEAR_DOWNLOAD_STATUS(temp_scratch2); | |
794 | SBOX_WRITE(temp_scratch2, mmio_va, SBOX_SCRATCH2); | |
795 | ||
796 | //program scratch register with uos image size and notify bootstrap | |
797 | status = notify_uosboot(mic_ctx, uos_size); | |
798 | if(status) | |
799 | goto exit; | |
800 | status = wait_for_bootstrap(mmio_va); | |
801 | exit: | |
802 | if(status) { | |
803 | mic_setstate(mic_ctx, MIC_BOOTFAIL); | |
804 | } else { | |
805 | mic_setstate(mic_ctx, MIC_ONLINE); | |
806 | mic_ctx->boot_count++; | |
807 | printk("ELF booted succesfully\n"); | |
808 | ; | |
809 | } | |
810 | return status; | |
811 | } | |
812 | ||
813 | /* Perform hardware reset of the device */ | |
814 | void | |
cd1ed09a | 815 | reset_timer(struct timer_list *arg) |
800f879a | 816 | { |
cd1ed09a | 817 | mic_ctx_t *mic_ctx = from_timer(mic_ctx, arg, boot_timer); |
800f879a AT |
818 | uint32_t scratch2 = 0; |
819 | uint32_t postcode = mic_getpostcode(mic_ctx); | |
820 | ||
821 | printk("mic%d: Resetting (Post Code %c%c)\n", mic_ctx->bi_id, | |
822 | postcode & 0xff, (postcode >> 8) & 0xff); | |
823 | mic_ctx->reset_count++; | |
824 | ||
825 | /* Assuming that the bootstrap takes around 90 seconds to reset, | |
826 | * we fail after 300 seconds, thus allowing 3 attempts to reset | |
827 | */ | |
828 | if (mic_ctx->reset_count == RESET_FAIL_TIME || | |
829 | !postcode || 0xffffffff == postcode || mic_ctx->state == MIC_RESETFAIL) { | |
830 | mic_ctx->reset_count = 0; | |
831 | mic_setstate(mic_ctx, MIC_RESETFAIL); | |
832 | wake_up(&mic_ctx->resetwq); | |
833 | printk("MIC %d RESETFAIL postcode %c%c %d\n", mic_ctx->bi_id, | |
834 | postcode & 0xff, (postcode >> 8) & 0xff, postcode); | |
835 | return; | |
836 | } | |
837 | ||
838 | /* check for F2 or F4 error codes from bootstrap */ | |
839 | if ((postcode == RESET_FAILED_F2) || (postcode == RESET_FAILED_F4)) { | |
840 | if (mic_ctx->resetworkq) { | |
841 | queue_work(mic_ctx->resetworkq, &mic_ctx->resetwork); | |
842 | } else { | |
843 | mic_ctx->reset_count = 0; | |
844 | mic_setstate(mic_ctx, MIC_RESETFAIL); | |
845 | wake_up(&mic_ctx->resetwq); | |
846 | return; | |
847 | } | |
848 | } | |
849 | ||
850 | /* checking if bootstrap is ready or still resetting */ | |
851 | scratch2 = SBOX_READ(mic_ctx->mmio.va, SBOX_SCRATCH2); | |
852 | if (SCRATCH2_DOWNLOAD_STATUS(scratch2)) { | |
853 | mic_ctx->boot_start = 0; | |
854 | mic_setstate(mic_ctx, MIC_READY); | |
855 | ||
856 | if (mic_ctx->msie) | |
857 | mic_enable_msi_interrupts(mic_ctx); | |
858 | mic_enable_interrupts(mic_ctx); | |
859 | mic_smpt_restore(mic_ctx); | |
860 | micscif_start(mic_ctx); | |
861 | ||
862 | wake_up(&mic_ctx->resetwq); | |
863 | mic_ctx->reset_count = 0; | |
864 | ||
865 | return; | |
866 | } | |
867 | ||
800f879a | 868 | mic_ctx->boot_timer.expires = jiffies + HZ; |
cd1ed09a | 869 | timer_setup(&mic_ctx->boot_timer, reset_timer, 0); |
800f879a AT |
870 | } |
871 | ||
872 | void | |
873 | adapter_wait_reset(mic_ctx_t *mic_ctx) | |
874 | { | |
800f879a AT |
875 | mic_ctx->boot_timer.expires = jiffies + HZ; |
876 | mic_ctx->boot_start = jiffies; | |
cd1ed09a | 877 | timer_setup(&mic_ctx->boot_timer, reset_timer, 0); |
800f879a AT |
878 | } |
879 | ||
880 | void | |
881 | adapter_reset(mic_ctx_t *mic_ctx, int wait_reset, int reattempt) | |
882 | { | |
883 | uint32_t resetReg; | |
884 | mutex_lock(&mic_ctx->state_lock); | |
885 | /* TODO: check state for lost node as well once design is done */ | |
886 | if ((mic_ctx->state == MIC_RESET || mic_ctx->state == MIC_READY) && (reattempt == 0)) { | |
887 | if (wait_reset == 0) { | |
888 | mic_setstate(mic_ctx, MIC_INVALID); | |
889 | del_timer_sync(&mic_ctx->boot_timer); | |
890 | mutex_unlock(&mic_ctx->state_lock); | |
891 | return; | |
892 | } | |
893 | mutex_unlock(&mic_ctx->state_lock); | |
894 | return; | |
895 | } | |
896 | ||
897 | mic_setstate(mic_ctx, MIC_RESET); | |
898 | ||
899 | mutex_unlock(&mic_ctx->state_lock); | |
900 | ||
901 | del_timer_sync(&mic_ctx->boot_timer); | |
902 | ||
903 | //Write 0 to uos download status otherwise we might continue booting | |
904 | //before reset has completed... | |
905 | SBOX_WRITE(0, mic_ctx->mmio.va, SBOX_SCRATCH2); | |
906 | ||
907 | // Virtual network link value should be 0 before reset | |
908 | SBOX_WRITE(0, mic_ctx->mmio.va, SBOX_SCRATCH14); | |
909 | ||
910 | // Data from Doorbell1 about restart/shutdown should be 0 before reset | |
911 | SBOX_WRITE(0, mic_ctx->mmio.va, SBOX_SDBIC1); | |
912 | ||
913 | //This will trigger reset | |
914 | resetReg = SBOX_READ(mic_ctx->mmio.va, SBOX_RGCR); | |
915 | resetReg |= 0x1; | |
916 | SBOX_WRITE(resetReg, mic_ctx->mmio.va, SBOX_RGCR); | |
917 | ||
918 | /* At least of KNF it seems we really want to delay at least 1 second */ | |
919 | /* after touching reset to prevent a lot of problems. */ | |
920 | msleep(1000); | |
921 | ||
922 | if (!wait_reset) { | |
923 | return; | |
924 | } | |
925 | ||
926 | adapter_wait_reset(mic_ctx); | |
927 | ||
928 | } | |
929 | ||
930 | void ramoops_flip(mic_ctx_t *mic_ctx); | |
931 | ||
932 | int | |
933 | adapter_shutdown_device(mic_ctx_t *mic_ctx) | |
934 | { | |
935 | ; | |
936 | ||
937 | if (micpm_get_reference(mic_ctx, true)) | |
938 | return 0; | |
939 | ||
940 | mutex_lock(&mic_ctx->state_lock); | |
941 | if (mic_ctx->state == MIC_ONLINE) { | |
942 | mic_setstate(mic_ctx, MIC_SHUTDOWN); | |
943 | ||
944 | /* | |
945 | * Writing to SBOX RDMASR0 will generate an interrupt | |
946 | * on the uOS which will initiate orderly shutdown. | |
947 | */ | |
948 | mic_send_sht_intr(mic_ctx); | |
949 | } | |
950 | mutex_unlock(&mic_ctx->state_lock); | |
951 | ||
952 | micpm_put_reference(mic_ctx); | |
953 | return 0; | |
954 | } | |
955 | ||
956 | int | |
957 | adapter_stop_device(mic_ctx_t *mic_ctx, int wait_reset, int reattempt) | |
958 | { | |
959 | ; | |
960 | ||
961 | micvcons_stop(mic_ctx); | |
962 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) || \ | |
963 | defined(RHEL_RELEASE_CODE) | |
964 | mic_vhost_blk_stop(mic_ctx->bd_info); | |
965 | #endif | |
966 | micveth_stop(mic_ctx); | |
967 | ||
968 | micpm_stop(mic_ctx); | |
969 | micscif_stop(mic_ctx); | |
970 | vmcore_remove(mic_ctx); | |
971 | close_dma_device(mic_ctx->bi_id + 1, &mic_ctx->dma_handle); | |
972 | ramoops_flip(mic_ctx); | |
973 | ||
974 | /* Calling adapter_reset after issuing Host shutdown/reboot | |
975 | * leads to randon NMIs. These are not rleated to any Card in | |
976 | * specific but occurs on the PCI bridge. */ | |
977 | if ((system_state == SYSTEM_POWER_OFF) || | |
978 | (system_state == SYSTEM_RESTART) || | |
979 | (system_state == SYSTEM_HALT)) | |
980 | return 0; | |
981 | adapter_reset(mic_ctx, wait_reset, reattempt); | |
982 | ||
983 | return 0; | |
984 | } | |
985 | ||
986 | static void | |
987 | destroy_reset_workqueue(mic_ctx_t *mic_ctx) | |
988 | { | |
989 | struct workqueue_struct *tempworkq; | |
990 | tempworkq = mic_ctx->resetworkq; | |
991 | mic_ctx->resetworkq = NULL; | |
992 | destroy_workqueue(tempworkq); | |
993 | del_timer_sync(&mic_ctx->boot_timer); | |
994 | } | |
995 | ||
996 | int | |
997 | adapter_remove(mic_ctx_t *mic_ctx) | |
998 | { | |
999 | ||
1000 | #ifdef USE_VCONSOLE | |
1001 | if (mic_ctx->bi_vcons.dc_hdr_virt) { | |
1002 | mic_ctx_unmap_single(mic_ctx, mic_ctx->bi_vcons.dc_hdr_dma_addr, | |
1003 | sizeof(struct vcons_buf)); | |
1004 | kfree(mic_ctx->bi_vcons.dc_hdr_virt); | |
1005 | mic_ctx->bi_vcons.dc_hdr_virt = NULL; | |
1006 | } | |
1007 | ||
1008 | if (mic_ctx->bi_vcons.dc_buf_virt) { | |
1009 | mic_ctx_unmap_single(mic_ctx, mic_ctx->bi_vcons.dc_dma_addr, | |
1010 | MICVCONS_BUF_SIZE); | |
1011 | free_pages((uint64_t)mic_ctx->bi_vcons.dc_buf_virt, 0); | |
1012 | mic_ctx->bi_vcons.dc_buf_virt = NULL; | |
1013 | } | |
1014 | #endif | |
1015 | ||
1016 | mic_psmi_uninit(mic_ctx); | |
1017 | micpm_remove(mic_ctx); | |
1018 | micscif_remove(mic_ctx); | |
1019 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) || defined(RHEL_RELEASE_CODE) | |
1020 | mic_vhost_blk_remove(mic_ctx->bd_info); | |
1021 | #endif | |
1022 | micveth_remove(mic_ctx); | |
1023 | mic_unreg_irqhandler(mic_ctx, 0x1, "MIC SHUTDOWN DoorBell 1"); | |
1024 | ||
1025 | ramoops_remove(mic_ctx); | |
1026 | vmcore_remove(mic_ctx); | |
1027 | mic_smpt_uninit(mic_ctx); | |
1028 | /* Make sure that no reset timer is running after the workqueue is destroyed */ | |
1029 | destroy_reset_workqueue(mic_ctx); | |
1030 | ||
1031 | if (mic_ctx->mmio.va) { | |
1032 | iounmap((void *)mic_ctx->mmio.va); | |
1033 | mic_ctx->mmio.va = 0; | |
1034 | } | |
1035 | ||
1036 | if (mic_ctx->aper.va) { | |
1037 | iounmap((void *)mic_ctx->aper.va); | |
1038 | mic_ctx->aper.va = 0; | |
1039 | } | |
1040 | ||
1041 | ||
1042 | return 0; | |
1043 | } | |
1044 | ||
1045 | #define MIC_MAX_BOOT_TIME 180 // Maximum number of seconds to wait for boot to complete | |
1046 | ||
1047 | static void | |
cd1ed09a | 1048 | online_timer(struct timer_list *arg) |
800f879a | 1049 | { |
cd1ed09a | 1050 | mic_ctx_t *mic_ctx = from_timer(mic_ctx, arg, boot_timer); |
800f879a AT |
1051 | uint64_t delay = (jiffies - mic_ctx->boot_start) / HZ; |
1052 | ||
1053 | if (mic_ctx->state == MIC_ONLINE) | |
1054 | return; | |
1055 | ||
1056 | if (delay > MIC_MAX_BOOT_TIME) { | |
1057 | printk("Fail booting MIC %d. Wait time execeed %d seconds\n", mic_ctx->bi_id, MIC_MAX_BOOT_TIME); | |
1058 | mic_ctx->state = MIC_BOOTFAIL; | |
1059 | return; | |
1060 | } | |
1061 | ||
800f879a | 1062 | mic_ctx->boot_timer.expires = jiffies + HZ; |
cd1ed09a | 1063 | timer_setup(&mic_ctx->boot_timer, online_timer, 0); |
800f879a AT |
1064 | |
1065 | if (!(delay % 5)) | |
1066 | printk("Waiting for MIC %d boot %lld\n", mic_ctx->bi_id, delay); | |
1067 | } | |
1068 | ||
1069 | static void | |
cd1ed09a | 1070 | boot_timer(struct timer_list *arg) |
800f879a | 1071 | { |
cd1ed09a | 1072 | mic_ctx_t *mic_ctx = from_timer(mic_ctx, arg, boot_timer); |
800f879a AT |
1073 | struct micvnet_info *vnet_info = (struct micvnet_info *) mic_ctx->bi_vethinfo; |
1074 | uint64_t delay = (jiffies - mic_ctx->boot_start) / HZ; | |
1075 | bool timer_restart = false; | |
1076 | ||
1077 | if ((mic_ctx->state != MIC_BOOT) && (mic_ctx->state != MIC_ONLINE)) { | |
1078 | return; | |
1079 | } | |
1080 | ||
1081 | if (delay > MIC_MAX_BOOT_TIME) { | |
1082 | printk("Fail booting MIC %d. Wait time execeed %d seconds\n", mic_ctx->bi_id, MIC_MAX_BOOT_TIME); | |
1083 | mic_ctx->state = MIC_BOOTFAIL; | |
1084 | return; | |
1085 | } | |
1086 | ||
1087 | if (!(delay % 5)) | |
1088 | printk("Waiting for MIC %d boot %lld\n", mic_ctx->bi_id, delay); | |
1089 | ||
1090 | if (mic_vnet_mode != VNET_MODE_DMA) | |
1091 | timer_restart = (SBOX_READ(mic_ctx->mmio.va, SBOX_SCRATCH14) == 0)? | |
1092 | true : false; | |
1093 | else if (atomic_read(&vnet_info->vi_state) != MICVNET_STATE_LINKUP) | |
1094 | timer_restart = (mic_ctx->state != MIC_ONLINE)? true: false; | |
1095 | ||
1096 | if (timer_restart) { | |
800f879a | 1097 | mic_ctx->boot_timer.expires = jiffies + HZ; |
cd1ed09a | 1098 | timer_setup(&mic_ctx->boot_timer, boot_timer, 0); |
800f879a AT |
1099 | return; |
1100 | } | |
1101 | ||
800f879a | 1102 | mic_ctx->boot_timer.expires = jiffies + HZ; |
cd1ed09a | 1103 | timer_setup(&mic_ctx->boot_timer, online_timer, 0); |
800f879a AT |
1104 | |
1105 | printk("MIC %d Network link is up\n", mic_ctx->bi_id); | |
1106 | schedule_work(&mic_ctx->boot_ws); | |
1107 | } | |
1108 | ||
1109 | void | |
1110 | post_boot_startup(struct work_struct *work) | |
1111 | { | |
1112 | ||
1113 | mic_ctx_t *mic_ctx | |
1114 | = container_of(work, mic_ctx_t, boot_ws); | |
1115 | ||
1116 | if (micpm_get_reference(mic_ctx, true) != 0) | |
1117 | return; | |
1118 | ||
1119 | // We should only enable DMA after uos is booted | |
1120 | BUG_ON(open_dma_device(mic_ctx->bi_id+1, | |
1121 | mic_ctx->mmio.va + HOST_SBOX_BASE_ADDRESS, | |
1122 | &mic_ctx->dma_handle)); | |
1123 | if (micveth_start(mic_ctx)) | |
1124 | printk(KERN_ERR "%s: micveth_start failed\n", __FUNCTION__); | |
1125 | micpm_put_reference(mic_ctx); | |
1126 | ||
1127 | } | |
1128 | ||
1129 | void | |
1130 | attempt_reset(struct work_struct *work) | |
1131 | { | |
1132 | mic_ctx_t *mic_ctx | |
1133 | = container_of(work, mic_ctx_t, resetwork); | |
1134 | printk("Reattempting reset after F2/F4 failure\n"); | |
1135 | adapter_reset(mic_ctx, RESET_WAIT, RESET_REATTEMPT); | |
1136 | } | |
1137 | ||
1138 | static void | |
1139 | ioremap_work(struct work_struct *work) | |
1140 | { | |
1141 | mic_ctx_t *mic_ctx | |
1142 | = container_of(work, mic_ctx_t, ioremapwork); | |
1143 | mic_ctx->aper.va = ioremap_wc(mic_ctx->aper.pa, mic_ctx->aper.len); | |
1144 | if (mic_ctx->aper.va == NULL) { | |
1145 | printk(KERN_ERR "mic %d: failed to map aperture space\n", mic_ctx->bi_id); | |
1146 | mutex_lock(&mic_ctx->state_lock); | |
1147 | mic_setstate(mic_ctx, MIC_RESETFAIL); | |
1148 | mutex_unlock(&mic_ctx->state_lock); | |
1149 | } | |
1150 | wake_up(&mic_ctx->ioremapwq); | |
1151 | } | |
1152 | ||
1153 | int | |
1154 | adapter_post_boot_device(mic_ctx_t *mic_ctx) | |
1155 | { | |
800f879a AT |
1156 | mic_ctx->boot_timer.expires = jiffies + HZ; |
1157 | mic_ctx->boot_start = jiffies; | |
cd1ed09a | 1158 | timer_setup(&mic_ctx->boot_timer, boot_timer, 0); |
800f879a AT |
1159 | return 0; |
1160 | } | |
1161 | ||
1162 | int | |
1163 | mic_shutdown_host_doorbell_intr_handler(mic_ctx_t *mic_ctx, int doorbell) | |
1164 | { | |
1165 | struct micscif_dev *dev = &scif_dev[mic_get_scifnode_id(mic_ctx)]; | |
1166 | mic_ctx->sdbic1 = SBOX_READ(mic_ctx->mmio.va, SBOX_SDBIC1); | |
1167 | SBOX_WRITE(0x0, mic_ctx->mmio.va, SBOX_SDBIC1); | |
1168 | if (mic_ctx->sdbic1) | |
1169 | queue_delayed_work(dev->sd_ln_wq, | |
1170 | &dev->sd_watchdog_work, 0); | |
1171 | return 0; | |
1172 | } | |
1173 | ||
1174 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) | |
1175 | static int | |
1176 | ramoops_proc_show(struct seq_file *m, void *data) | |
1177 | { | |
1178 | uint64_t id = ((uint64_t)data) & 0xffffffff; | |
1179 | uint64_t entry = ((uint64_t)data) >> 32; | |
1180 | struct list_head *pos, *tmpq; | |
1181 | bd_info_t *bd = NULL; | |
1182 | mic_ctx_t *mic_ctx = NULL; | |
1183 | char *record; | |
1184 | char *end; | |
1185 | int size = 0; | |
1186 | int l = 0; | |
1187 | char *output; | |
1188 | unsigned long flags; | |
1189 | ||
1190 | list_for_each_safe(pos, tmpq, &mic_data.dd_bdlist) { | |
1191 | bd = list_entry(pos, bd_info_t, bi_list); | |
1192 | mic_ctx = &bd->bi_ctx; | |
1193 | if (mic_ctx->bi_id == id) | |
1194 | break; | |
1195 | } | |
1196 | ||
1197 | if (mic_ctx == NULL) | |
1198 | return 0; | |
1199 | ||
1200 | spin_lock_irqsave(&mic_ctx->ramoops_lock, flags); | |
1201 | ||
1202 | record = mic_ctx->ramoops_va[entry]; | |
1203 | if (record == NULL) { | |
1204 | spin_unlock_irqrestore(&mic_ctx->ramoops_lock, flags); | |
1205 | return -EEXIST; | |
1206 | } | |
1207 | ||
1208 | size = mic_ctx->ramoops_size; | |
1209 | end = record + size; | |
1210 | ||
1211 | if ((output = kzalloc(size, GFP_ATOMIC)) == NULL) { | |
1212 | spin_unlock_irqrestore(&mic_ctx->ramoops_lock, flags); | |
1213 | return -ENOMEM; | |
1214 | } | |
1215 | ||
1216 | l += scnprintf(output, size, "%s", record); | |
1217 | ||
1218 | spin_unlock_irqrestore(&mic_ctx->ramoops_lock, flags); | |
1219 | ||
1220 | seq_printf(m, "%s", output); | |
1221 | return 0; | |
1222 | } | |
1223 | ||
1224 | static int | |
1225 | ramoops_proc_open(struct inode *inode, struct file *file) | |
1226 | { | |
1227 | return single_open(file, ramoops_proc_show, NULL); | |
1228 | } | |
1229 | ||
1230 | struct file_operations ramoops_proc_fops = { | |
1231 | .open = ramoops_proc_open, | |
1232 | .read = seq_read, | |
1233 | .llseek = seq_lseek, | |
1234 | .release = single_release, | |
1235 | }; | |
1236 | ||
1237 | #else // LINUX VERSION | |
1238 | static int | |
1239 | ramoops_read(char *buf, char **start, off_t offset, int len, int *eof, void *data) | |
1240 | { | |
1241 | uint64_t id = ((uint64_t)data) & 0xffffffff; | |
1242 | uint64_t entry = ((uint64_t)data) >> 32; | |
1243 | struct list_head *pos, *tmpq; | |
1244 | bd_info_t *bd = NULL; | |
1245 | mic_ctx_t *mic_ctx = NULL; | |
1246 | char *record; | |
1247 | char *end; | |
1248 | int size = 0; | |
1249 | int l = 0; | |
1250 | int left_to_read; | |
1251 | char *output; | |
1252 | unsigned long flags; | |
1253 | ||
1254 | list_for_each_safe(pos, tmpq, &mic_data.dd_bdlist) { | |
1255 | bd = list_entry(pos, bd_info_t, bi_list); | |
1256 | mic_ctx = &bd->bi_ctx; | |
1257 | if (mic_ctx->bi_id == id) | |
1258 | break; | |
1259 | } | |
1260 | ||
1261 | if (mic_ctx == NULL) | |
1262 | return 0; | |
1263 | ||
1264 | spin_lock_irqsave(&mic_ctx->ramoops_lock, flags); | |
1265 | ||
1266 | record = mic_ctx->ramoops_va[entry]; | |
1267 | if (record == NULL) { | |
1268 | spin_unlock_irqrestore(&mic_ctx->ramoops_lock, flags); | |
1269 | *eof = 1; | |
1270 | return 0; | |
1271 | } | |
1272 | ||
1273 | size = mic_ctx->ramoops_size; | |
1274 | end = record + size; | |
1275 | ||
1276 | if ((output = kzalloc(size, GFP_ATOMIC)) == NULL) { | |
1277 | spin_unlock_irqrestore(&mic_ctx->ramoops_lock, flags); | |
1278 | return -ENOMEM; | |
1279 | } | |
1280 | ||
1281 | l += scnprintf(output, size, "%s", record); | |
1282 | ||
1283 | spin_unlock_irqrestore(&mic_ctx->ramoops_lock, flags); | |
1284 | ||
1285 | left_to_read = l - offset; | |
1286 | if (left_to_read < 0) | |
1287 | left_to_read = 0; | |
1288 | if (left_to_read == 0) | |
1289 | *eof = 1; | |
1290 | ||
1291 | left_to_read = min(len, left_to_read); | |
1292 | memcpy(buf, output + offset, left_to_read); | |
1293 | kfree(output); | |
1294 | *start = buf; | |
1295 | return left_to_read; | |
1296 | } | |
1297 | #endif // LINUX VERSION | |
1298 | ||
1299 | int | |
1300 | set_ramoops_pa(mic_ctx_t *mic_ctx) | |
1301 | { | |
1302 | if (mic_ctx->ramoops_pa[0] == 0L) { | |
1303 | kfree(mic_ctx->ramoops_va[0]); | |
1304 | mic_ctx->ramoops_size = 0; | |
1305 | mic_ctx->ramoops_va[0] = NULL; | |
1306 | return 1; | |
1307 | } | |
1308 | return 0; | |
1309 | } | |
1310 | ||
1311 | int ramoops_count = 4; | |
1312 | ||
1313 | void | |
1314 | ramoops_probe(mic_ctx_t *mic_ctx) | |
1315 | { | |
1316 | char name[64]; | |
1317 | ||
1318 | mic_ctx->ramoops_size = ramoops_count * PAGE_SIZE; | |
1319 | if ((mic_ctx->ramoops_va[0] = kzalloc(mic_ctx->ramoops_size, GFP_KERNEL)) != NULL) { | |
1320 | spin_lock_init(&mic_ctx->ramoops_lock); | |
1321 | mic_ctx->ramoops_va[1] = NULL; | |
1322 | ||
1323 | mic_ctx->ramoops_pa[0] = mic_ctx_map_single(mic_ctx, mic_ctx->ramoops_va[0], | |
1324 | mic_ctx->ramoops_size); | |
1325 | if (set_ramoops_pa(mic_ctx)) | |
1326 | return; | |
1327 | ||
1328 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) | |
1329 | snprintf(name, 64, "mic%d", mic_ctx->bi_id); | |
1330 | proc_create_data(name, 0444, ramoops_dir, &ramoops_proc_fops, | |
1331 | (void *)(long)mic_ctx->bi_id); | |
1332 | ||
1333 | snprintf(name, 64, "mic%d_prev", mic_ctx->bi_id); | |
1334 | proc_create_data(name, 0444, ramoops_dir, &ramoops_proc_fops, | |
1335 | (void *)((long)mic_ctx->bi_id | (1L << 32))); | |
1336 | #else // LINUX VERSION | |
1337 | snprintf(name, 64, "mic%d", mic_ctx->bi_id); | |
1338 | if (create_proc_read_entry(name, 0444, ramoops_dir, ramoops_read, | |
1339 | (void *)(long)mic_ctx->bi_id) == NULL) | |
1340 | printk("Failed to intialize /proc/mic_ramoops/%s\n", name); | |
1341 | ||
1342 | snprintf(name, 64, "mic%d_prev", mic_ctx->bi_id); | |
1343 | if (create_proc_read_entry(name, 0444, ramoops_dir, ramoops_read, | |
1344 | (void *)((long)mic_ctx->bi_id | (1L << 32))) == NULL) | |
1345 | printk("Failed to intialize /proc/mic_ramoops/%s\n", name); | |
1346 | #endif //LINUX VERSION | |
1347 | } else { | |
1348 | mic_ctx->ramoops_size = 0; | |
1349 | } | |
1350 | } | |
1351 | ||
1352 | void | |
1353 | ramoops_flip(mic_ctx_t *mic_ctx) | |
1354 | { | |
1355 | unsigned long flags; | |
1356 | ||
1357 | if (mic_ctx->ramoops_size == 0) | |
1358 | return; | |
1359 | ||
1360 | spin_lock_irqsave(&mic_ctx->ramoops_lock, flags); | |
1361 | if (mic_ctx->ramoops_va[1] != NULL) { | |
1362 | mic_ctx_unmap_single(mic_ctx, mic_ctx->ramoops_pa[1], mic_ctx->ramoops_size); | |
1363 | kfree(mic_ctx->ramoops_va[1]); | |
1364 | } | |
1365 | ||
1366 | mic_ctx->ramoops_pa[1] = mic_ctx->ramoops_pa[0]; | |
1367 | mic_ctx->ramoops_va[1] = mic_ctx->ramoops_va[0]; | |
1368 | if ((mic_ctx->ramoops_va[0] = kzalloc(mic_ctx->ramoops_size, GFP_ATOMIC)) != NULL) { | |
1369 | mic_ctx->ramoops_pa[0] = mic_ctx_map_single(mic_ctx, mic_ctx->ramoops_va[0], | |
1370 | mic_ctx->ramoops_size); | |
1371 | set_ramoops_pa(mic_ctx); | |
1372 | } | |
1373 | spin_unlock_irqrestore(&mic_ctx->ramoops_lock, flags); | |
1374 | } | |
1375 | ||
1376 | int | |
1377 | adapter_probe(mic_ctx_t *mic_ctx) | |
1378 | { | |
1379 | int db; | |
1380 | uint32_t scratch13; | |
1381 | int32_t status = 0; | |
1382 | ||
1383 | // Init the irq information | |
1384 | atomic_set(&mic_ctx->bi_irq.mi_received, 0); | |
1385 | spin_lock_init(&mic_ctx->bi_irq.mi_lock); | |
1386 | tasklet_init(&mic_ctx->bi_dpc, adapter_dpc, (unsigned long)&mic_ctx->bi_dpc); | |
1387 | ||
1388 | for (db = 0; db < MIC_NUM_DB; db++) { | |
1389 | INIT_LIST_HEAD(&mic_ctx->bi_irq.mi_dblist[db]); | |
1390 | } | |
1391 | ||
1392 | if (mic_ctx->msie) | |
1393 | mic_enable_msi_interrupts(mic_ctx); | |
1394 | ||
1395 | scratch13 = SBOX_READ(mic_ctx->mmio.va, SBOX_SCRATCH13); | |
1396 | mic_ctx->bi_stepping = SCRATCH13_STEP_ID(scratch13); | |
1397 | mic_ctx->bi_substepping = SCRATCH13_SUB_STEP(scratch13); | |
1398 | #ifdef MIC_IS_EMULATION | |
1399 | mic_ctx->bi_platform = PLATFORM_EMULATOR; | |
1400 | #else | |
1401 | mic_ctx->bi_platform = SCRATCH13_PLATFORM_ID(scratch13); | |
1402 | #endif | |
1403 | ||
1404 | mic_enable_interrupts(mic_ctx); | |
1405 | if (micveth_probe(mic_ctx)) | |
1406 | printk(KERN_ERR "%s: micveth_probe failed\n", __FUNCTION__); | |
1407 | ||
1408 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) || defined(RHEL_RELEASE_CODE) | |
1409 | if (mic_vhost_blk_probe(mic_ctx->bd_info)) | |
1410 | printk(KERN_ERR "%s: mic_vhost_blk_probe failed\n", __FUNCTION__); | |
1411 | #endif | |
1412 | micscif_probe(mic_ctx); | |
1413 | if(micpm_probe(mic_ctx)) | |
1414 | printk(KERN_ERR "%s: micpm_probe failed\n", __FUNCTION__); | |
1415 | ||
1416 | mic_reg_irqhandler(mic_ctx, 1, "MIC SHUTDOWN DoorBell 1", | |
1417 | mic_shutdown_host_doorbell_intr_handler); | |
1418 | ||
1419 | ramoops_probe(mic_ctx); | |
1420 | if (status) { | |
1421 | printk("boot_linux_uos failed \n"); | |
1422 | return status; | |
1423 | } | |
1424 | ||
1425 | // We should only enable DMA after uos is booted | |
1426 | //mic_dma_lib_init(mic_ctx->mmio.va+HOST_SBOX_BASE_ADDRESS); | |
1427 | ||
1428 | return status; | |
1429 | } | |
1430 | ||
1431 | int | |
1432 | adapter_start_device(mic_ctx_t *mic_ctx) | |
1433 | { | |
1434 | int ret; | |
1435 | ||
1436 | mutex_lock(&mic_ctx->state_lock); | |
1437 | if (mic_ctx->state == MIC_READY) { | |
1438 | mic_setstate(mic_ctx, MIC_BOOT); | |
1439 | } else { | |
1440 | mutex_unlock(&mic_ctx->state_lock); | |
1441 | /* TODO: Unknown state handling? */ | |
1442 | printk(KERN_ERR "%s %d state %d??\n", | |
1443 | __func__, __LINE__, mic_ctx->state); | |
1444 | ret = -EINVAL; | |
1445 | goto exit; | |
1446 | } | |
1447 | mutex_unlock(&mic_ctx->state_lock); | |
1448 | mic_ctx->mode = MODE_LINUX; | |
1449 | ret = boot_linux_uos(mic_ctx, mic_ctx->image, mic_ctx->initramfs); | |
1450 | if (ret) { | |
1451 | printk(KERN_ERR "boot_linux_uos failed %d\n", ret); | |
1452 | goto exit; | |
1453 | } | |
1454 | ||
1455 | ret = adapter_post_boot_device(mic_ctx); | |
1456 | if (ret) { | |
1457 | printk(KERN_ERR "adapter post boot failed %d\n", ret); | |
1458 | goto exit; | |
1459 | } | |
1460 | ||
1461 | pr_debug("adapter started successfully\n"); | |
1462 | exit: | |
1463 | return ret; | |
1464 | } | |
1465 | ||
1466 | int | |
1467 | adapter_init_device(mic_ctx_t *mic_ctx) | |
1468 | { | |
1469 | #ifdef USE_VCONSOLE | |
1470 | struct vcons_buf *vcons_buf; | |
1471 | #endif | |
1472 | uint32_t mmio_data_cc; /* mmio data from class code register */ | |
1473 | uint32_t mmio_data_bar; /* mmio data from bar enable register */ | |
1474 | uint32_t device_id; | |
1475 | int err = 0; | |
1476 | ||
1477 | spin_lock_init(&mic_ctx->sysfs_lock); | |
1478 | mic_setstate(mic_ctx, MIC_RESET); | |
1479 | mic_ctx->mode = MODE_NONE; | |
1480 | mic_ctx->reset_count = 0; | |
1481 | mutex_init (&mic_ctx->state_lock); | |
1482 | init_waitqueue_head(&mic_ctx->resetwq); | |
1483 | init_waitqueue_head(&mic_ctx->ioremapwq); | |
800f879a AT |
1484 | if (!(mic_ctx->resetworkq = __mic_create_singlethread_workqueue("RESET WORK"))) |
1485 | return -ENOMEM; | |
1486 | if (!(mic_ctx->ioremapworkq = __mic_create_singlethread_workqueue("IOREMAP_WORK"))) { | |
1487 | err = -EINVAL; | |
1488 | goto destroy_reset_wq; | |
1489 | } | |
1490 | INIT_WORK(&mic_ctx->ioremapwork, ioremap_work); | |
1491 | INIT_WORK(&mic_ctx->boot_ws, post_boot_startup); | |
1492 | INIT_WORK(&mic_ctx->resetwork, attempt_reset); | |
1493 | atomic_set(&mic_ctx->gate_interrupt, 0); | |
1494 | ||
1495 | device_id = mic_ctx->bi_pdev->device; | |
1496 | mic_ctx->bi_family = get_product_family(device_id); | |
1497 | ||
1498 | if ((mic_ctx->mmio.va = ioremap_nocache(mic_ctx->mmio.pa, | |
1499 | mic_ctx->mmio.len)) == NULL) { | |
1500 | printk("mic %d: failed to map mmio space\n", mic_ctx->bi_id); | |
1501 | err = -ENOMEM; | |
1502 | goto destroy_remap_wq; | |
1503 | } | |
1504 | ||
1505 | if (mic_ctx->aper.pa == 0) { | |
1506 | /* | |
1507 | * Read class code from SBOX_PCIE_PCI_REVISION_ID_AND_C_0X8 register | |
1508 | * If the mode is zombie, then | |
1509 | * 1> Aperture is not available | |
1510 | * 2> Register 0x5CD4 is written to 0x00000002 to disable all BARs except MMIO | |
1511 | * 3> Register 0x5808 is written to 0xFF0000XX to set the class ID to a generic PCI device. | |
1512 | */ | |
1513 | mmio_data_cc = SBOX_READ(mic_ctx->mmio.va, SBOX_PCIE_PCI_REVISION_ID_AND_C_0X8); | |
1514 | mmio_data_cc = PCIE_CLASS_CODE(mmio_data_cc); | |
1515 | mmio_data_bar = SBOX_READ(mic_ctx->mmio.va, SBOX_PCIE_BAR_ENABLE); | |
1516 | ||
1517 | if((mmio_data_cc == ZOMBIE_CLASS_CODE) && (mmio_data_bar == DISABLE_BAR)) { | |
1518 | mic_ctx->card_usage_mode = USAGE_MODE_ZOMBIE; | |
1519 | usagemode_param = USAGE_MODE_ZOMBIE; | |
1520 | } else { | |
1521 | printk("Error: Not in zombie mode and aperture is 0\n"); | |
1522 | err = -EINVAL; | |
1523 | goto adap_init_unmapmmio; | |
1524 | } | |
1525 | } else { | |
1526 | if (mic_ctx->ioremapworkq) { | |
1527 | queue_work(mic_ctx->ioremapworkq, &mic_ctx->ioremapwork); | |
1528 | } else { | |
1529 | if ((mic_ctx->aper.va = ioremap_wc(mic_ctx->aper.pa, mic_ctx->aper.len)) == NULL) { | |
1530 | printk("mic %d: failed to map aperture space\n", mic_ctx->bi_id); | |
1531 | err = -EINVAL; | |
1532 | goto adap_init_unmapmmio; | |
1533 | } | |
1534 | } | |
1535 | } | |
1536 | ||
1537 | mic_debug_init(mic_ctx); | |
1538 | mic_smpt_init(mic_ctx); | |
1539 | #ifdef USE_VCONSOLE | |
1540 | // Allocate memory for PCI serial console | |
1541 | mic_ctx->bi_vcons.dc_buf_virt = (void *)get_zeroed_page(GFP_KERNEL); | |
1542 | mic_ctx->bi_vcons.dc_hdr_virt = kzalloc(sizeof(struct vcons_buf), GFP_KERNEL); | |
1543 | ||
1544 | if ((!mic_ctx->bi_vcons.dc_buf_virt) || (!mic_ctx->bi_vcons.dc_hdr_virt)) { | |
1545 | printk(KERN_ERR "mic %d: failed to allocate memory for vcons buffer\n", | |
1546 | mic_ctx->bi_id); | |
1547 | mic_ctx->bi_vcons.dc_enabled = 0; | |
1548 | if (mic_ctx->bi_vcons.dc_buf_virt) | |
1549 | free_pages((uint64_t)mic_ctx->bi_vcons.dc_buf_virt, 0); | |
1550 | if (mic_ctx->bi_vcons.dc_hdr_virt) | |
1551 | kfree(mic_ctx->bi_vcons.dc_hdr_virt); | |
1552 | } else { | |
1553 | mic_ctx->bi_vcons.dc_hdr_dma_addr = mic_ctx_map_single(mic_ctx, | |
1554 | mic_ctx->bi_vcons.dc_hdr_virt, | |
1555 | sizeof(struct vcons_buf)); | |
1556 | mic_ctx->bi_vcons.dc_dma_addr = mic_ctx_map_single(mic_ctx, | |
1557 | mic_ctx->bi_vcons.dc_buf_virt, | |
1558 | MICVCONS_BUF_SIZE); | |
1559 | if ((!mic_ctx->bi_vcons.dc_dma_addr) || | |
1560 | (!mic_ctx->bi_vcons.dc_hdr_dma_addr)) | |
1561 | mic_ctx->bi_vcons.dc_enabled = 0; | |
1562 | else | |
1563 | mic_ctx->bi_vcons.dc_enabled = 1; | |
1564 | mic_ctx->bi_vcons.dc_size = MICVCONS_BUF_SIZE; | |
1565 | vcons_buf = (struct vcons_buf *)(mic_ctx->bi_vcons.dc_hdr_virt); | |
1566 | vcons_buf->o_buf_dma_addr = mic_ctx->bi_vcons.dc_dma_addr; | |
1567 | vcons_buf->o_size = MICVCONS_BUF_SIZE; | |
1568 | smp_wmb(); | |
1569 | vcons_buf->host_magic = MIC_HOST_VCONS_READY; | |
1570 | vcons_buf->host_rb_ver = micscif_rb_get_version(); | |
1571 | } | |
1572 | #endif // USE_VCONSOLE | |
1573 | mic_ctx->boot_mem = 0; | |
1574 | mic_psmi_init(mic_ctx); | |
1575 | mic_ctx->dma_handle = NULL; | |
1576 | mic_ctx->sdbic1 = 0; | |
1577 | // To avoid hazard on Windows, sku_build_table is done on DriverEntry | |
1578 | sku_build_table(); | |
1579 | device_id = mic_ctx->bi_pdev->device; | |
1580 | sku_find(mic_ctx, device_id); | |
1581 | // To avoid hazard on Windows, sku_destroy_table is done on MicUnload | |
1582 | sku_destroy_table(); | |
1583 | ||
1584 | /* Determine the amount of compensation that needs to be applied to MIC's ETC timer */ | |
1585 | calculate_etc_compensation(mic_ctx); | |
1586 | ||
1587 | return 0; | |
1588 | ||
1589 | adap_init_unmapmmio: | |
1590 | iounmap(mic_ctx->mmio.va); | |
1591 | destroy_remap_wq: | |
1592 | destroy_workqueue(mic_ctx->ioremapworkq); | |
1593 | destroy_reset_wq: | |
1594 | destroy_workqueue(mic_ctx->resetworkq); | |
1595 | return err; | |
1596 | } | |
1597 | ||
1598 | void | |
1599 | mic_enable_interrupts(mic_ctx_t *mic_ctx) | |
1600 | { | |
1601 | ENABLE_MIC_INTERRUPTS(mic_ctx->mmio.va); | |
1602 | } | |
1603 | ||
1604 | void | |
1605 | mic_disable_interrupts(mic_ctx_t *mic_ctx) | |
1606 | { | |
1607 | uint32_t sboxSice0reg; | |
1608 | ||
1609 | sboxSice0reg = SBOX_READ(mic_ctx->mmio.va, SBOX_SICE0); | |
1610 | SBOX_WRITE(sboxSice0reg, mic_ctx->mmio.va, SBOX_SICC0); | |
1611 | } | |
1612 | ||
1613 | void | |
1614 | mic_enable_msi_interrupts(mic_ctx_t *mic_ctx) | |
1615 | { | |
1616 | uint32_t sboxMXARreg; | |
1617 | ||
1618 | // Only support single MSI interrupt for now | |
1619 | sboxMXARreg = SBOX_SICE0_DBR_BITS(0xf) | SBOX_SICE0_DMA_BITS(0xff); | |
1620 | if (mic_ctx->bi_family == FAMILY_KNC) | |
1621 | SBOX_WRITE(sboxMXARreg, mic_ctx->mmio.va, SBOX_MXAR0_K1OM); | |
1622 | else | |
1623 | SBOX_WRITE(sboxMXARreg, mic_ctx->mmio.va, SBOX_MXAR0); | |
1624 | } | |
1625 | ||
1626 | int | |
1627 | mic_reg_irqhandler(mic_ctx_t *mic_ctx, int doorbell, char *idstring, | |
1628 | int (*irqfunc)(mic_ctx_t *mic_ctx, int doorbell)) | |
1629 | { | |
1630 | mic_irqhandler_t *irqhandle; | |
1631 | unsigned long flags; | |
1632 | ||
1633 | if (doorbell > MIC_IRQ_MAX) { | |
1634 | return EINVAL; | |
1635 | } | |
1636 | ||
1637 | if (!(irqhandle = kmalloc(sizeof(mic_irqhandler_t), GFP_ATOMIC))) | |
1638 | goto memerror1; | |
1639 | ||
1640 | if (!(irqhandle->ih_idstring = kmalloc(strlen(idstring) + 1, GFP_ATOMIC))) | |
1641 | goto memerror2; | |
1642 | ||
1643 | irqhandle->ih_func = irqfunc; | |
1644 | strcpy(irqhandle->ih_idstring, idstring); | |
1645 | ||
1646 | spin_lock_irqsave(&mic_ctx->bi_irq.mi_lock, flags); | |
1647 | list_add_tail(&irqhandle->ih_list, &mic_ctx->bi_irq.mi_dblist[doorbell]); | |
1648 | spin_unlock_irqrestore(&mic_ctx->bi_irq.mi_lock, flags); | |
1649 | return 0; | |
1650 | ||
1651 | memerror2: | |
1652 | kfree(irqhandle); | |
1653 | memerror1: | |
1654 | return -ENOMEM; | |
1655 | } | |
1656 | ||
1657 | int | |
1658 | mic_unreg_irqhandler(mic_ctx_t *mic_ctx, int doorbell, char *idstring) | |
1659 | { | |
1660 | mic_irqhandler_t *irqhandle; | |
1661 | struct list_head *pos, *tmpq; | |
1662 | unsigned long flags; | |
1663 | ||
1664 | spin_lock_irqsave(&mic_ctx->bi_irq.mi_lock, flags); | |
1665 | list_for_each_safe(pos, tmpq, &mic_ctx->bi_irq.mi_dblist[doorbell]) { | |
1666 | irqhandle = list_entry(pos, mic_irqhandler_t, ih_list); | |
1667 | if (strcmp(idstring, irqhandle->ih_idstring) == 0) { | |
1668 | list_del(pos); | |
1669 | kfree(irqhandle->ih_idstring); | |
1670 | kfree(irqhandle); | |
1671 | } | |
1672 | } | |
1673 | spin_unlock_irqrestore(&mic_ctx->bi_irq.mi_lock, flags); | |
1674 | ||
1675 | return 0; | |
1676 | } | |
1677 | ||
1678 | static __always_inline | |
1679 | void adapter_process_one_interrupt(mic_ctx_t *mic_ctx, uint32_t events) | |
1680 | { | |
1681 | mic_irqhandler_t *irqhandle; | |
1682 | struct list_head *pos; | |
1683 | int doorbell; | |
1684 | ||
1685 | atomic_inc(&mic_ctx->bi_irq.mi_received); | |
1686 | ||
1687 | if (SBOX_SICR0_DBR(events)) { | |
1688 | for (doorbell = 0; doorbell < 4; doorbell++) { | |
1689 | if (SBOX_SICR0_DBR(events) & (0x1 << doorbell)) { | |
1690 | spin_lock(&mic_ctx->bi_irq.mi_lock); | |
1691 | list_for_each(pos, &mic_ctx->bi_irq.mi_dblist[doorbell]) { | |
1692 | irqhandle = list_entry(pos, mic_irqhandler_t, ih_list); | |
1693 | irqhandle->ih_func(mic_ctx, doorbell); | |
1694 | } | |
1695 | spin_unlock(&mic_ctx->bi_irq.mi_lock); | |
1696 | } | |
1697 | } | |
1698 | ||
1699 | } | |
1700 | ||
1701 | if (SBOX_SICR0_DMA(events)) | |
1702 | host_dma_interrupt_handler(mic_ctx->dma_handle, events); | |
1703 | } | |
1704 | ||
1705 | int | |
1706 | adapter_isr(mic_ctx_t *mic_ctx) | |
1707 | { | |
1708 | volatile uint32_t sboxSicr0reg; | |
1709 | if (atomic_cmpxchg(&mic_ctx->gate_interrupt, 0, 1) == 1) | |
1710 | return -1; | |
1711 | ||
1712 | sboxSicr0reg = SBOX_READ(mic_ctx->mmio.va, SBOX_SICR0); | |
1713 | ||
1714 | if (unlikely(!sboxSicr0reg)) { | |
1715 | // Spurious interrupt | |
1716 | atomic_set(&mic_ctx->gate_interrupt, 0); | |
1717 | return -1; | |
1718 | } | |
1719 | ||
1720 | // tell mic that we recived interrupt otherwise it will keep sending them | |
1721 | SBOX_WRITE(sboxSicr0reg, mic_ctx->mmio.va, SBOX_SICR0); | |
1722 | ||
1723 | // This only applies to KNC B0 | |
1724 | if (FAMILY_KNC == mic_ctx->bi_family && | |
1725 | mic_ctx->bi_stepping >= KNC_B0_STEP) | |
1726 | mic_enable_interrupts(mic_ctx); | |
1727 | ||
1728 | atomic_set(&mic_ctx->gate_interrupt, 0); | |
1729 | adapter_process_one_interrupt(mic_ctx, sboxSicr0reg); | |
1730 | return 0; | |
1731 | } | |
1732 | ||
1733 | int | |
1734 | adapter_imsr(mic_ctx_t *mic_ctx) | |
1735 | { | |
1736 | #if 0 /* TODO: disable interrupt when KNC auto-enable isn't used */ | |
1737 | mic_disable_interrupts(mic_ctx); | |
1738 | #endif | |
1739 | tasklet_schedule(&mic_ctx->bi_dpc); | |
1740 | return 0; | |
1741 | } | |
1742 | ||
1743 | static void adapter_dpc(unsigned long dpc) | |
1744 | { | |
1745 | mic_ctx_t *mic_ctx = | |
1746 | container_of((struct tasklet_struct *)dpc, mic_ctx_t, bi_dpc); | |
1747 | ||
1748 | volatile uint32_t sboxSicr0reg; | |
1749 | ||
1750 | if (atomic_cmpxchg(&mic_ctx->gate_interrupt, 0, 1) == 1) | |
1751 | return; | |
1752 | ||
1753 | /* Clear pending bit array */ | |
1754 | if (FAMILY_KNC == mic_ctx->bi_family) { | |
1755 | if (KNC_A_STEP == mic_ctx->bi_stepping) | |
1756 | SBOX_WRITE(1, mic_ctx->mmio.va, SBOX_MSIXPBACR_K1OM); | |
1757 | } else | |
1758 | SBOX_WRITE(1, mic_ctx->mmio.va, SBOX_MSIXPBACR); | |
1759 | ||
1760 | sboxSicr0reg = SBOX_READ(mic_ctx->mmio.va, SBOX_SICR0); | |
1761 | if (unlikely(!sboxSicr0reg)) { | |
1762 | atomic_set(&mic_ctx->gate_interrupt, 0); | |
1763 | return; | |
1764 | } | |
1765 | ||
1766 | SBOX_WRITE(sboxSicr0reg, mic_ctx->mmio.va, SBOX_SICR0); | |
1767 | ||
1768 | // This only applies to KNC B0 | |
1769 | if (FAMILY_KNC == mic_ctx->bi_family && | |
1770 | mic_ctx->bi_stepping >= KNC_B0_STEP) | |
1771 | mic_enable_interrupts(mic_ctx); | |
1772 | ||
1773 | atomic_set(&mic_ctx->gate_interrupt, 0); | |
1774 | adapter_process_one_interrupt(mic_ctx, sboxSicr0reg); | |
1775 | } | |
1776 | ||
1777 | void ramoops_init(void) | |
1778 | { | |
1779 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) | |
1780 | ramoops_dir = proc_mkdir("mic_ramoops", NULL); | |
1781 | #else | |
1782 | ramoops_dir = create_proc_entry("mic_ramoops", S_IFDIR | S_IRUGO, NULL); | |
1783 | #endif | |
1784 | } | |
1785 | ||
1786 | void ramoops_exit(void) | |
1787 | { | |
1788 | remove_proc_entry("mic_ramoops", NULL); | |
1789 | } | |
1790 | ||
1791 | void ramoops_remove(mic_ctx_t *mic_ctx) | |
1792 | { | |
1793 | char name[64]; | |
1794 | int i; | |
1795 | ||
1796 | snprintf(name, 64, "mic%d", mic_ctx->bi_id); | |
1797 | remove_proc_entry(name, ramoops_dir); | |
1798 | ||
1799 | snprintf(name, 64, "mic%d_prev", mic_ctx->bi_id); | |
1800 | remove_proc_entry(name, ramoops_dir); | |
1801 | if (mic_ctx->ramoops_size == 0) | |
1802 | return; | |
1803 | ||
1804 | for (i = 0; i < 2; i++) { | |
1805 | if (mic_ctx->ramoops_va[i] != NULL) { | |
1806 | mic_ctx_unmap_single(mic_ctx, mic_ctx->ramoops_pa[i], | |
1807 | mic_ctx->ramoops_size); | |
1808 | kfree(mic_ctx->ramoops_va[i]); | |
1809 | } | |
1810 | } | |
1811 | } | |
1812 | ||
1813 | void vmcore_init(void) | |
1814 | { | |
1815 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) | |
1816 | vmcore_dir = proc_mkdir("mic_vmcore", NULL); | |
1817 | #else | |
1818 | vmcore_dir = create_proc_entry("mic_vmcore", S_IFDIR | S_IRUGO, NULL); | |
1819 | #endif | |
1820 | } | |
1821 | ||
1822 | void vmcore_exit(void) | |
1823 | { | |
1824 | if (vmcore_dir) { | |
1825 | remove_proc_entry("mic_vmcore", NULL); | |
1826 | vmcore_dir = NULL; | |
1827 | } | |
1828 | } | |
1829 | ||
1830 | void vmcore_remove(mic_ctx_t *mic_ctx) | |
1831 | { | |
1832 | char name[64]; | |
1833 | ||
1834 | snprintf(name, 64, "mic%d", mic_ctx->bi_id); | |
1835 | if (mic_ctx->vmcore_dir) { | |
1836 | remove_proc_entry(name, vmcore_dir); | |
1837 | mic_ctx->vmcore_dir = NULL; | |
1838 | } | |
1839 | if (mic_ctx->elfcorebuf) { | |
1840 | kfree(mic_ctx->elfcorebuf); | |
1841 | mic_ctx->elfcorebuf = NULL; | |
1842 | mic_ctx->elfcorebuf_sz = 0; | |
1843 | mic_ctx->vmcore_size = 0; | |
1844 | } | |
1845 | } | |
1846 | ||
1847 | ||
1848 | void | |
1849 | adapter_init(void) | |
1850 | { | |
1851 | // Per driver init ONLY. | |
1852 | mic_dma_init(); | |
1853 | micscif_init(); | |
1854 | micpm_init(); | |
1855 | ramoops_init(); | |
1856 | vmcore_init(); | |
1857 | INIT_LIST_HEAD(&mic_data.dd_bdlist); | |
1858 | } | |
1859 | ||
1860 | ||
1861 | void show_stepping_comm(mic_ctx_t *mic_ctx,char *buf) | |
1862 | { | |
1863 | #define STEPINGSTRSIZE 3 | |
1864 | char string[STEPINGSTRSIZE]; | |
1865 | switch (mic_ctx->bi_family) { | |
1866 | case FAMILY_ABR: | |
1867 | switch (mic_ctx->bi_stepping) { | |
1868 | case 0: | |
1869 | string[0] = 'A'; | |
1870 | string[1] = mic_ctx->bi_substepping + '0'; | |
1871 | break; | |
1872 | case 2: | |
1873 | string[0] = 'B'; | |
1874 | string[1] = '0'; | |
1875 | break; | |
1876 | case 3: | |
1877 | string[0] = 'B'; | |
1878 | string[1] = '1'; | |
1879 | break; | |
1880 | case 4: | |
1881 | string[0] = 'C'; | |
1882 | string[1] = '0'; | |
1883 | break; | |
1884 | case 5: | |
1885 | string[0] = 'C'; | |
1886 | string[1] = '1'; | |
1887 | break; | |
1888 | case 6: | |
1889 | string[0] = 'D'; | |
1890 | string[1] = '0'; | |
1891 | break; | |
1892 | default: | |
1893 | string[0] = '?'; | |
1894 | string[1] = '?'; | |
1895 | break; | |
1896 | } | |
1897 | break; | |
1898 | case FAMILY_KNC: | |
1899 | switch (mic_ctx->bi_stepping) { | |
1900 | case KNC_A_STEP: | |
1901 | string[0] = 'A'; | |
1902 | string[1] = '0'; | |
1903 | break; | |
1904 | case KNC_B0_STEP: | |
1905 | string[0] = 'B'; | |
1906 | string[1] = '0'; | |
1907 | break; | |
1908 | case KNC_B1_STEP: | |
1909 | string[0] = 'B'; | |
1910 | string[1] = '1'; | |
1911 | break; | |
1912 | case KNC_C_STEP: | |
1913 | string[0] = 'C'; | |
1914 | string[1] = '0'; | |
1915 | break; | |
1916 | default: | |
1917 | string[0] = '?'; | |
1918 | string[1] = '?'; | |
1919 | break; | |
1920 | } | |
1921 | break; | |
1922 | default: | |
1923 | string[0] = '?'; | |
1924 | string[1] = '?'; | |
1925 | break; | |
1926 | } | |
1927 | ||
1928 | string[2] = '\0'; | |
1929 | ||
1930 | strncpy(buf,string,STEPINGSTRSIZE); | |
1931 | } | |
1932 | ||
1933 |