Path: blob/master/arch/powerpc/platforms/powernv/opal-memory-errors.c
26481 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* OPAL asynchronus Memory error handling support in PowerNV.3*4* Copyright 2013 IBM Corporation5* Author: Mahesh Salgaonkar <[email protected]>6*/78#undef DEBUG910#include <linux/kernel.h>11#include <linux/init.h>12#include <linux/of.h>13#include <linux/mm.h>14#include <linux/slab.h>1516#include <asm/machdep.h>17#include <asm/opal.h>18#include <asm/cputable.h>1920static int opal_mem_err_nb_init;21static LIST_HEAD(opal_memory_err_list);22static DEFINE_SPINLOCK(opal_mem_err_lock);2324struct OpalMsgNode {25struct list_head list;26struct opal_msg msg;27};2829static void handle_memory_error_event(struct OpalMemoryErrorData *merr_evt)30{31uint64_t paddr_start, paddr_end;3233pr_debug("%s: Retrieved memory error event, type: 0x%x\n",34__func__, merr_evt->type);35switch (merr_evt->type) {36case OPAL_MEM_ERR_TYPE_RESILIENCE:37paddr_start = be64_to_cpu(merr_evt->u.resilience.physical_address_start);38paddr_end = be64_to_cpu(merr_evt->u.resilience.physical_address_end);39break;40case OPAL_MEM_ERR_TYPE_DYN_DALLOC:41paddr_start = be64_to_cpu(merr_evt->u.dyn_dealloc.physical_address_start);42paddr_end = be64_to_cpu(merr_evt->u.dyn_dealloc.physical_address_end);43break;44default:45return;46}4748for (; paddr_start < paddr_end; paddr_start += PAGE_SIZE) {49memory_failure(paddr_start >> PAGE_SHIFT, 0);50}51}5253static void handle_memory_error(void)54{55unsigned long flags;56struct OpalMemoryErrorData *merr_evt;57struct OpalMsgNode *msg_node;5859spin_lock_irqsave(&opal_mem_err_lock, flags);60while (!list_empty(&opal_memory_err_list)) {61msg_node = list_entry(opal_memory_err_list.next,62struct OpalMsgNode, list);63list_del(&msg_node->list);64spin_unlock_irqrestore(&opal_mem_err_lock, flags);6566merr_evt = (struct OpalMemoryErrorData *)67&msg_node->msg.params[0];68handle_memory_error_event(merr_evt);69kfree(msg_node);70spin_lock_irqsave(&opal_mem_err_lock, flags);71}72spin_unlock_irqrestore(&opal_mem_err_lock, flags);73}7475static void mem_error_handler(struct work_struct *work)76{77handle_memory_error();78}7980static DECLARE_WORK(mem_error_work, mem_error_handler);8182/*83* opal_memory_err_event - notifier handler that queues up the opal message84* to be processed later.85*/86static int opal_memory_err_event(struct notifier_block *nb,87unsigned long msg_type, void *msg)88{89unsigned long flags;90struct OpalMsgNode *msg_node;9192if (msg_type != OPAL_MSG_MEM_ERR)93return 0;9495msg_node = kzalloc(sizeof(*msg_node), GFP_ATOMIC);96if (!msg_node) {97pr_err("MEMORY_ERROR: out of memory, Opal message event not"98"handled\n");99return -ENOMEM;100}101memcpy(&msg_node->msg, msg, sizeof(msg_node->msg));102103spin_lock_irqsave(&opal_mem_err_lock, flags);104list_add(&msg_node->list, &opal_memory_err_list);105spin_unlock_irqrestore(&opal_mem_err_lock, flags);106107schedule_work(&mem_error_work);108return 0;109}110111static struct notifier_block opal_mem_err_nb = {112.notifier_call = opal_memory_err_event,113.next = NULL,114.priority = 0,115};116117static int __init opal_mem_err_init(void)118{119int ret;120121if (!opal_mem_err_nb_init) {122ret = opal_message_notifier_register(123OPAL_MSG_MEM_ERR, &opal_mem_err_nb);124if (ret) {125pr_err("%s: Can't register OPAL event notifier (%d)\n",126__func__, ret);127return ret;128}129opal_mem_err_nb_init = 1;130}131return 0;132}133machine_device_initcall(powernv, opal_mem_err_init);134135136