linux/arch/ia64/sn/kernel/huberror.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved.
   7 */
   8
   9#include <linux/types.h>
  10#include <linux/interrupt.h>
  11#include <asm/delay.h>
  12#include <asm/sn/sn_sal.h>
  13#include "ioerror.h"
  14#include <asm/sn/addrs.h>
  15#include <asm/sn/shubio.h>
  16#include <asm/sn/geo.h>
  17#include "xtalk/xwidgetdev.h"
  18#include "xtalk/hubdev.h"
  19#include <asm/sn/bte.h>
  20
  21void hubiio_crb_error_handler(struct hubdev_info *hubdev_info);
  22extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *,
  23                                  int);
  24static irqreturn_t hub_eint_handler(int irq, void *arg)
  25{
  26        struct hubdev_info *hubdev_info;
  27        struct ia64_sal_retval ret_stuff;
  28        nasid_t nasid;
  29
  30        ret_stuff.status = 0;
  31        ret_stuff.v0 = 0;
  32        hubdev_info = (struct hubdev_info *)arg;
  33        nasid = hubdev_info->hdi_nasid;
  34
  35        if (is_shub1()) {
  36                SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
  37                        (u64) nasid, 0, 0, 0, 0, 0, 0);
  38
  39                if ((int)ret_stuff.v0)
  40                        panic("%s: Fatal %s Error", __func__,
  41                                ((nasid & 1) ? "TIO" : "HUBII"));
  42
  43                if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
  44                        (void)hubiio_crb_error_handler(hubdev_info);
  45        } else
  46                if (nasid & 1) {        /* TIO errors */
  47                        SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
  48                                (u64) nasid, 0, 0, 0, 0, 0, 0);
  49
  50                        if ((int)ret_stuff.v0)
  51                                panic("%s: Fatal TIO Error", __func__);
  52                } else
  53                        bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
  54
  55        return IRQ_HANDLED;
  56}
  57
  58/*
  59 * Free the hub CRB "crbnum" which encountered an error.
  60 * Assumption is, error handling was successfully done,
  61 * and we now want to return the CRB back to Hub for normal usage.
  62 *
  63 * In order to free the CRB, all that's needed is to de-allocate it
  64 *
  65 * Assumption:
  66 *      No other processor is mucking around with the hub control register.
  67 *      So, upper layer has to single thread this.
  68 */
  69void hubiio_crb_free(struct hubdev_info *hubdev_info, int crbnum)
  70{
  71        ii_icrb0_b_u_t icrbb;
  72
  73        /*
  74         * The hardware does NOT clear the mark bit, so it must get cleared
  75         * here to be sure the error is not processed twice.
  76         */
  77        icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hubdev_info->hdi_nasid,
  78                                               IIO_ICRB_B(crbnum));
  79        icrbb.b_mark = 0;
  80        REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICRB_B(crbnum),
  81                     icrbb.ii_icrb0_b_regval);
  82        /*
  83         * Deallocate the register wait till hub indicates it's done.
  84         */
  85        REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum));
  86        while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND)
  87                cpu_relax();
  88
  89}
  90
  91/*
  92 * hubiio_crb_error_handler
  93 *
  94 *      This routine gets invoked when a hub gets an error 
  95 *      interrupt. So, the routine is running in interrupt context
  96 *      at error interrupt level.
  97 * Action:
  98 *      It's responsible for identifying ALL the CRBs that are marked
  99 *      with error, and process them. 
 100 *      
 101 *      If you find the CRB that's marked with error, map this to the
 102 *      reason it caused error, and invoke appropriate error handler.
 103 *
 104 *      XXX Be aware of the information in the context register.
 105 *
 106 * NOTE:
 107 *      Use REMOTE_HUB_* macro instead of LOCAL_HUB_* so that the interrupt
 108 *      handler can be run on any node. (not necessarily the node 
 109 *      corresponding to the hub that encountered error).
 110 */
 111
 112void hubiio_crb_error_handler(struct hubdev_info *hubdev_info)
 113{
 114        nasid_t nasid;
 115        ii_icrb0_a_u_t icrba;   /* II CRB Register A */
 116        ii_icrb0_b_u_t icrbb;   /* II CRB Register B */
 117        ii_icrb0_c_u_t icrbc;   /* II CRB Register C */
 118        ii_icrb0_d_u_t icrbd;   /* II CRB Register D */
 119        ii_icrb0_e_u_t icrbe;   /* II CRB Register D */
 120        int i;
 121        int num_errors = 0;     /* Num of errors handled */
 122        ioerror_t ioerror;
 123
 124        nasid = hubdev_info->hdi_nasid;
 125
 126        /*
 127         * XXX - Add locking for any recovery actions
 128         */
 129        /*
 130         * Scan through all CRBs in the Hub, and handle the errors
 131         * in any of the CRBs marked.
 132         */
 133        for (i = 0; i < IIO_NUM_CRBS; i++) {
 134                /* Check this crb entry to see if it is in error. */
 135                icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i));
 136
 137                if (icrbb.b_mark == 0) {
 138                        continue;
 139                }
 140
 141                icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i));
 142
 143                IOERROR_INIT(&ioerror);
 144
 145                /* read other CRB error registers. */
 146                icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i));
 147                icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
 148                icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i));
 149
 150                IOERROR_SETVALUE(&ioerror, errortype, icrbb.b_ecode);
 151
 152                /* Check if this error is due to BTE operation,
 153                 * and handle it separately.
 154                 */
 155                if (icrbd.d_bteop ||
 156                    ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 ||
 157                      icrbb.b_initiator == IIO_ICRB_INIT_BTE1) &&
 158                     (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE ||
 159                      icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))) {
 160
 161                        int bte_num;
 162
 163                        if (icrbd.d_bteop)
 164                                bte_num = icrbc.c_btenum;
 165                        else    /* b_initiator bit 2 gives BTE number */
 166                                bte_num = (icrbb.b_initiator & 0x4) >> 2;
 167
 168                        hubiio_crb_free(hubdev_info, i);
 169
 170                        bte_crb_error_handler(nasid_to_cnodeid(nasid), bte_num,
 171                                              i, &ioerror, icrbd.d_bteop);
 172                        num_errors++;
 173                        continue;
 174                }
 175        }
 176}
 177
 178/*
 179 * Function     : hub_error_init
 180 * Purpose      : initialize the error handling requirements for a given hub.
 181 * Parameters   : cnode, the compact nodeid.
 182 * Assumptions  : Called only once per hub, either by a local cpu. Or by a
 183 *                      remote cpu, when this hub is headless.(cpuless)
 184 * Returns      : None
 185 */
 186void hub_error_init(struct hubdev_info *hubdev_info)
 187{
 188
 189        if (request_irq(SGI_II_ERROR, hub_eint_handler, IRQF_SHARED,
 190                        "SN_hub_error", hubdev_info)) {
 191                printk(KERN_ERR "hub_error_init: Failed to request_irq for 0x%p\n",
 192                    hubdev_info);
 193                return;
 194        }
 195        sn_set_err_irq_affinity(SGI_II_ERROR);
 196}
 197
 198
 199/*
 200 * Function     : ice_error_init
 201 * Purpose      : initialize the error handling requirements for a given tio.
 202 * Parameters   : cnode, the compact nodeid.
 203 * Assumptions  : Called only once per tio.
 204 * Returns      : None
 205 */
 206void ice_error_init(struct hubdev_info *hubdev_info)
 207{
 208
 209        if (request_irq
 210            (SGI_TIO_ERROR, (void *)hub_eint_handler, IRQF_SHARED, "SN_TIO_error",
 211             (void *)hubdev_info)) {
 212                printk("ice_error_init: request_irq() error hubdev_info 0x%p\n",
 213                       hubdev_info);
 214                return;
 215        }
 216        sn_set_err_irq_affinity(SGI_TIO_ERROR);
 217}
 218
 219