ChorusOS 5.0 Board Support Package Developer's Guide

Bus Exceptions

A hardened bus driver (usually the host bridge driver) will handle hardware bus exceptions to identify the bus address at fault. By invoking the associated driver's error handler, the hardened bus driver will propagate the appropriate error message upstream.

A hardened driver will not panic when its error handlers are invoked. This is considered as a device fault condition by a leaf driver, and is propagated to child drivers by a nexus driver.

In the ChorusOS Driver Framework a bus exception is reported by the nexus driver to a child driver through the error handler invocation. The error handler is specific to a mapped region: a driver specifies an error handler when calling its parent nexus driver to map a memory, I/O or DMA region. When an exception occurs, the bus driver analyzes the faulty bus address, detects the fault region and invokes the associated error handler.

Code Example 13-4 shows the Raven bus error interrupt handler. This handler manages errors at bus level and propagates warning of those errors to appropriate faulty device driver error (or event) handlers.


Example 13-4 Raven bus error handler

        /*
         * PowerPC "machine check" interrupt handler
         * It is called from DKI after context have been saved in stack.
         * This handler uses the RAVEN internal register to analyze and
         * dispatch bus errors to device error handlers.
         */
    static CpuIntrStatus
errHandler (RavenData* raven)
{
            PciBusError   error;
            PciMap*       pciMap;
            uint32_f      merad;
            uint16_f      merat;
   volatile uint8_f       merstReg;
            uint8_f       merst;
            uint8_f       overflow;
            KnIntrCtx*    intrCtx;
            CpuIntrStatus status = CPU_INTR_UNCLAIMED;
       /*
        * Read Raven MPC_MERST register ... and clear error bits that will
        * be handled
        */
   merst = merstReg = READ_REG_8(raven->regs.vaddr, MPC_MERST);
   WRITE_REG_8(raven->regs.vaddr, MPC_MERST, merstReg);

   overflow = merst & MPC_MERST_OVF;
   svIntrCtxGet(&intrCtx);
       /*
        * DATA PARITY ERROR and PCI SYSTEM ERROR are propagated as a
        * PCI_SYS_ERROR event, because the RAVEN does not latch any address
        * in this cases.
        */
   if (merst & (MPC_MERST_PERR | MPC_MERST_SERR)) {
       PciDev* pciDev;

       DKI_ERR(("%s: error -- (MC) pc=0x%08x lr=0x%08x sp=0x%08x\n",
                raven->path, intrCtx->pc, intrCtx->lr, intrCtx->r1));
       if (merst & MPC_MERST_PERR) {
           DKI_ERR(("%s: error -- PARITY ERROR detected\n", raven->path));
       }
       if (merst & MPC_MERST_SERR) {
           DKI_ERR(("%s: error -- SYSTEM ERROR detected\n", raven->path));
       }
       pciDev = raven->dev;
       while (pciDev) {
           if (pciDev->evtHandler) {
               pciDev->evtHandler(pciDev->cookie, PCI_SYS_ERROR, NULL);
           }
           pciDev = pciDev->next;
       }
       return CPU_INTR_CLAIMED;
   }

   if (overflow) {
       DKI_WARN(("%s: warning -- error overflow (0x%02x)\n",
                 raven->path, merst));
   }
       /*
        * Read latched fault address and cycle attributes
        */
   merad = READ_REG_32(raven->regs.vaddr, MPC_MERAD);
   merat = READ_REG_16(raven->regs.vaddr, MPC_MERAT);
       /*
        * PowerPC bus error: MERAT/MERAD contains PowerPC cycles attributes
        */
   if (merst & MPC_MERST_MATO) {
       error.code = PCI_ERR_TARGET_ABORT;
           /*
            * Search an existing map to which the latched address belong
            * and call the associated error handler.
            * DMA maps are in memMap list.
            */
       pciMap = raven->memMap;
       while (pciMap) {
           if ((pciMap->memChunk.paddr <= merad) && 
               (merad <= pciMap->memChunk.paddr + pciMap->memChunk.psize)) {
               error.offset = merad - pciMap->memChunk.paddr;
               pciMap->errHandler(pciMap->errCookie, &error);
               status = CPU_INTR_CLAIMED;
               break;
           }
           pciMap = pciMap->next;
       }
           /*
            * Save fault address in dar to raise a kernel exception
            */
       intrCtx->dar = merad;

       if (status == CPU_INTR_UNCLAIMED) {
         DKI_ERR(("%s: error -- (MC) pc=0x%08x lr=0x%08x sp=0x%08x\n",
                  raven->path, intrCtx->pc, intrCtx->lr, intrCtx->r1));
         DKI_ERR(("%s: error -- PowerPC timed-out 0x%08x (merat=0x%04x)\n",
                  raven->path, merad, merat));
         DKI_ERR(("%s: error -- from %s %s TT=0x%02x TSIZ=0x%01x\n",
                raven->path,
                (MPC_MERAT_MID(merat) == MPC_MID_RAVEN) ? "raven" : "cpu",
                (merat & MPC_MERAT_TBST) ? "burst" : "",
                merat & MPC_MERAT_TT,
                MPC_MERAT_TSIZ(merat)));
       }
       return status;
   }
       /*
        * PCI bus errors: MERAT/MERAD contains PCI cycle attributs
        */
   if (merst & MPC_MERST_RTA) {
       error.code = PCI_ERR_TARGET_ABORT;
   }else if (merst & MPC_MERST_SMA) {
       error.code = PCI_ERR_MASTER_ABORT;
   }
   switch (merat & MPC_MERAT_COMM) {
   case MPC_MERAT_IACK:
       DKI_ERR(("%s: error -- PCI IACK cycle\n", raven->path));
       break;
   case MPC_MERAT_CFG_READ:
   case MPC_MERAT_CFG_WRITE:
           /*
            * An error occured while accessing PCI configuration space
            */
       if ((merad == (raven->confAddr & ~0x3)) ||
           (merad == CONFIG_ADDR_TO_ADDR(raven->confAddr))) {
               /*
                * The latched error address matches the one currently 
                * accessed through a conf_load_xx operation.
                * Reset the accessed (confAddr) address to indicate
                * the operation failed.
                */
           raven->confAddr = 0;
           status = CPU_INTR_CLAIMED;
       } else {
               /*
                * The error is not due to our conf_xxx() operations !
                */
           DKI_ERR(("%s: error -- PCI Configuration cycle\n", raven->path));
       }
       break;
   case MPC_MERAT_IO_READ:
   case MPC_MERAT_IO_WRITE:
           /*
            * An error occured while accessing PCI I/O space
            * Search an existing map to which the latched address belong
            * and call the associated error handler
            */
       pciMap = raven->ioMap;
       while (pciMap) {
           if ((pciMap->first <= merad) && (merad <= pciMap->last)) {
               error.offset = merad - pciMap->first;
               pciMap->errHandler(pciMap->errCookie, &error);
               status = CPU_INTR_CLAIMED;
               break;
           }
           pciMap = pciMap->next;
       }
       break;
   case MPC_MERAT_MEM_READ:
   case MPC_MERAT_MEM_WRITE:
   case MPC_MERAT_MEM_READ_MULTI:
   case MPC_MERAT_MEM_READ_LINE:
   case MPC_MERAT_MEM_WRITE_INVAL:
           /*
            * An error occured while accessing PCI Memory space
            * Search an existing map to which the latched address belong
            * and call the associated error handler
            */
       pciMap = raven->memMap;
       while (pciMap) {
           if ((pciMap->first <= merad) && (merad <= pciMap->last)) {
               error.offset = merad - pciMap->first;
               pciMap->errHandler(pciMap->errCookie, &error);
               status = CPU_INTR_CLAIMED;
               break;
           }
           pciMap = pciMap->next;
       }
   }

   if (status == CPU_INTR_UNCLAIMED) {
     DKI_ERR(("%s: error -- (MC) pc=0x%08x lr=0x%08x sp=0x%08x\n",
               raven->path, intrCtx->pc, intrCtx->lr, intrCtx->r1));
    DKI_ERR(("%s: error -- (%d) PCI at 0x%08x merat=0x%04x merst=0x%02x\n",
               raven->path, error.code, merad, merat, merst));
     DKI_ERR(("%s: error -- from %s %s BYTE_EN=0x%02x\n",
             raven->path,
             (MPC_MERAT_MID(merat) == MPC_MID_RAVEN) ? "raven" : "cpu",
             (merat & MPC_MERAT_TBST) ? "write-posted" : "",
             merat & MPC_MERAT_BYTE_EN));
   }

   return status;
}

Refer to the ChorusOS man pages section 9DDI: Device Driver Interfaces for details about bus error handling interfaces.