Commit 2196c6f1ed66eef23df3b478cfe71661ae83726e

Authored by Vasant Hegde
Committed by Benjamin Herrenschmidt
1 parent 654837e8fe

powerpc/powernv: Return secondary CPUs to firmware before FW update

Firmware update on PowerNV platform takes several minutes. During
this time one CPU is stuck in FW and the kernel complains about "soft
lockups".

This patch returns all secondary CPUs to firmware before starting
firmware update process.

[ Reworked a bit and cleaned up -- BenH ]

Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Showing 3 changed files with 66 additions and 7 deletions Side-by-side Diff

arch/powerpc/include/asm/opal.h
... ... @@ -916,6 +916,7 @@
916 916 extern unsigned long opal_get_boot_time(void);
917 917 extern void opal_nvram_init(void);
918 918 extern void opal_flash_init(void);
  919 +extern void opal_flash_term_callback(void);
919 920 extern int opal_elog_init(void);
920 921 extern void opal_platform_dump_init(void);
921 922 extern void opal_sys_param_init(void);
arch/powerpc/platforms/powernv/opal-flash.c
... ... @@ -20,6 +20,7 @@
20 20 #include <linux/mm.h>
21 21 #include <linux/vmalloc.h>
22 22 #include <linux/pagemap.h>
  23 +#include <linux/delay.h>
23 24  
24 25 #include <asm/opal.h>
25 26  
26 27  
... ... @@ -290,16 +291,52 @@
290 291 /* First entry address */
291 292 addr = __pa(list);
292 293  
293   - pr_alert("FLASH: Image is %u bytes\n", image_data.size);
294   - pr_alert("FLASH: Image update requested\n");
295   - pr_alert("FLASH: Image will be updated during system reboot\n");
296   - pr_alert("FLASH: This will take several minutes. Do not power off!\n");
297   -
298 294 flash:
299 295 rc = opal_update_flash(addr);
300 296  
301 297 invalid_img:
302 298 return rc;
  299 +}
  300 +
  301 +/* Return CPUs to OPAL before starting FW update */
  302 +static void flash_return_cpu(void *info)
  303 +{
  304 + int cpu = smp_processor_id();
  305 +
  306 + if (!cpu_online(cpu))
  307 + return;
  308 +
  309 + /* Disable IRQ */
  310 + hard_irq_disable();
  311 +
  312 + /* Return the CPU to OPAL */
  313 + opal_return_cpu();
  314 +}
  315 +
  316 +/* This gets called just before system reboots */
  317 +void opal_flash_term_callback(void)
  318 +{
  319 + struct cpumask mask;
  320 +
  321 + if (update_flash_data.status != FLASH_IMG_READY)
  322 + return;
  323 +
  324 + pr_alert("FLASH: Flashing new firmware\n");
  325 + pr_alert("FLASH: Image is %u bytes\n", image_data.size);
  326 + pr_alert("FLASH: Performing flash and reboot/shutdown\n");
  327 + pr_alert("FLASH: This will take several minutes. Do not power off!\n");
  328 +
  329 + /* Small delay to help getting the above message out */
  330 + msleep(500);
  331 +
  332 + /* Return secondary CPUs to firmware */
  333 + cpumask_copy(&mask, cpu_online_mask);
  334 + cpumask_clear_cpu(smp_processor_id(), &mask);
  335 + if (!cpumask_empty(&mask))
  336 + smp_call_function_many(&mask,
  337 + flash_return_cpu, NULL, false);
  338 + /* Hard disable interrupts */
  339 + hard_irq_disable();
303 340 }
304 341  
305 342 /*
arch/powerpc/platforms/powernv/setup.c
... ... @@ -98,11 +98,32 @@
98 98 of_node_put(root);
99 99 }
100 100  
  101 +static void pnv_prepare_going_down(void)
  102 +{
  103 + /*
  104 + * Disable all notifiers from OPAL, we can't
  105 + * service interrupts anymore anyway
  106 + */
  107 + opal_notifier_disable();
  108 +
  109 + /* Soft disable interrupts */
  110 + local_irq_disable();
  111 +
  112 + /*
  113 + * Return secondary CPUs to firwmare if a flash update
  114 + * is pending otherwise we will get all sort of error
  115 + * messages about CPU being stuck etc.. This will also
  116 + * have the side effect of hard disabling interrupts so
  117 + * past this point, the kernel is effectively dead.
  118 + */
  119 + opal_flash_term_callback();
  120 +}
  121 +
101 122 static void __noreturn pnv_restart(char *cmd)
102 123 {
103 124 long rc = OPAL_BUSY;
104 125  
105   - opal_notifier_disable();
  126 + pnv_prepare_going_down();
106 127  
107 128 while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
108 129 rc = opal_cec_reboot();
... ... @@ -119,7 +140,7 @@
119 140 {
120 141 long rc = OPAL_BUSY;
121 142  
122   - opal_notifier_disable();
  143 + pnv_prepare_going_down();
123 144  
124 145 while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
125 146 rc = opal_cec_power_down(0);