Skip to content

Commit 2196c6f

Browse files
Vasant Hegdeozbenh
authored andcommitted
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 <[email protected]> Signed-off-by: Benjamin Herrenschmidt <[email protected]>
1 parent 654837e commit 2196c6f

File tree

3 files changed

+66
-7
lines changed

3 files changed

+66
-7
lines changed

arch/powerpc/include/asm/opal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,7 @@ extern void opal_get_rtc_time(struct rtc_time *tm);
916916
extern unsigned long opal_get_boot_time(void);
917917
extern void opal_nvram_init(void);
918918
extern void opal_flash_init(void);
919+
extern void opal_flash_term_callback(void);
919920
extern int opal_elog_init(void);
920921
extern void opal_platform_dump_init(void);
921922
extern void opal_sys_param_init(void);

arch/powerpc/platforms/powernv/opal-flash.c

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/mm.h>
2121
#include <linux/vmalloc.h>
2222
#include <linux/pagemap.h>
23+
#include <linux/delay.h>
2324

2425
#include <asm/opal.h>
2526

@@ -290,18 +291,54 @@ static int opal_flash_update(int op)
290291
/* First entry address */
291292
addr = __pa(list);
292293

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-
298294
flash:
299295
rc = opal_update_flash(addr);
300296

301297
invalid_img:
302298
return rc;
303299
}
304300

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();
340+
}
341+
305342
/*
306343
* Show candidate image status
307344
*/

arch/powerpc/platforms/powernv/setup.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,32 @@ static void pnv_show_cpuinfo(struct seq_file *m)
9898
of_node_put(root);
9999
}
100100

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+
101122
static void __noreturn pnv_restart(char *cmd)
102123
{
103124
long rc = OPAL_BUSY;
104125

105-
opal_notifier_disable();
126+
pnv_prepare_going_down();
106127

107128
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
108129
rc = opal_cec_reboot();
@@ -119,7 +140,7 @@ static void __noreturn pnv_power_off(void)
119140
{
120141
long rc = OPAL_BUSY;
121142

122-
opal_notifier_disable();
143+
pnv_prepare_going_down();
123144

124145
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
125146
rc = opal_cec_power_down(0);

0 commit comments

Comments
 (0)