Update ia64 patch to 2.5.69-030521, throwing away the parts included
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / sn / io / sn2 / bte_error.c
index 8e086e1..4ab2cb0 100644 (file)
@@ -1,10 +1,35 @@
-/* $Id: bte_error.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $
+/*
  *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
  */
 
 
 #include <asm/sn/sn2/shubio.h>
 #include <asm/sn/bte.h>
 
-/************************************************************************
- *                                                                     *
- *                      BTE ERROR RECOVERY                             *
- *                                                                     *
- * Given a BTE error, the node causing the error must do the following: *
- *    a) Clear all crbs relating to that BTE                           *
- *             1) Read CRBA value for crb in question                  *
- *             2) Mark CRB as VALID, store local physical              *
- *                address known to be good in the address field        *
- *                (bte_notification_targ is a known good local         *
- *                 address).                                           *
- *             3) Write CRBA                                           *
- *             4) Using ICCR, FLUSH the CRB, and wait for it to        *
- *                complete.                                            *
- *             ... BTE BUSY bit should now be clear (or at least       *
- *                 should be after ALL CRBs associated with the        *
- *                 transfer are complete.                              *
- *                                                                     *
- *    b) Re-enable BTE                                                 *
- *             1) Write IMEM with BTE Enable + XXX bits
- *             2) Write IECLR with BTE clear bits
- *             3) Clear IIDSR INT_SENT bits.
- *                                                                     *
- ************************************************************************/
-
-/* 
- * >>> bte_crb_error_handler needs to be broken into two parts.  The
- * first should cleanup the CRB.  The second should wait until all bte
- * related CRB's are complete and then do the error reset.
+
+/*
+ * Bte error handling is done in two parts.  The first captures
+ * any crb related errors.  Since there can be multiple crbs per
+ * interface and multiple interfaces active, we need to wait until
+ * all active crbs are completed.  This is the first job of the
+ * second part error handler.  When all bte related CRBs are cleanly
+ * completed, it resets the interfaces and gets them ready for new
+ * transfers to be queued.
  */
-void
-bte_crb_error_handler(devfs_handle_t hub_v, int btenum, 
-                     int crbnum, ioerror_t *ioe, int bteop)
+
+
+void bte_error_handler(unsigned long);
+
+
 /*
- * Function:   bte_crb_error_handler
- * Purpose:    Process a CRB for a specific HUB/BTE
- * Parameters: hub_v   - vertex of hub in HW graph
- *             btenum  - bte number on hub (0 == a, 1 == b)
- *             crbnum  - crb number being processed
- * Notes: 
- *     This routine assumes serialization at a higher level. A CRB 
- *     should not be processed more than once. The error recovery 
- *     follows the following sequence - if you change this, be real
- *     sure about what you are doing. 
- *
+ * First part error handler.  This is called whenever any error CRB interrupt
+ * is generated by the II.
  */
+void
+bte_crb_error_handler(vertex_hdl_t hub_v, int btenum,
+                     int crbnum, ioerror_t * ioe, int bteop)
 {
-        hubinfo_t      hinfo;
-       icrba_t         crba; 
-       icrbb_t         crbb; 
-       nasid_t         n;
-       hubreg_t        iidsr, imem, ieclr;
+       hubinfo_t hinfo;
+       struct bteinfo_s *bte;
+
 
        hubinfo_get(hub_v, &hinfo);
+       bte = &hinfo->h_nodepda->bte_if[btenum];
+
+       /*
+        * The caller has already figured out the error type, we save that
+        * in the bte handle structure for the thread excercising the
+        * interface to consume.
+        */
+       switch (ioe->ie_errortype) {
+       case IIO_ICRB_ECODE_PERR:
+               bte->bh_error = BTEFAIL_POISON;
+               break;
+       case IIO_ICRB_ECODE_WERR:
+               bte->bh_error = BTEFAIL_PROT;
+               break;
+       case IIO_ICRB_ECODE_AERR:
+               bte->bh_error = BTEFAIL_ACCESS;
+               break;
+       case IIO_ICRB_ECODE_TOUT:
+               bte->bh_error = BTEFAIL_TOUT;
+               break;
+       case IIO_ICRB_ECODE_XTERR:
+               bte->bh_error = BTEFAIL_XTERR;
+               break;
+       case IIO_ICRB_ECODE_DERR:
+               bte->bh_error = BTEFAIL_DIR;
+               break;
+       case IIO_ICRB_ECODE_PWERR:
+       case IIO_ICRB_ECODE_PRERR:
+               /* NO BREAK */
+       default:
+               bte->bh_error = BTEFAIL_ERROR;
+       }
 
+       bte->bte_error_count++;
+
+       BTE_PRINTK(("Got an error on cnode %d bte %d\n",
+                   bte->bte_cnode, bte->bte_num));
+       bte_error_handler((unsigned long) hinfo->h_nodepda);
+}
 
