linux/arch/x86/kernel/cpu/mcheck/mce-genpool.c
<<
>>
Prefs
   1/*
   2 * MCE event pool management in MCE context
   3 *
   4 * Copyright (C) 2015 Intel Corp.
   5 * Author: Chen, Gong <gong.chen@linux.intel.com>
   6 *
   7 * This file is licensed under GPLv2.
   8 */
   9#include <linux/smp.h>
  10#include <linux/mm.h>
  11#include <linux/genalloc.h>
  12#include <linux/llist.h>
  13#include "mce-internal.h"
  14
  15/*
  16 * printk() is not safe in MCE context. This is a lock-less memory allocator
  17 * used to save error information organized in a lock-less list.
  18 *
  19 * This memory pool is only to be used to save MCE records in MCE context.
  20 * MCE events are rare, so a fixed size memory pool should be enough. Use
  21 * 2 pages to save MCE events for now (~80 MCE records at most).
  22 */
  23#define MCE_POOLSZ      (2 * PAGE_SIZE)
  24
  25static struct gen_pool *mce_evt_pool;
  26static LLIST_HEAD(mce_event_llist);
  27static char gen_pool_buf[MCE_POOLSZ];
  28
  29void mce_gen_pool_process(void)
  30{
  31        struct llist_node *head;
  32        struct mce_evt_llist *node;
  33        struct mce *mce;
  34
  35        head = llist_del_all(&mce_event_llist);
  36        if (!head)
  37                return;
  38
  39        head = llist_reverse_order(head);
  40        llist_for_each_entry(node, head, llnode) {
  41                mce = &node->mce;
  42                atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
  43                gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node));
  44        }
  45}
  46
  47bool mce_gen_pool_empty(void)
  48{
  49        return llist_empty(&mce_event_llist);
  50}
  51
  52int mce_gen_pool_add(struct mce *mce)
  53{
  54        struct mce_evt_llist *node;
  55
  56        if (!mce_evt_pool)
  57                return -EINVAL;
  58
  59        node = (void *)gen_pool_alloc(mce_evt_pool, sizeof(*node));
  60        if (!node) {
  61                pr_warn_ratelimited("MCE records pool full!\n");
  62                return -ENOMEM;
  63        }
  64
  65        memcpy(&node->mce, mce, sizeof(*mce));
  66        llist_add(&node->llnode, &mce_event_llist);
  67
  68        return 0;
  69}
  70
  71static int mce_gen_pool_create(void)
  72{
  73        struct gen_pool *tmpp;
  74        int ret = -ENOMEM;
  75
  76        tmpp = gen_pool_create(ilog2(sizeof(struct mce_evt_llist)), -1);
  77        if (!tmpp)
  78                goto out;
  79
  80        ret = gen_pool_add(tmpp, (unsigned long)gen_pool_buf, MCE_POOLSZ, -1);
  81        if (ret) {
  82                gen_pool_destroy(tmpp);
  83                goto out;
  84        }
  85
  86        mce_evt_pool = tmpp;
  87
  88out:
  89        return ret;
  90}
  91
  92int mce_gen_pool_init(void)
  93{
  94        /* Just init mce_gen_pool once. */
  95        if (mce_evt_pool)
  96                return 0;
  97
  98        return mce_gen_pool_create();
  99}
 100