root/drivers/infiniband/hw/mthca/mthca_catas.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. catas_reset
  2. handle_catas
  3. poll_catas
  4. mthca_start_catas_poll
  5. mthca_stop_catas_poll
  6. mthca_catas_init
  7. mthca_catas_cleanup

   1 /*
   2  * Copyright (c) 2005 Cisco Systems.  All rights reserved.
   3  *
   4  * This software is available to you under a choice of one of two
   5  * licenses.  You may choose to be licensed under the terms of the GNU
   6  * General Public License (GPL) Version 2, available from the file
   7  * COPYING in the main directory of this source tree, or the
   8  * OpenIB.org BSD license below:
   9  *
  10  *     Redistribution and use in source and binary forms, with or
  11  *     without modification, are permitted provided that the following
  12  *     conditions are met:
  13  *
  14  *      - Redistributions of source code must retain the above
  15  *        copyright notice, this list of conditions and the following
  16  *        disclaimer.
  17  *
  18  *      - Redistributions in binary form must reproduce the above
  19  *        copyright notice, this list of conditions and the following
  20  *        disclaimer in the documentation and/or other materials
  21  *        provided with the distribution.
  22  *
  23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30  * SOFTWARE.
  31  */
  32 
  33 #include <linux/jiffies.h>
  34 #include <linux/module.h>
  35 #include <linux/timer.h>
  36 #include <linux/workqueue.h>
  37 
  38 #include "mthca_dev.h"
  39 
  40 enum {
  41         MTHCA_CATAS_POLL_INTERVAL       = 5 * HZ,
  42 
  43         MTHCA_CATAS_TYPE_INTERNAL       = 0,
  44         MTHCA_CATAS_TYPE_UPLINK         = 3,
  45         MTHCA_CATAS_TYPE_DDR            = 4,
  46         MTHCA_CATAS_TYPE_PARITY         = 5,
  47 };
  48 
  49 static DEFINE_SPINLOCK(catas_lock);
  50 
  51 static LIST_HEAD(catas_list);
  52 static struct workqueue_struct *catas_wq;
  53 static struct work_struct catas_work;
  54 
  55 static int catas_reset_disable;
  56 module_param_named(catas_reset_disable, catas_reset_disable, int, 0644);
  57 MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero");
  58 
  59 static void catas_reset(struct work_struct *work)
  60 {
  61         struct mthca_dev *dev, *tmpdev;
  62         LIST_HEAD(tlist);
  63         int ret;
  64 
  65         mutex_lock(&mthca_device_mutex);
  66 
  67         spin_lock_irq(&catas_lock);
  68         list_splice_init(&catas_list, &tlist);
  69         spin_unlock_irq(&catas_lock);
  70 
  71         list_for_each_entry_safe(dev, tmpdev, &tlist, catas_err.list) {
  72                 struct pci_dev *pdev = dev->pdev;
  73                 ret = __mthca_restart_one(dev->pdev);
  74                 /* 'dev' now is not valid */
  75                 if (ret)
  76                         printk(KERN_ERR "mthca %s: Reset failed (%d)\n",
  77                                pci_name(pdev), ret);
  78                 else {
  79                         struct mthca_dev *d = pci_get_drvdata(pdev);
  80                         mthca_dbg(d, "Reset succeeded\n");
  81                 }
  82         }
  83 
  84         mutex_unlock(&mthca_device_mutex);
  85 }
  86 
  87 static void handle_catas(struct mthca_dev *dev)
  88 {
  89         struct ib_event event;
  90         unsigned long flags;
  91         const char *type;
  92         int i;
  93 
  94         event.device = &dev->ib_dev;
  95         event.event  = IB_EVENT_DEVICE_FATAL;
  96         event.element.port_num = 0;
  97         dev->active = false;
  98 
  99         ib_dispatch_event(&event);
 100 
 101         switch (swab32(readl(dev->catas_err.map)) >> 24) {
 102         case MTHCA_CATAS_TYPE_INTERNAL:
 103                 type = "internal error";
 104                 break;
 105         case MTHCA_CATAS_TYPE_UPLINK:
 106                 type = "uplink bus error";
 107                 break;
 108         case MTHCA_CATAS_TYPE_DDR:
 109                 type = "DDR data error";
 110                 break;
 111         case MTHCA_CATAS_TYPE_PARITY:
 112                 type = "internal parity error";
 113                 break;
 114         default:
 115                 type = "unknown error";
 116                 break;
 117         }
 118 
 119         mthca_err(dev, "Catastrophic error detected: %s\n", type);
 120         for (i = 0; i < dev->catas_err.size; ++i)
 121                 mthca_err(dev, "  buf[%02x]: %08x\n",
 122                           i, swab32(readl(dev->catas_err.map + i)));
 123 
 124         if (catas_reset_disable)
 125                 return;
 126 
 127         spin_lock_irqsave(&catas_lock, flags);
 128         list_add(&dev->catas_err.list, &catas_list);
 129         queue_work(catas_wq, &catas_work);
 130         spin_unlock_irqrestore(&catas_lock, flags);
 131 }
 132 
 133 static void poll_catas(struct timer_list *t)
 134 {
 135         struct mthca_dev *dev = from_timer(dev, t, catas_err.timer);
 136         int i;
 137 
 138         for (i = 0; i < dev->catas_err.size; ++i)
 139                 if (readl(dev->catas_err.map + i)) {
 140                         handle_catas(dev);
 141                         return;
 142                 }
 143 
 144         mod_timer(&dev->catas_err.timer,
 145                   round_jiffies(jiffies + MTHCA_CATAS_POLL_INTERVAL));
 146 }
 147 
 148 void mthca_start_catas_poll(struct mthca_dev *dev)
 149 {
 150         phys_addr_t addr;
 151 
 152         timer_setup(&dev->catas_err.timer, poll_catas, 0);
 153         dev->catas_err.map  = NULL;
 154 
 155         addr = pci_resource_start(dev->pdev, 0) +
 156                 ((pci_resource_len(dev->pdev, 0) - 1) &
 157                  dev->catas_err.addr);
 158 
 159         dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4);
 160         if (!dev->catas_err.map) {
 161                 mthca_warn(dev, "couldn't map catastrophic error region "
 162                            "at 0x%llx/0x%x\n", (unsigned long long) addr,
 163                            dev->catas_err.size * 4);
 164                 return;
 165         }
 166 
 167         dev->catas_err.timer.expires  = jiffies + MTHCA_CATAS_POLL_INTERVAL;
 168         INIT_LIST_HEAD(&dev->catas_err.list);
 169         add_timer(&dev->catas_err.timer);
 170 }
 171 
 172 void mthca_stop_catas_poll(struct mthca_dev *dev)
 173 {
 174         del_timer_sync(&dev->catas_err.timer);
 175 
 176         if (dev->catas_err.map)
 177                 iounmap(dev->catas_err.map);
 178 
 179         spin_lock_irq(&catas_lock);
 180         list_del(&dev->catas_err.list);
 181         spin_unlock_irq(&catas_lock);
 182 }
 183 
 184 int __init mthca_catas_init(void)
 185 {
 186         INIT_WORK(&catas_work, catas_reset);
 187 
 188         catas_wq = alloc_ordered_workqueue("mthca_catas", WQ_MEM_RECLAIM);
 189         if (!catas_wq)
 190                 return -ENOMEM;
 191 
 192         return 0;
 193 }
 194 
 195 void mthca_catas_cleanup(void)
 196 {
 197         destroy_workqueue(catas_wq);
 198 }

/* [<][>][^][v][top][bottom][index][help] */