-       n = hinfo->h_nasid;
-       
 
+/*
+ * Second part error handler.  Wait until all BTE related CRBs are completed
+ * and then reset the interfaces.
+ */
+void
+bte_error_handler(unsigned long _nodepda)
+{
+       struct nodepda_s *err_nodepda = (struct nodepda_s *) _nodepda;
+       spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock;
+       struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
+       nasid_t nasid;
+       int i;
+       int valid_crbs;
+       unsigned long irq_flags;
+       volatile u64 *notify;
+       bte_result_t bh_error;
+       ii_imem_u_t imem;       /* II IMEM Register */
+       ii_icrb0_d_u_t icrbd;   /* II CRB Register D */
+       ii_ibcr_u_t ibcr;
+       ii_icmr_u_t icmr;
+
+
+       BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda,
+                   smp_processor_id()));
+
+       spin_lock_irqsave(recovery_lock, irq_flags);
+
+       if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) &&
+           (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) {
+               BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda,
+                           smp_processor_id()));
+               spin_unlock_irqrestore(recovery_lock, irq_flags);
+               return;
+       }
        /*
-        * The following 10 lines (or so) are adapted from IRIXs
-        * bte_crb_error function.  No clear documentation tells
-        * why the crb needs to complete normally in order for
-        * the BTE to resume normal operations.  This first step
-        * appears vital!
+        * Lock all interfaces on this node to prevent new transfers
+        * from being queued.
         */
+       for (i = 0; i < BTES_PER_NODE; i++) {
+               if (err_nodepda->bte_if[i].cleanup_active) {
+                       continue;
+               }
+               spin_lock(&err_nodepda->bte_if[i].spinlock);
+               BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda,
+                           smp_processor_id(), i));
+               err_nodepda->bte_if[i].cleanup_active = 1;
+       }
+
+       /* Determine information about our hub */
+       nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
+
 
        /*
-        * Zero error and error code to prevent error_dump complaining
-        * about these CRBs. Copy the CRB to the notification line.
-        * The crb address is in shub format (physical address shifted
-        * right by cacheline size).
+        * A BTE transfer can use multiple CRBs.  We need to make sure
+        * that all the BTE CRBs are complete (or timed out) before
+        * attempting to clean up the error.  Resetting the BTE while
+        * there are still BTE CRBs active will hang the BTE.
+        * We should look at all the CRBs to see if they are allocated
+        * to the BTE and see if they are still active.  When none
+        * are active, we can continue with the cleanup.
+        *
+        * We also want to make sure that the local NI port is up.
+        * When a router resets the NI port can go down, while it
+        * goes through the LLP handshake, but then comes back up.
         */
