powerpc/pseries: Add support for hotplug interrupt source
authorJohn Allen <jallen@linux.vnet.ibm.com>
Thu, 7 Jul 2016 15:03:44 +0000 (10:03 -0500)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 19 Jul 2016 10:12:30 +0000 (20:12 +1000)
Add handler for new hotplug interrupt. For memory and CPU hotplug events,
we will add the hotplug errorlog to the hotplug workqueue. Since PCI
hotplug is not currently supported in the kernel, PCI hotplug events are
written to the rtas_log_bug and are handled by rtas_errd.

Signed-off-by: John Allen <jallen@linux.vnet.ibm.com>
Reviewed-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/platforms/pseries/pseries.h
arch/powerpc/platforms/pseries/ras.c

index ddb9aa51aad6f49bbb67ea1afc85dba074863548..bba32853c468bc956dabe3e9a8c06b019cfbed06 100644 (file)
@@ -56,6 +56,8 @@ extern int dlpar_detach_node(struct device_node *);
 extern int dlpar_acquire_drc(u32 drc_index);
 extern int dlpar_release_drc(u32 drc_index);
 
+void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog,
+                        struct completion *hotplug_done, int *rc);
 #ifdef CONFIG_MEMORY_HOTPLUG
 int dlpar_memory(struct pseries_hp_errorlog *hp_elog);
 #else
index 9a3e27b863ce518451f7eb0ecd33b4f15760bb57..904a677208d1fc47188f4329a3bafdd6b31cda89 100644 (file)
@@ -43,6 +43,7 @@ static int ras_check_exception_token;
 /* EPOW events counter variable */
 static int num_epow_events;
 
+static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id);
 static irqreturn_t ras_epow_interrupt(int irq, void *dev_id);
 static irqreturn_t ras_error_interrupt(int irq, void *dev_id);
 
@@ -65,6 +66,14 @@ static int __init init_ras_IRQ(void)
                of_node_put(np);
        }
 
+       /* Hotplug Events */
+       np = of_find_node_by_path("/event-sources/hot-plug-events");
+       if (np != NULL) {
+               request_event_sources_irqs(np, ras_hotplug_interrupt,
+                                          "RAS_HOTPLUG");
+               of_node_put(np);
+       }
+
        /* EPOW Events */
        np = of_find_node_by_path("/event-sources/epow-events");
        if (np != NULL) {
@@ -190,6 +199,36 @@ static void rtas_parse_epow_errlog(struct rtas_error_log *log)
                num_epow_events++;
 }
 
+static irqreturn_t ras_hotplug_interrupt(int irq, void *dev_id)
+{
+       struct pseries_errorlog *pseries_log;
+       struct pseries_hp_errorlog *hp_elog;
+
+       spin_lock(&ras_log_buf_lock);
+
+       rtas_call(ras_check_exception_token, 6, 1, NULL,
+                 RTAS_VECTOR_EXTERNAL_INTERRUPT, virq_to_hw(irq),
+                 RTAS_HOTPLUG_EVENTS, 0, __pa(&ras_log_buf),
+                 rtas_get_error_log_max());
+
+       pseries_log = get_pseries_errorlog((struct rtas_error_log *)ras_log_buf,
+                                          PSERIES_ELOG_SECT_ID_HOTPLUG);
+       hp_elog = (struct pseries_hp_errorlog *)pseries_log->data;
+
+       /*
+        * Since PCI hotplug is not currently supported on pseries, put PCI
+        * hotplug events on the ras_log_buf to be handled by rtas_errd.
+        */
+       if (hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_MEM ||
+           hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU)
+               queue_hotplug_event(hp_elog, NULL, NULL);
+       else
+               log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);
+
+       spin_unlock(&ras_log_buf_lock);
+       return IRQ_HANDLED;
+}
+
 /* Handle environmental and power warning (EPOW) interrupts. */
 static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
 {