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
 
   6  * Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved.
 
   9 #include <linux/types.h>
 
  10 #include <linux/interrupt.h>
 
  11 #include <linux/pci.h>
 
  12 #include <asm/delay.h>
 
  13 #include <asm/sn/sn_sal.h>
 
  15 #include <asm/sn/addrs.h>
 
  16 #include <asm/sn/shubio.h>
 
  17 #include <asm/sn/geo.h>
 
  18 #include "xtalk/xwidgetdev.h"
 
  19 #include "xtalk/hubdev.h"
 
  20 #include <asm/sn/bte.h>
 
  22 void hubiio_crb_error_handler(struct hubdev_info *hubdev_info);
 
  23 extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *,
 
  25 static irqreturn_t hub_eint_handler(int irq, void *arg, struct pt_regs *ep)
 
  27         struct hubdev_info *hubdev_info;
 
  28         struct ia64_sal_retval ret_stuff;
 
  33         hubdev_info = (struct hubdev_info *)arg;
 
  34         nasid = hubdev_info->hdi_nasid;
 
  35         SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
 
  36                         (u64) nasid, 0, 0, 0, 0, 0, 0);
 
  38         if ((int)ret_stuff.v0)
 
  39                 panic("hubii_eint_handler(): Fatal TIO Error");
 
  42                 if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
 
  43                         (void)hubiio_crb_error_handler(hubdev_info);
 
  45                 bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
 
  51  * Free the hub CRB "crbnum" which encountered an error.
 
  52  * Assumption is, error handling was successfully done,
 
  53  * and we now want to return the CRB back to Hub for normal usage.
 
  55  * In order to free the CRB, all that's needed is to de-allocate it
 
  58  *      No other processor is mucking around with the hub control register.
 
  59  *      So, upper layer has to single thread this.
 
  61 void hubiio_crb_free(struct hubdev_info *hubdev_info, int crbnum)
 
  66          * The hardware does NOT clear the mark bit, so it must get cleared
 
  67          * here to be sure the error is not processed twice.
 
  69         icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hubdev_info->hdi_nasid,
 
  72         REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICRB_B(crbnum),
 
  73                      icrbb.ii_icrb0_b_regval);
 
  75          * Deallocate the register wait till hub indicates it's done.
 
  77         REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum));
 
  78         while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND)
 
  84  * hubiio_crb_error_handler
 
  86  *      This routine gets invoked when a hub gets an error 
 
  87  *      interrupt. So, the routine is running in interrupt context
 
  88  *      at error interrupt level.
 
  90  *      It's responsible for identifying ALL the CRBs that are marked
 
  91  *      with error, and process them. 
 
  93  *      If you find the CRB that's marked with error, map this to the
 
  94  *      reason it caused error, and invoke appropriate error handler.
 
  96  *      XXX Be aware of the information in the context register.
 
  99  *      Use REMOTE_HUB_* macro instead of LOCAL_HUB_* so that the interrupt
 
 100  *      handler can be run on any node. (not necessarily the node 
 
 101  *      corresponding to the hub that encountered error).
 
 104 void hubiio_crb_error_handler(struct hubdev_info *hubdev_info)
 
 107         ii_icrb0_a_u_t icrba;   /* II CRB Register A */
 
 108         ii_icrb0_b_u_t icrbb;   /* II CRB Register B */
 
 109         ii_icrb0_c_u_t icrbc;   /* II CRB Register C */
 
 110         ii_icrb0_d_u_t icrbd;   /* II CRB Register D */
 
 111         ii_icrb0_e_u_t icrbe;   /* II CRB Register D */
 
 113         int num_errors = 0;     /* Num of errors handled */
 
 116         nasid = hubdev_info->hdi_nasid;
 
 119          * XXX - Add locking for any recovery actions
 
 122          * Scan through all CRBs in the Hub, and handle the errors
 
 123          * in any of the CRBs marked.
 
 125         for (i = 0; i < IIO_NUM_CRBS; i++) {
 
 126                 /* Check this crb entry to see if it is in error. */
 
 127                 icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i));
 
 129                 if (icrbb.b_mark == 0) {
 
 133                 icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i));
 
 135                 IOERROR_INIT(&ioerror);
 
 137                 /* read other CRB error registers. */
 
 138                 icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i));
 
 139                 icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
 
 140                 icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i));
 
 142                 IOERROR_SETVALUE(&ioerror, errortype, icrbb.b_ecode);
 
 144                 /* Check if this error is due to BTE operation,
 
 145                  * and handle it separately.
 
 148                     ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 ||
 
 149                       icrbb.b_initiator == IIO_ICRB_INIT_BTE1) &&
 
 150                      (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE ||
 
 151                       icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))) {
 
 156                                 bte_num = icrbc.c_btenum;
 
 157                         else    /* b_initiator bit 2 gives BTE number */
 
 158                                 bte_num = (icrbb.b_initiator & 0x4) >> 2;
 
 160                         hubiio_crb_free(hubdev_info, i);
 
 162                         bte_crb_error_handler(nasid_to_cnodeid(nasid), bte_num,
 
 163                                               i, &ioerror, icrbd.d_bteop);
 
 171  * Function     : hub_error_init
 
 172  * Purpose      : initialize the error handling requirements for a given hub.
 
 173  * Parameters   : cnode, the compact nodeid.
 
 174  * Assumptions  : Called only once per hub, either by a local cpu. Or by a
 
 175  *                      remote cpu, when this hub is headless.(cpuless)
 
 178 void hub_error_init(struct hubdev_info *hubdev_info)
 
 180         if (request_irq(SGI_II_ERROR, (void *)hub_eint_handler, SA_SHIRQ,
 
 181                         "SN_hub_error", (void *)hubdev_info))
 
 182                 printk("hub_error_init: Failed to request_irq for 0x%p\n",
 
 189  * Function     : ice_error_init
 
 190  * Purpose      : initialize the error handling requirements for a given tio.
 
 191  * Parameters   : cnode, the compact nodeid.
 
 192  * Assumptions  : Called only once per tio.
 
 195 void ice_error_init(struct hubdev_info *hubdev_info)
 
 198             (SGI_TIO_ERROR, (void *)hub_eint_handler, SA_SHIRQ, "SN_TIO_error",
 
 199              (void *)hubdev_info))
 
 200                 printk("ice_error_init: request_irq() error hubdev_info 0x%p\n",