-       crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum));
-       crbb.b_error=0;
-       crbb.b_ecode=0;
-       REMOTE_HUB_S(n, IIO_ICRB_B(crbnum), crbb.ii_icrb0_b_regval);
-
-       crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum));
-       crba.a_addr = TO_PHYS((u64)&nodepda->bte_if[btenum].notify) >> 3;
-       crba.a_valid = 1;
-       REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval);
-
-       REMOTE_HUB_S(n, IIO_ICCR, 
-                    IIO_ICCR_PENDING | IIO_ICCR_CMD_FLUSH | crbnum);
-
-       while (REMOTE_HUB_L(n, IIO_ICCR) & IIO_ICCR_PENDING)
-           ;
-
-
-       /* Terminate the BTE. */
-       /* >>> The other bte transfer will need to be restarted. */
-       HUB_L((shubreg_t *)((nodepda->bte_if[btenum].bte_base_addr +
-                      IIO_IBCT0 - IIO_IBLS0)));
-
-       imem = REMOTE_HUB_L(n, IIO_IMEM);
-       ieclr = REMOTE_HUB_L(n, IIO_IECLR);
-       if (btenum == 0) {
-               imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD;
-               ieclr|= IECLR_BTE0;
-       } else {
-               imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD;
-               ieclr|= IECLR_BTE1;
+       icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR);
+       if (icmr.ii_icmr_fld_s.i_crb_mark != 0) {
+               /*
+                * There are errors which still need to be cleaned up by
+                * hubiio_crb_error_handler
+                */
+               mod_timer(recovery_timer, HZ * 5);
+               BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda,
+                           smp_processor_id()));
+               spin_unlock_irqrestore(recovery_lock, irq_flags);
+               return;
        }
-       REMOTE_HUB_S(n, IIO_IMEM, imem);
-       REMOTE_HUB_S(n, IIO_IECLR, ieclr);
-               
-       iidsr  = REMOTE_HUB_L(n, IIO_IIDSR);
-       iidsr &= ~IIO_IIDSR_SENT_MASK;
-       iidsr |= IIO_IIDSR_ENB_MASK;
-       REMOTE_HUB_S(n, IIO_IIDSR, iidsr);
+       if (icmr.ii_icmr_fld_s.i_crb_vld != 0) {
 
+               valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld;
 
-       bte_reset_nasid(n);
+               for (i = 0; i < IIO_NUM_CRBS; i++) {
+                       if (!((1 << i) & valid_crbs)) {
+                               /* This crb was not marked as valid, ignore */
+                               continue;
+                       }
+                       icrbd.ii_icrb0_d_regval =
+                           REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
+                       if (icrbd.d_bteop) {
+                               mod_timer(recovery_timer, HZ * 5);
+                               BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n",
+                                        err_nodepda, smp_processor_id(), i));
+                               spin_unlock_irqrestore(recovery_lock,
+                                                      irq_flags);
+                               return;
+                       }
+               }
+       }
 
-       *nodepda->bte_if[btenum].most_rcnt_na = IBLS_ERROR;
-}
 
+       BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda,
+                   smp_processor_id()));
+       /* Reenable both bte interfaces */
+       imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM);
+       imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1;
+       REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval);
+
+       /* Reinitialize both BTE state machines. */
+       ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR);
+       ibcr.ii_ibcr_fld_s.i_soft_reset = 1;
+       REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval);
+
+
+       for (i = 0; i < BTES_PER_NODE; i++) {
+               bh_error = err_nodepda->bte_if[i].bh_error;
+               if (bh_error != BTE_SUCCESS) {
+                       /* There is an error which needs to be notified */
+                       notify = err_nodepda->bte_if[i].most_rcnt_na;
+                       BTE_PRINTK(("cnode %d bte %d error=0x%lx\n",
+                                   err_nodepda->bte_if[i].bte_cnode,
+                                   err_nodepda->bte_if[i].bte_num,
+                                   IBLS_ERROR | (u64) bh_error));
+                       *notify = IBLS_ERROR | bh_error;
+                       err_nodepda->bte_if[i].bh_error = BTE_SUCCESS;
+               }
+
+               err_nodepda->bte_if[i].cleanup_active = 0;
+               BTE_PRINTK(("eh:%p:%d Unlocked %d\n", err_nodepda,
+                           smp_processor_id(), i));
+               spin_unlock(&pda->cpu_bte_if[i]->spinlock);
+       }
+
+       del_timer(recovery_timer);
+
+       spin_unlock_irqrestore(recovery_lock, irq_flags);
+}