root/usr/src/uts/common/io/1394/adapters/hci1394_ohci.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 * Copyright (c) 2016 by Delphix. All rights reserved.
 */

/*
 * hci1394_ohci.c
 *    Provides access routines to the OpenHCI HW.
 */

#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/modctl.h>
#include <sys/sunddi.h>
#include <sys/types.h>
#include <sys/mkdev.h>
#include <sys/kmem.h>
#include <sys/pci.h>

#include <sys/1394/adapters/hci1394.h>
#include <sys/1394/adapters/hci1394_extern.h>


/*
 * Data swap macros used to swap config rom data that is going to be placed
 * in OpenHCI registers.  The config rom is treated like a byte stream.  When
 * the services layer calls into us to update the config rom, they pass us a
 * byte stream of data.  This works well except for the the fact that the
 * hardware uses its internal registers for the first 5 quadlets.  We have to
 * copy the cfgrom header and bus options into their corresponding OpenHCI
 * registers.  On an x86 machine, this means we have to byte swap them first.
 */
#ifdef _LITTLE_ENDIAN
#define OHCI_SWAP32(DATA)       (ddi_swap32(DATA))
#else
#define OHCI_SWAP32(DATA)       (DATA)
#endif


static int hci1394_ohci_selfid_init(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_cfgrom_init(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_chip_init(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_phy_resume(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_1394a_init(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_1394a_resume(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_phy_read_no_lock(hci1394_ohci_handle_t ohci_hdl,
    uint_t address, uint_t *data);
static int hci1394_ohci_phy_write_no_lock(hci1394_ohci_handle_t ohci_hdl,
    uint_t address, uint_t data);


/*
 * hci1394_ohci_init()
 *    Initialize the OpenHCI hardware.
 */
int
hci1394_ohci_init(hci1394_state_t *soft_state, hci1394_drvinfo_t *drvinfo,
    hci1394_ohci_handle_t *ohci_hdl)
{
        int status;
        uint32_t version;
        hci1394_ohci_t *ohci;
#if defined(__x86)
        uint16_t cmdreg;
#endif


        ASSERT(ohci_hdl != NULL);

        /* alloc the space for ohci */
        ohci = kmem_alloc(sizeof (hci1394_ohci_t), KM_SLEEP);
        *ohci_hdl = ohci;

        /*
         * Start with the cycle timer rollover interrupt disabled.  When it is
         * enabled, we will get an interrupt every 64 seconds, even if we have
         * nothing plugged into the bus.  This interrupt is used to keep track
         * of the bus time.  We will enable the interrupt when the bus manager
         * writes to the bus_time CSR register (Currently there are not known
         * implementations that write to the bus_time register)
         */
        ohci->ohci_bustime_enabled = B_FALSE;
        ohci->ohci_bustime_count = 0;

        ohci->ohci_set_root_holdoff = B_FALSE;
        ohci->ohci_set_gap_count = B_FALSE;
        ohci->ohci_gap_count = 0;

        mutex_init(&ohci->ohci_mutex, NULL, MUTEX_DRIVER,
            drvinfo->di_iblock_cookie);

        /* Map OpenHCI Registers */
        status = ddi_regs_map_setup(drvinfo->di_dip, OHCI_REG_SET,
            (caddr_t *)&ohci->ohci_regs, 0, 0, &drvinfo->di_reg_attr,
            &ohci->ohci_reg_handle);
        if (status != DDI_SUCCESS) {
                mutex_destroy(&ohci->ohci_mutex);
                kmem_free(ohci, sizeof (hci1394_ohci_t));
                *ohci_hdl = NULL;
                return (DDI_FAILURE);
        }

        ohci->soft_state = soft_state;
        ohci->ohci_drvinfo = drvinfo;

        /*
         * make sure PCI Master and PCI Memory Access are enabled on x86
         * platforms. This may not be the case if plug and play OS is
         * set in the BIOS
         */
#if defined(__x86)
        cmdreg = pci_config_get16(soft_state->pci_config, PCI_CONF_COMM);
        if ((cmdreg & (PCI_COMM_MAE | PCI_COMM_ME)) != (PCI_COMM_MAE |
            PCI_COMM_ME)) {
                cmdreg |= PCI_COMM_MAE | PCI_COMM_ME;
                pci_config_put16(soft_state->pci_config, PCI_CONF_COMM, cmdreg);
        }
#endif

        /*
         * Initialize the openHCI chip.  This is broken out because we need to
         * do this when resuming too.
         */
        status = hci1394_ohci_chip_init(ohci);
        if (status != DDI_SUCCESS) {
                ddi_regs_map_free(&ohci->ohci_reg_handle);
                mutex_destroy(&ohci->ohci_mutex);
                kmem_free(ohci, sizeof (hci1394_ohci_t));
                *ohci_hdl = NULL;
                return (DDI_FAILURE);
        }

        /* Init the 1394 PHY */
        status = hci1394_ohci_phy_init(ohci);
        if (status != DDI_SUCCESS) {
                (void) hci1394_ohci_soft_reset(ohci);
                ddi_regs_map_free(&ohci->ohci_reg_handle);
                mutex_destroy(&ohci->ohci_mutex);
                kmem_free(ohci, sizeof (hci1394_ohci_t));
                *ohci_hdl = NULL;
                return (DDI_FAILURE);
        }

        /* Init 1394a features if present */
        if (ohci->ohci_phy == H1394_PHY_1394A) {
                status = hci1394_ohci_1394a_init(ohci);
                if (status != DDI_SUCCESS) {
                        (void) hci1394_ohci_soft_reset(ohci);
                        ddi_regs_map_free(&ohci->ohci_reg_handle);
                        mutex_destroy(&ohci->ohci_mutex);
                        kmem_free(ohci, sizeof (hci1394_ohci_t));
                        *ohci_hdl = NULL;
                        return (DDI_FAILURE);
                }
        }

        /* save away guid, phy type, and vendor info */
        soft_state->halinfo.guid = hci1394_ohci_guid(ohci);
        soft_state->halinfo.phy = ohci->ohci_phy;
        soft_state->vendor_info.ohci_vendor_id =
            ddi_get32(ohci->ohci_reg_handle, &ohci->ohci_regs->vendor_id);
        version = ddi_get32(ohci->ohci_reg_handle, &ohci->ohci_regs->version);
        soft_state->vendor_info.ohci_version = version;

        /* We do not support version < 1.0 */
        if (OHCI_VERSION(version) == 0) {
                cmn_err(CE_NOTE,
                    "hci1394(%d): OpenHCI version %x.%x is not supported",
                    drvinfo->di_instance, OHCI_VERSION(version),
                    OHCI_REVISION(version));
                (void) hci1394_ohci_soft_reset(ohci);
                ddi_regs_map_free(&ohci->ohci_reg_handle);
                mutex_destroy(&ohci->ohci_mutex);
                kmem_free(ohci, sizeof (hci1394_ohci_t));
                *ohci_hdl = NULL;
                return (DDI_FAILURE);
        }

        /* Initialize the selfid buffer */
        status = hci1394_ohci_selfid_init(ohci);
        if (status != DDI_SUCCESS) {
                (void) hci1394_ohci_soft_reset(ohci);
                ddi_regs_map_free(&ohci->ohci_reg_handle);
                mutex_destroy(&ohci->ohci_mutex);
                kmem_free(ohci, sizeof (hci1394_ohci_t));
                *ohci_hdl = NULL;
                return (DDI_FAILURE);
        }

        /* Initialize the config rom buffer */
        status = hci1394_ohci_cfgrom_init(ohci);
        if (status != DDI_SUCCESS) {
                (void) hci1394_ohci_soft_reset(ohci);
                hci1394_buf_free(&ohci->ohci_selfid_handle);
                ddi_regs_map_free(&ohci->ohci_reg_handle);
                mutex_destroy(&ohci->ohci_mutex);
                kmem_free(ohci, sizeof (hci1394_ohci_t));
                *ohci_hdl = NULL;
                return (DDI_FAILURE);
        }

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_fini()
 *    Cleanup after OpenHCI init.  This should be called during detach.
 */
void
hci1394_ohci_fini(hci1394_ohci_handle_t *ohci_hdl)
{
        hci1394_ohci_t *ohci;


        ASSERT(ohci_hdl != NULL);

        ohci = *ohci_hdl;

        /* reset chip */
        (void) hci1394_ohci_soft_reset(ohci);

        /* Free config rom space */
        hci1394_buf_free(&ohci->ohci_cfgrom_handle);

        /* Free selfid buffer space */
        hci1394_buf_free(&ohci->ohci_selfid_handle);

        /* Free up the OpenHCI registers */
        ddi_regs_map_free(&ohci->ohci_reg_handle);

        mutex_destroy(&ohci->ohci_mutex);

        /* Free the OpenHCI state space */
        kmem_free(ohci, sizeof (hci1394_ohci_t));
        *ohci_hdl = NULL;
}


/*
 * hci1394_ohci_chip_init()
 *    Initialize the OpenHCI registers.  This contains the bulk of the initial
 *    register setup.
 */
static int
hci1394_ohci_chip_init(hci1394_ohci_handle_t ohci_hdl)
{
        int status;


        ASSERT(ohci_hdl != NULL);

        /* Reset 1394 OHCI HW */
        status = hci1394_ohci_soft_reset(ohci_hdl);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        /*
         * Setup Host Control Register. The software reset does not put all
         * registers in a known state. The Host Control Register is one of these
         * registers. First make sure noByteSwapData and postedWriteEnable and
         * are cleared.
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->hc_ctrl_clr, OHCI_HC_NO_BSWAP |
            OHCI_HC_POSTWR_ENBL);

        /*
         * the determination if we should swap data is made during the PCI
         * initialization.
         */
        if (ohci_hdl->soft_state->swap_data == B_FALSE) {
                /*
                 * most hba's don't swap data.  It will be swapped in the
                 * global swap for SPARC.  Enable Link Power(LPS). Enable
                 * Posted Writes
                 */
                ddi_put32(ohci_hdl->ohci_reg_handle,
                    &ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_NO_BSWAP |
                    OHCI_HC_LPS | OHCI_HC_POSTWR_ENBL);
        } else {
                /*
                 * Swap Data. Enable Link Power(LPS). Enable Posted Writes
                 */
                ddi_put32(ohci_hdl->ohci_reg_handle,
                    &ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_LPS |
                    OHCI_HC_POSTWR_ENBL);
        }

        /*
         * Wait for PHY to come up. There does not seem to be standard time for
         * how long wait for the PHY to come up. The problem is that the PHY
         * provides a clock to the link layer and if that is not stable, we
         * could get a PCI timeout error when reading/writing a phy register
         * (and maybe an OpenHCI register?)  This used to be set to 10mS which
         * works for just about every adapter we tested on.  We got a new TI
         * adapter which would crash the system once in a while if nothing
         * (1394 device) was pluged into the adapter.  Changing this delay to
         * 50mS made that problem go away. This value is set via a patchable
         * variable located in hci1394_extern.c
         */
        delay(drv_usectohz(hci1394_phy_stabilization_delay_uS));

        /* Clear Isochrounous receive multi-chan mode registers */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_multi_maskhi_clr, 0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_multi_masklo_clr, 0xFFFFFFFF);

        /*
         * Setup async retry on busy or ack_data_error
         *   secondlimit = 0 <= bits 31-29
         *   cycleLimit = 0 <= bits 28-16
         *   maxPhysRespRetries = 0 <= bits 11-8
         *   maxARRespRetries = 0 <= bits 7-4
         *   maxATReqRetries = 2 <= bits 3-0
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_retries, 0x00000002);

        /*
         * Setup Link Control
         *   Enable cycleMaster, cycleTimerEnable, and rcvPhyPkt.
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->link_ctrl_clr, 0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->link_ctrl_set, OHCI_LC_CYC_MAST |
            OHCI_LC_CTIME_ENBL | OHCI_LC_RCV_PHY);

        /*
         * Set the Physical address map boundary to 0x0000FFFFFFFF. The
         * phys_upper_bound is the upper 32-bits of the 48-bit 1394 address. The
         * lower 16 bits are assumed to be 0xFFFF.
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->phys_upper_bound, (uint32_t)0x0000FFFF);

        /*
         * Enable all async requests.
         * The asyncReqResourceAll bit (0x80000000) does not get cleared during
         * a bus reset.  If this code is changed to selectively allow nodes to
         * perform ARREQ's, the ARREQ filter bits will need to be updated after
         * every bus reset.
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ar_req_filterhi_set, (uint32_t)0x80000000);

        /*
         * clear isochronous interrupt event and mask registers clearing the
         * mask registers disable all isoc tx & rx ints
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->it_intr_event_clr, (uint32_t)0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->it_intr_mask_clr, (uint32_t)0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_intr_event_clr, (uint32_t)0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_intr_mask_clr, (uint32_t)0xFFFFFFFF);

        /* Clear interrupt event/mask register */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->intr_event_clr, (uint32_t)0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->intr_mask_clr, (uint32_t)0xFFFFFFFF);

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_soft_reset()
 *    Reset OpenHCI HW.
 */
int
hci1394_ohci_soft_reset(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t resetStatus;


        ASSERT(ohci_hdl != NULL);

        /* Reset 1394 HW - Reset is bit 16 in HCControl */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_SOFT_RESET);

        /* Wait for reset to complete */
        drv_usecwait(OHCI_CHIP_RESET_TIME_IN_uSEC);

        /* Verify reset is complete */
        resetStatus = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->hc_ctrl_set);
        resetStatus = resetStatus & OHCI_HC_SOFT_RESET;
        if (resetStatus != 0) {
                return (DDI_FAILURE);
        }

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_reg_read()
 *    Read OpenHCI register.  This is called from the test ioctl interface
 *    through devctl.
 */
void
hci1394_ohci_reg_read(hci1394_ohci_handle_t ohci_hdl,
    uint_t offset, uint32_t *data)
{
        uint32_t *addr;


        ASSERT(ohci_hdl != NULL);
        ASSERT(data != NULL);

        addr = (uint32_t *)((uintptr_t)ohci_hdl->ohci_regs +
            (uintptr_t)(offset & OHCI_REG_ADDR_MASK));
        *data = ddi_get32(ohci_hdl->ohci_reg_handle, addr);
}


/*
 * hci1394_ohci_reg_write()
 *    Write OpenHCI register.  This is called from the test ioctl interface
 *    through devctl.
 */
void
hci1394_ohci_reg_write(hci1394_ohci_handle_t ohci_hdl,
    uint_t offset, uint32_t data)
{
        uint32_t *addr;


        ASSERT(ohci_hdl != NULL);

        addr = (uint32_t *)((uintptr_t)ohci_hdl->ohci_regs +
            (uintptr_t)(offset & OHCI_REG_ADDR_MASK));
        ddi_put32(ohci_hdl->ohci_reg_handle, addr, data);
}


/*
 * hci1394_ohci_intr_master_enable()
 *    Enable interrupts to be passed on from OpenHCI.  This is a global mask.
 *    Individual interrupts still need to be enabled for interrupts to be
 *    generated.
 */
void
hci1394_ohci_intr_master_enable(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->intr_mask_set, OHCI_INTR_MASTER_INTR_ENBL);
}


/*
 * hci1394_ohci_intr_master_disable()
 *    Disable all OpenHCI interrupts from being passed on.  This does not affect
 *    the individual interrupt mask settings.  When interrupts are enabled
 *    again, the same individual interrupts will still be enabled.
 */
void
hci1394_ohci_intr_master_disable(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->intr_mask_clr, OHCI_INTR_MASTER_INTR_ENBL);
}


/*
 * hci1394_ohci_intr_asserted()
 *    Return which ENABLED interrupts are asserted.  If an interrupt is disabled
 *    via its mask bit, it will not be returned from here.
 *
 * NOTE: we may want to make this a macro at some point.
 */
uint32_t
hci1394_ohci_intr_asserted(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t interrupts_asserted;

        ASSERT(ohci_hdl != NULL);

        /*
         * Only look at interrupts which are enabled by reading the
         * intr_event_clr register.
         */
        interrupts_asserted = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->intr_event_clr);

        return (interrupts_asserted);
}


/*
 * hci1394_ohci_intr_enable()
 *    Enable an individual interrupt or set of interrupts. This does not affect
 *    the global interrupt mask.
 */
void
hci1394_ohci_intr_enable(hci1394_ohci_handle_t ohci_hdl,
    uint32_t interrupt_mask)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->intr_mask_set, interrupt_mask);
}


/*
 * hci1394_ohci_intr_disable()
 *    Disable an individual interrupt or set of interrupts. This does not affect
 *    the global interrupt mask.
 */
void
hci1394_ohci_intr_disable(hci1394_ohci_handle_t ohci_hdl,
    uint32_t interrupt_mask)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->intr_mask_clr, interrupt_mask);
}


/*
 * hci1394_ohci_intr_clear()
 *    Clear a set of interrupts so that they are not asserted anymore.
 *
 * NOTE: we may want to make this a macro at some point.
 */
void
hci1394_ohci_intr_clear(hci1394_ohci_handle_t ohci_hdl,
    uint32_t interrupt_mask)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->intr_event_clr, interrupt_mask);
}


/*
 * hci1394_ohci_it_intr_asserted()
 *    Return which ENABLED isoch TX interrupts are asserted.  If an interrupt is
 *    disabled via its mask bit, it will not be returned from here.
 *
 * NOTE: we may want to make this a macro at some point.
 */
uint32_t
hci1394_ohci_it_intr_asserted(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t interrupts_asserted;

        ASSERT(ohci_hdl != NULL);

        /* Only look at interrupts which are enabled */
        interrupts_asserted = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->it_intr_event_clr);

        return (interrupts_asserted);
}


/*
 * hci1394_ohci_it_intr_enable()
 *    Enable an individual isoch TX interrupt. This does not affect the general
 *    isoch interrupt mask in the OpenHCI Mask register.  That is enabled/
 *    disabled via hci1394_ohci_intr_enable/hci1394_ohci_intr_disable.
 */
void
hci1394_ohci_it_intr_enable(hci1394_ohci_handle_t ohci_hdl,
    uint32_t interrupt_mask)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->it_intr_mask_set, interrupt_mask);
}


/*
 * hci1394_ohci_it_intr_disable()
 *    Disable an individual isoch TX interrupt. This does not affect the general
 *    isoch interrupt mask in the OpenHCI Mask register.  That is enabled/
 *    disabled via hci1394_ohci_intr_enable/hci1394_ohci_intr_disable.
 */
void
hci1394_ohci_it_intr_disable(hci1394_ohci_handle_t ohci_hdl,
    uint32_t interrupt_mask)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->it_intr_mask_clr, interrupt_mask);
}


/*
 * hci1394_ohci_it_intr_clear()
 *    Clear an individual isoch TX interrupt so that it is not asserted anymore.
 *
 * NOTE: we may want to make this a macro at some point.
 */
void
hci1394_ohci_it_intr_clear(hci1394_ohci_handle_t ohci_hdl,
    uint32_t interrupt_mask)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->it_intr_event_clr, interrupt_mask);
}


/*
 * hci1394_ohci_it_ctxt_count_get()
 *    Determine the number of supported isochronous transmit contexts.
 */
int
hci1394_ohci_it_ctxt_count_get(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t channel_mask;
        int count;

        ASSERT(ohci_hdl != NULL);

        /*
         * hw is required to support contexts 0 to N, where N <= 31
         * the interrupt mask bits are wired to ground for unsupported
         * contexts.  Write 1's to all it mask bits, then read the mask.
         * Implemented contexts will read (sequentially) as 1
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->it_intr_mask_set, 0xFFFFFFFF);
        channel_mask = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->it_intr_mask_set);
        count = 0;
        while (channel_mask != 0) {
                channel_mask = channel_mask >> 1;
                count++;
        }

        return (count);
}


/*
 * hci1394_ohci_it_cmd_ptr_set()
 *    Set the context pointer for a given isoch TX context.  This is the IO
 *    address for the HW to fetch the first descriptor.  The context should
 *    not be running when this routine is called.
 */
void
hci1394_ohci_it_cmd_ptr_set(hci1394_ohci_handle_t ohci_hdl,
    uint_t context_number, uint32_t io_addr)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->it[context_number].cmd_ptrlo,
            io_addr);
}


/*
 * hci1394_ohci_ir_intr_asserted()
 *    Return which ENABLED isoch RX interrupts are asserted.  If an interrupt is
 *    disabled via its mask bit, it will not be returned from here.
 *
 * NOTE: we may want to make this a macro at some point.
 */
uint32_t
hci1394_ohci_ir_intr_asserted(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t interrupts_asserted;

        ASSERT(ohci_hdl != NULL);

        /* Only look at interrupts which are enabled */
        interrupts_asserted = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_intr_event_clr);

        return (interrupts_asserted);
}


/*
 * hci1394_ohci_ir_intr_enable()
 *    Enable an individual isoch RX interrupt. This does not affect the isoch
 *    interrupt mask in the OpenHCI Mask register.  That is enabled/disabled
 *    via hci1394_ohci_intr_enable/hci1394_ohci_intr_disable.
 */
void
hci1394_ohci_ir_intr_enable(hci1394_ohci_handle_t ohci_hdl,
    uint32_t interrupt_mask)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_intr_mask_set, interrupt_mask);
}


/*
 * hci1394_ohci_ir_intr_disable()
 *    Disable an individual isoch RX interrupt. This does not affect the isoch
 *    interrupt mask in the OpenHCI Mask register.  That is enabled/disabled
 *    via hci1394_ohci_intr_enable/hci1394_ohci_intr_disable.
 */
void
hci1394_ohci_ir_intr_disable(hci1394_ohci_handle_t ohci_hdl,
    uint32_t interrupt_mask)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_intr_mask_clr, interrupt_mask);
}


/*
 * hci1394_ohci_ir_intr_clear()
 *    Clear an individual isoch RX interrupt so that it is not asserted anymore.
 *
 * NOTE: we may want to make this a macro at some point.
 */
void
hci1394_ohci_ir_intr_clear(hci1394_ohci_handle_t ohci_hdl,
    uint32_t interrupt_mask)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_intr_event_clr, interrupt_mask);
}


/*
 * hci1394_ohci_ir_ctxt_count_get()
 *    Determine the number of supported isochronous receive contexts.
 */
int
hci1394_ohci_ir_ctxt_count_get(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t channel_mask;
        int count;

        ASSERT(ohci_hdl != NULL);

        /*
         * hw is required to support contexts 0 to N, where N <= 31
         * the interrupt mask bits are wired to ground for unsupported
         * contexts.  Write 1's to all ir mask bits, then read the mask.
         * Implemented contexts will read (sequentially) as 1
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_intr_mask_set, 0xFFFFFFFF);
        channel_mask = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir_intr_mask_set);
        count = 0;
        while (channel_mask != 0) {
                channel_mask = channel_mask >> 1;
                count++;
        }

        return (count);
}


/*
 * hci1394_ohci_ir_cmd_ptr_set()
 *    Set the context pointer for a given isoch RX context.  This is the IO
 *    address for the HW to fetch the first descriptor.  The context should
 *    not be running when this routine is called.
 */
void
hci1394_ohci_ir_cmd_ptr_set(hci1394_ohci_handle_t ohci_hdl,
    uint_t context_number, uint32_t io_addr)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ir[context_number].cmd_ptrlo,
            io_addr);
}


/*
 * hci1394_ohci_link_enable()
 *    Enable the 1394 link layer.  When the link is enabled, the PHY will pass
 *    up any 1394 bus transactions which would normally come up to the link.
 */
void
hci1394_ohci_link_enable(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_LINK_ENBL);
}


/*
 * hci1394_ohci_link_disable()
 *    Disable the 1394 link layer.  When the link is disabled, the PHY will NOT
 *    pass up any 1394 bus transactions which would normally come up to the
 *    link.  This "logically" disconnects us from the 1394 bus.
 */
void
hci1394_ohci_link_disable(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->hc_ctrl_clr, OHCI_HC_LINK_ENBL);
}


/*
 * hci1394_ohci_bus_reset()
 *     Reset the 1394 bus. This performs a "long" bus reset and can be called
 *     when the adapter has either a 1394-1995 or 1394A PHY.
 */
int
hci1394_ohci_bus_reset(hci1394_ohci_handle_t ohci_hdl)
{
        int status;
        uint_t reg;


        ASSERT(ohci_hdl != NULL);

        /*
         * We want to reset the bus.  We also handle the root_holdoff and gap
         * count cacheing explained at the top of this file.
         */
        reg = OHCI_PHY_IBR;
        if (ohci_hdl->ohci_set_root_holdoff == B_TRUE) {
                reg = reg | OHCI_PHY_RHB;
        }
        if (ohci_hdl->ohci_set_gap_count == B_TRUE) {
                reg = reg | ohci_hdl->ohci_gap_count;
        } else {
                reg = reg | OHCI_PHY_MAX_GAP;
        }

        /*
         * Reset the bus. We intentionally do NOT do a PHY read here.  A PHY
         * read could introduce race conditions and would be more likely to fail
         * due to a timeout.
         */
        status = hci1394_ohci_phy_write(ohci_hdl, 0x1, reg);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        /* clear the root holdoff and gap count state bits */
        ohci_hdl->ohci_set_root_holdoff = B_FALSE;
        ohci_hdl->ohci_set_gap_count = B_FALSE;

        return (DDI_SUCCESS);
}

/*
 *
 * hci1394_ohci_bus_reset_nroot()
 *     Reset the 1394 bus. This performs a "long" bus reset with out a root.
 */
int
hci1394_ohci_bus_reset_nroot(hci1394_ohci_handle_t ohci_hdl)
{
        int status;
        uint_t reg;

        ASSERT(ohci_hdl != NULL);

        /*
         * We want to reset the bus.  We don't care about any holdoff
         * we are suspending need no root...
         */
        (void) hci1394_ohci_phy_read(ohci_hdl, 0x1, &reg);
        reg = reg | OHCI_PHY_IBR;
        reg = reg & ~OHCI_PHY_RHB;

        /*
         * Reset the bus. We intentionally do NOT do a PHY read here.  A PHY
         * read could introduce race conditions and would be more likely to fail
         * due to a timeout.
         */
        status = hci1394_ohci_phy_write(ohci_hdl, 0x1, reg);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        return (DDI_SUCCESS);
}

/*
 * hci1394_ohci_phy_init()
 *    Setup the PHY.  This should be called during attach and performs any PHY
 *    initialization required including figuring out what kind of PHY we have.
 */
int
hci1394_ohci_phy_init(hci1394_ohci_handle_t ohci_hdl)
{
        int status;
        uint_t phy_reg;


        ASSERT(ohci_hdl != NULL);

        /*
         * if the phy has extended set to 7, the phy is a not a 1394-1995 PHY.
         * It could be a 1394a phy or beyond.  The PHY type can be found in PHY
         * register page 1 in the compliance_level register.
         *
         * Since there are not any current standards beyond 1394A, we are going
         * to consider the PHY to be a 1394A phy if the extended bit is set.
         *
         * phy registers are byte wide registers and are addressed as 0, 1, 2,
         * 3, ...  Phy register 0 may not be read or written.
         *
         * Phy register 0x2 (bit 0 MSB, 7 LSB)
         *   Extended    - bits 0 - 2
         *   Total Ports - bits 4 - 7
         */
        status = hci1394_ohci_phy_read(ohci_hdl, 2, &phy_reg);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        if ((phy_reg & OHCI_PHY_EXTND_MASK) != OHCI_PHY_EXTND) {
                /*
                 * if the extended bit is not set, we have to be a 1394-1995
                 * PHY
                 */
                ohci_hdl->ohci_phy = H1394_PHY_1995;
        } else {
                /* Treat all other PHY's as a 1394A PHY */
                ohci_hdl->ohci_phy = H1394_PHY_1394A;
        }

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_phy_resume()
 *    re-initialize the PHY. This routine should be called during a resume after
 *    a successful suspend has been done.
 */
/* ARGSUSED */
static int
hci1394_ohci_phy_resume(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        /* There is currently nothing to re-initialize here */
        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_phy_set()
 *    Perform bitset operation on PHY register.
 */
int
hci1394_ohci_phy_set(hci1394_ohci_handle_t ohci_hdl, uint_t address,
    uint_t bits)
{
        int status;
        uint_t reg;


        ASSERT(ohci_hdl != NULL);

        mutex_enter(&ohci_hdl->ohci_mutex);

        /* read the PHY register */
        status = hci1394_ohci_phy_read_no_lock(ohci_hdl, address, &reg);
        if (status != DDI_SUCCESS) {
                mutex_exit(&ohci_hdl->ohci_mutex);
                return (DDI_FAILURE);
        }

        /* Set the bits and write the result back */
        reg = reg | bits;
        status = hci1394_ohci_phy_write_no_lock(ohci_hdl, address, reg);
        if (status != DDI_SUCCESS) {
                mutex_exit(&ohci_hdl->ohci_mutex);
                return (DDI_FAILURE);
        }

        mutex_exit(&ohci_hdl->ohci_mutex);

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_phy_clr()
 *    Perform bitclr operation on PHY register.
 */
int
hci1394_ohci_phy_clr(hci1394_ohci_handle_t ohci_hdl, uint_t address,
    uint_t bits)
{
        int status;
        uint_t reg;


        ASSERT(ohci_hdl != NULL);

        mutex_enter(&ohci_hdl->ohci_mutex);

        /* read the PHY register */
        status = hci1394_ohci_phy_read_no_lock(ohci_hdl, address, &reg);
        if (status != DDI_SUCCESS) {
                mutex_exit(&ohci_hdl->ohci_mutex);
                return (DDI_FAILURE);
        }

        /* Set the bits and write the result back */
        reg = reg & ~bits;
        status = hci1394_ohci_phy_write_no_lock(ohci_hdl, address, reg);
        if (status != DDI_SUCCESS) {
                mutex_exit(&ohci_hdl->ohci_mutex);
                return (DDI_FAILURE);
        }

        mutex_exit(&ohci_hdl->ohci_mutex);
        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_phy_read()
 *    Atomic PHY register read
 */
int
hci1394_ohci_phy_read(hci1394_ohci_handle_t ohci_hdl, uint_t address,
    uint_t *data)
{
        int status;

        ASSERT(ohci_hdl != NULL);
        mutex_enter(&ohci_hdl->ohci_mutex);
        status = hci1394_ohci_phy_read_no_lock(ohci_hdl, address, data);
        mutex_exit(&ohci_hdl->ohci_mutex);

        return (status);
}


/*
 * hci1394_ohci_phy_write()
 *    Atomic PHY register write
 */
int
hci1394_ohci_phy_write(hci1394_ohci_handle_t ohci_hdl, uint_t address,
    uint_t data)
{
        int status;

        ASSERT(ohci_hdl != NULL);
        mutex_enter(&ohci_hdl->ohci_mutex);
        status = hci1394_ohci_phy_write_no_lock(ohci_hdl, address, data);
        mutex_exit(&ohci_hdl->ohci_mutex);

        return (status);
}


/*
 * hci1394_ohci_phy_read_no_lock()
 *    This routine actually performs the PHY register read.  It is seperated
 *    out from phy_read so set & clr lock can perform an atomic PHY register
 *    operation.  It assumes the OpenHCI mutex is held.
 */
static int
hci1394_ohci_phy_read_no_lock(hci1394_ohci_handle_t ohci_hdl, uint_t address,
    uint_t *data)
{
        uint32_t ohci_reg;
        int count;


        ASSERT(ohci_hdl != NULL);
        ASSERT(data != NULL);
        ASSERT(MUTEX_HELD(&ohci_hdl->ohci_mutex));

        /* You can't read or write PHY register #0 */
        if (address == 0) {
                return (DDI_FAILURE);
        }

        /* Verify phy access not in progress */
        ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->phy_ctrl);
        if ((ohci_reg & (OHCI_PHYC_RDREG | OHCI_PHYC_WRREG)) != 0) {
                return (DDI_FAILURE);
        }

        /* Start the PHY register read */
        ohci_reg = OHCI_PHYC_RDREG | ((address & 0xF) <<
            OHCI_PHYC_REGADDR_SHIFT);
        ddi_put32(ohci_hdl->ohci_reg_handle, &ohci_hdl->ohci_regs->phy_ctrl,
            ohci_reg);

        /*
         * The PHY read usually takes less than 1uS.  It is not worth having
         * this be interrupt driven. Having this be interrupt driven would also
         * make the bus reset and self id processing much more complex for
         * 1995 PHY's.  We will wait up to hci1394_phy_delay_uS for the read
         * to complete (this was initially set to 10).  I have yet to see
         * count > 1.  The delay is a patchable variable.
         */
        count = 0;
        while (count < hci1394_phy_delay_uS) {
                /* See if the read is done yet */
                ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
                    &ohci_hdl->ohci_regs->phy_ctrl);
                if ((ohci_reg & OHCI_PHYC_RDDONE) != 0) {
                        /*
                         * The read is done. clear the phyRegRecv interrupt. We
                         * do not have this interrupt enabled but this keeps
                         * things clean in case someone in the future does.
                         * Break out of the loop, we are done.
                         */
                        ddi_put32(ohci_hdl->ohci_reg_handle,
                            &ohci_hdl->ohci_regs->intr_event_clr,
                            OHCI_INTR_PHY_REG_RCVD);
                        break;
                }

                /*
                 * the phy read did not yet complete, wait 1uS, increment the
                 * count and try again.
                 */
                drv_usecwait(1);
                count++;
        }

        /* Check to see if we timed out */
        if (count >= hci1394_phy_delay_uS) {
                /* we timed out, return failure */
                *data = 0;
                return (DDI_FAILURE);
        }

        /* setup the PHY read data to be returned */
        *data = (ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->phy_ctrl) & OHCI_PHYC_RDDATA_MASK) >>
            OHCI_PHYC_RDDATA_SHIFT;

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_phy_write_no_lock()
 *    This routine actually performs the PHY register write.  It is separated
 *    out from phy_write so set & clr lock can perform an atomic PHY register
 *    operation.  It assumes the OpenHCI mutex is held.
 */
static int
hci1394_ohci_phy_write_no_lock(hci1394_ohci_handle_t ohci_hdl, uint_t address,
    uint_t data)
{
        uint32_t ohci_reg;
        int count;


        ASSERT(ohci_hdl != NULL);
        ASSERT(MUTEX_HELD(&ohci_hdl->ohci_mutex));

        /* You can't read or write PHY register #0 */
        if (address == 0) {
                return (DDI_FAILURE);
        }

        /* Verify phy access not in progress */
        ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->phy_ctrl);
        if ((ohci_reg & (OHCI_PHYC_RDREG | OHCI_PHYC_WRREG)) != 0) {
                return (DDI_FAILURE);
        }

        /* Start the PHY register write */
        ohci_reg = OHCI_PHYC_WRREG | ((address & 0xF) <<
            OHCI_PHYC_REGADDR_SHIFT) | (data & OHCI_PHYC_WRDATA_MASK);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->phy_ctrl, ohci_reg);

        /*
         * The PHY write usually takes less than 1uS.  It is not worth having
         * this be interrupt driven. Having this be interrupt driven would also
         * make the bus reset and self id processing much more complex. We will
         * wait up to hci1394_phy_delay_uS for the write to complete (this was
         * initially set to 10).  I have yet to see count > 0.  The delay is a
         * patchable variable.
         */
        count = 0;
        while (count < hci1394_phy_delay_uS) {
                /* See if the write is done yet */
                ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
                    &ohci_hdl->ohci_regs->phy_ctrl);
                if ((ohci_reg & OHCI_PHYC_WRREG) == 0) {
                        /*
                         * The write completed. Break out of the loop, we are
                         * done.
                         */
                        break;
                }

                /*
                 * the phy write did not yet complete, wait 1uS, increment the
                 * count and try again.
                 */
                drv_usecwait(1);
                count++;
        }

        /* Check to see if we timed out */
        if (count >= hci1394_phy_delay_uS) {
                /* we timed out, return failure */
                return (DDI_FAILURE);
        }

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_phy_info()
 *    Return selfid word for our PHY.  This routine should ONLY be called for
 *    adapters with a 1394-1995 PHY. These PHY's do not embed their own selfid
 *    information in the selfid buffer so we need to do it for them in the
 *    selfid complete interrupt handler.  This routine only supports building
 *    selfid info for a 3 port PHY.  Since we will probably not ever see a
 *    1394-1995 PHY in any production system, and if we do it will have 3 ports
 *    or less, this is a pretty safe assumption.
 */
int
hci1394_ohci_phy_info(hci1394_ohci_handle_t ohci_hdl, uint32_t *info)
{
        int status;
        uint32_t phy_info;
        uint32_t reg;
        int index;
        int num_ports;
        int count;
        uint32_t port_status;


        ASSERT(ohci_hdl != NULL);
        ASSERT(info != NULL);
        ASSERT(ohci_hdl->ohci_phy == H1394_PHY_1995);

        /*
         * Set Link on. We are using power class 0 since we have no idea what
         * our real power class is.
         */
        phy_info = 0x80400000;

        /* Add in Physical ID */
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->node_id);
        phy_info = phy_info | ((reg << IEEE1394_SELFID_PHYID_SHIFT) &
            IEEE1394_SELFID_PHYID_MASK);

        /* Add in Gap Count */
        status = hci1394_ohci_phy_read(ohci_hdl, 1, &reg);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }
        phy_info = phy_info | ((reg << IEEE1394_SELFID_GAP_CNT_SHIFT) &
            IEEE1394_SELFID_GAP_CNT_MASK);

        /* Add in speed & ports */
        status = hci1394_ohci_phy_read(ohci_hdl, 2, &reg);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }
        phy_info = phy_info | ((reg & 0xC0) << 8);
        num_ports = reg & 0x1F;

        /* PHY reports that it has 0 ports?? */
        if (num_ports == 0) {
                return (DDI_FAILURE);
        }

        /* Build up the port information for each port in the PHY */
        count = 0;
        for (index = 0; index < 3; index++) {
                if (num_ports > 0) {
                        status = hci1394_ohci_phy_read(ohci_hdl,
                            count + 3, &reg);
                        if (status != DDI_SUCCESS) {
                                return (DDI_FAILURE);
                        }
                        /* if port is not connected */
                        if ((reg & 0x04) == 0) {
                                port_status =
                                    IEEE1394_SELFID_PORT_NOT_CONNECTED;

                        /* else if port is connected to parent */
                        } else if ((reg & 0x08) == 0) {
                                port_status = IEEE1394_SELFID_PORT_TO_PARENT;

                        /* else port is connected to child */
                        } else {
                                port_status = IEEE1394_SELFID_PORT_TO_CHILD;
                        }

                        num_ports--;
                } else {
                        port_status = IEEE1394_SELFID_PORT_NO_PORT;
                }

                /* add in the port information */
                phy_info = phy_info | (port_status << (6 - (index * 2)));
                count++;
        }

        /* Copy the PHY selfid info to the return parameter */
        *info = phy_info;

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_current_busgen()
 *    return the current bus generation.
 */
uint_t
hci1394_ohci_current_busgen(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t reg;
        uint_t generation_count;


        ASSERT(ohci_hdl != NULL);

        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->self_id_count);
        generation_count = (reg & OHCI_SLFC_GEN_MASK) >> OHCI_SLFC_GEN_SHIFT;

        return (generation_count);
}


/*
 * hci1394_ohci_startup()
 *    Startup the 1394 nexus driver.  This is called after all of the HW has
 *    been initialized (in both attach and resume) and we are ready to
 *    participate on the bus.
 */
int
hci1394_ohci_startup(hci1394_ohci_handle_t ohci_hdl)
{
        int status;


        ASSERT(ohci_hdl != NULL);

        /*
         * Turn on 1394 link. This allows us to receive 1394 traffic off the
         * bus
         */
        hci1394_ohci_link_enable(ohci_hdl);

        /*
         * Reset the 1394 Bus.
         * Need to do this so that the link layer can collect all of the self-id
         * packets.  The Interrupt routine will cause further initialization
         * after the bus reset has completed
         */
        status = hci1394_ohci_bus_reset(ohci_hdl);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        /* setup out initial interrupt mask and enable interrupts */
        hci1394_isr_mask_setup(ohci_hdl->soft_state);
        hci1394_ohci_intr_master_enable(ohci_hdl);

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_postwr_addr()
 *    Read the Posted Write Address registers.  This should be read when a
 *    posted write error is detected to find out what transaction had an error.
 */
void
hci1394_ohci_postwr_addr(hci1394_ohci_handle_t ohci_hdl, uint64_t *addr)
{
        uint32_t reg;


        ASSERT(ohci_hdl != NULL);
        ASSERT(addr != NULL);

        /* read in the errored address */
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->posted_write_addrhi);
        *addr = ((uint64_t)reg) << 32;
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->posted_write_addrlo);
        *addr = *addr | (uint64_t)reg;

        /*
         * Interrupt should be cleared after reading the posted write address.
         * See 13.2.8.1 in OpenHCI spec v1.0.
         */
        hci1394_ohci_intr_clear(ohci_hdl, OHCI_INTR_POST_WR_ERR);
}


/*
 * hci1394_ohci_guid()
 *    Return the adapter's GUID
 */
uint64_t
hci1394_ohci_guid(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t reg;
        uint64_t guid;


        ASSERT(ohci_hdl != NULL);

        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->guid_hi);
        guid = ((uint64_t)reg) << 32;
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->guid_lo);
        guid = guid | (uint64_t)reg;

        return (guid);
}


/*
 * hci1394_ohci_csr_read()
 *    Read one of the HW implemented CSR registers.  These include
 *    bus_manager_id, bandwidth_available, channels_available_hi, and
 *    channels_available_lo. Offset should be set to
 *    OHCI_CSR_SEL_BUS_MGR_ID, OHCI_CSR_SEL_BANDWIDTH_AVAIL
 *    OHCI_CSR_SEL_CHANS_AVAIL_HI, or OHCI_CSR_SEL_CHANS_AVAIL_LO.
 */
int
hci1394_ohci_csr_read(hci1394_ohci_handle_t ohci_hdl, uint_t offset,
    uint32_t *data)
{
        uint_t generation;
        int status;


        ASSERT(ohci_hdl != NULL);
        ASSERT(data != NULL);

        /*
         * read the CSR register by doing a cswap with the same compare and
         * swap value.
         */
        generation = hci1394_ohci_current_busgen(ohci_hdl);
        status = hci1394_ohci_csr_cswap(ohci_hdl, generation, offset, 0, 0,
            data);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_csr_cswap()
 *    Perform a compare/swap on one of the HW implemented CSR registers. These
 *    include bus_manager_id, bandwidth_available, channels_available_hi, and
 *    channels_available_lo. Offset should be set to
 *    OHCI_CSR_SEL_BUS_MGR_ID, OHCI_CSR_SEL_BANDWIDTH_AVAIL
 *    OHCI_CSR_SEL_CHANS_AVAIL_HI, or OHCI_CSR_SEL_CHANS_AVAIL_LO.
 */
int
hci1394_ohci_csr_cswap(hci1394_ohci_handle_t ohci_hdl, uint_t generation,
    uint_t offset, uint32_t compare, uint32_t swap, uint32_t *old)
{
        int count;
        uint32_t ohci_reg;


        ASSERT(ohci_hdl != NULL);
        ASSERT(old != NULL);

        /*
         * Make sure we have not gotten a bus reset since this action was
         * started.
         */
        if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
                return (DDI_FAILURE);
        }

        mutex_enter(&ohci_hdl->ohci_mutex);

        /* init csrData and csrCompare */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->csr_data, swap);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->csr_compare_data, compare);

        /* start the compare swap */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->csr_ctrl, offset & OHCI_CSR_SELECT);

        /*
         * The CSR access should be immediate.  There in nothing that officially
         * states this so we will wait up to 2uS just in case before we timeout.
         * We actually perform a compare swap with both compare and swap set
         * to the same value.  This will return the old value which is in
         * essence, a read.
         */
        count = 0;
        while (count < 2) {
                /* See if the compare swap is done */
                ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
                    &ohci_hdl->ohci_regs->csr_ctrl);
                if ((ohci_reg & OHCI_CSR_DONE) != 0) {
                        /* The compare swap is done, break out of the loop */
                        break;
                }
                /*
                 * The compare swap has not completed yet, wait 1uS, increment
                 * the count and try again
                 */
                drv_usecwait(1);
                count++;
        }

        /* If we timed out, return an error */
        if (count >= 2) {
                *old = 0;
                mutex_exit(&ohci_hdl->ohci_mutex);
                return (DDI_FAILURE);
        }

        /* Copy the old data into the return parameter */
        *old = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->csr_data);

        mutex_exit(&ohci_hdl->ohci_mutex);

        /*
         * There is a race condition in the OpenHCI design here. After checking
         * the generation and before performing the cswap, we could get a bus
         * reset and incorrectly set something like the bus manager.  This would
         * put us into a condition where we would not have a bus manager and
         * we would think there was one. If it is possible that this race
         * condition occured, we will reset the bus to clean things up. We only
         * care about this if the compare swap was successful.
         */
        if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
                if (*old == compare) {
                        (void) hci1394_ohci_bus_reset(ohci_hdl);
                        return (DDI_FAILURE);
                }
        }

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_contender_enable()
 *    Set the contender bit in the PHY.  This routine should only be called
 *    if our PHY is 1394A compliant. (i.e. this routine should not be called
 *    for a 1394-1995 PHY).
 */
int
hci1394_ohci_contender_enable(hci1394_ohci_handle_t ohci_hdl)
{
        int status;


        ASSERT(ohci_hdl != NULL);

        /*
         * Make sure that phy is not a 1394-1995 phy. Those phy's do not have a
         * contender bit to set.
         */
        if (ohci_hdl->ohci_phy == H1394_PHY_1995) {
                return (DDI_FAILURE);
        }

        /* Set the Contender Bit */
        status = hci1394_ohci_phy_set(ohci_hdl, 0x4, OHCI_PHY_CNTDR);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_root_holdoff_enable()
 *    Set the root holdoff bit in the PHY. Since there are race conditions when
 *    writing to PHY register 1 (which can get updated from a PHY packet off the
 *    bus), we cache this state until a "long" bus reset is issued.
 */
int
hci1394_ohci_root_holdoff_enable(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ohci_hdl->ohci_set_root_holdoff = B_TRUE;

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_gap_count_set()
 *    Set the gap count in the PHY. Since there are race conditions when writing
 *    to PHY register 1 (which can get updated from a PHY packet off the bus),
 *    we cache this gap count until a "long" bus reset is issued.
 */
int
hci1394_ohci_gap_count_set(hci1394_ohci_handle_t ohci_hdl, uint_t gap_count)
{
        ASSERT(ohci_hdl != NULL);

        ohci_hdl->ohci_set_gap_count = B_TRUE;
        ohci_hdl->ohci_gap_count = gap_count & OHCI_PHY_MAX_GAP;

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_phy_filter_set()
 *    Enable a node (or nodes) to perform transactions to our physical
 *    memory. OpenHCI allows you to disable/enable physical requests on a node
 *    per node basis.  A physical request is basically a read/write to 1394
 *    address space 0x0 - 0xFFFFFFFF.  This address goes out to the IO MMU (in
 *    the case of a SPARC machine).  The HAL starts with all nodes unable to
 *    read/write physical memory.  The Services Layer will call down and enable
 *    nodes via setting a physical filter bit for that given node.  Since node
 *    numbers change every bus reset, the services layer has to call down after
 *    every bus reset to re-enable physical accesses. (NOTE: the hardware
 *    automatically clears these bits.
 */
int
hci1394_ohci_phy_filter_set(hci1394_ohci_handle_t ohci_hdl, uint64_t mask,
    uint_t generation)
{
        uint32_t data;


        ASSERT(ohci_hdl != NULL);

        /*
         * Make sure we have not gotten a bus reset since this action was
         * started.
         */
        if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
                return (DDI_FAILURE);
        }

        data = (uint32_t)((mask >> 32) & 0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->phys_req_filterhi_set, data);
        data = (uint32_t)(mask & 0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->phys_req_filterlo_set, data);

        /*
         * There is a race condition in the OpenHCI design here. After checking
         * the generation and before setting the physical filter bits, we could
         * get a bus reset and incorrectly set the physical filter bits.  If it
         * is possible that this race condition occured, we will reset the bus
         * to clean things up.
         */
        if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
                (void) hci1394_ohci_bus_reset(ohci_hdl);
                return (DDI_SUCCESS);
        }

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_phy_filter_clr()
 *    Disable a node (or nodes) from performing transactions to our physical
 *    memory. See hci1394_ohci_phy_filter_set() above for more info.
 */
int
hci1394_ohci_phy_filter_clr(hci1394_ohci_handle_t ohci_hdl,
    uint64_t mask, uint_t generation)
{
        uint32_t data;


        ASSERT(ohci_hdl != NULL);

        /*
         * Make sure we have not gotten a bus reset since this action was
         * started.
         */
        if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
                return (DDI_FAILURE);
        }

        data = (uint32_t)((mask >> 32) & 0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->phys_req_filterhi_clr, data);
        data = (uint32_t)(mask & 0xFFFFFFFF);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->phys_req_filterlo_clr, data);

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_bus_reset_short()
 *    Perform a 1394A short bus reset.  This function should only be called
 *    on an adapter with a 1394A PHY (or later).
 */
int
hci1394_ohci_bus_reset_short(hci1394_ohci_handle_t ohci_hdl)
{
        int status;

        ASSERT(ohci_hdl != NULL);

        /*
         * Make sure that phy is not a 1394-1995 phy. Those phy's do not have a
         * contender bit to set.
         */
        if (ohci_hdl->ohci_phy == H1394_PHY_1995) {
                return (DDI_FAILURE);
        }

        /* Initiate the short bus reset */
        status = hci1394_ohci_phy_set(ohci_hdl, 0x5, OHCI_PHY_ISBR);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        return (status);
}


/*
 * hci1394_ohci_cfgrom_update()
 *    Update the config rom with the provided contents.  The config rom is
 *    provided as a byte stream which is multiple of 4 bytes large.  The
 *    size is passed as a quadlet (4 bytes) count.  The entire contents
 *    of the config rom is updated at once.  We do not provide a partial
 *    update interface.
 */
void
hci1394_ohci_cfgrom_update(hci1394_ohci_handle_t ohci_hdl, void *local_buf,
    uint_t quadlet_count)
{
        uint32_t *data;


        ASSERT(ohci_hdl != NULL);
        ASSERT(local_buf != NULL);

        data = (uint32_t *)local_buf;

        /* zero out the config ROM header to start */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->config_rom_hdr, 0);

        /* copy Services Layer buffer into config rom buffer */
        ddi_rep_put8(ohci_hdl->ohci_cfgrom.bi_handle, local_buf,
            (uint8_t *)ohci_hdl->ohci_cfgrom.bi_kaddr, quadlet_count << 2,
            DDI_DEV_AUTOINCR);

        (void) ddi_dma_sync(ohci_hdl->ohci_cfgrom.bi_dma_handle, 0,
            quadlet_count << 2, DDI_DMA_SYNC_FORDEV);

        /*
         * setup OHCI bus options and config rom hdr registers. We need to swap
         * the config rom header and bus options on an X86 machine since the
         * data is provided to us as a byte stream and the OHCI registers expect
         * a big endian 32-bit number.
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->bus_options, OHCI_SWAP32(data[2]));
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->config_rom_hdr, OHCI_SWAP32(data[0]));
}


/*
 * hci1394_ohci_nodeid_get()
 *    Return our current nodeid (bus #/Node #)
 */
void
hci1394_ohci_nodeid_get(hci1394_ohci_handle_t ohci_hdl, uint_t *nodeid)
{
        uint32_t reg;

        ASSERT(ohci_hdl != NULL);
        ASSERT(nodeid != NULL);
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->node_id);
        *nodeid = (reg & 0xFFFF) << 16;
}


/*
 * hci1394_ohci_nodeid_set()
 *    Set our current nodeid (bus #/Node #).  This actually sets our bus number.
 *    Our node number cannot be set by software.  This is usually trigered via
 *    a write to the CSR NODEIDS register.
 */
void
hci1394_ohci_nodeid_set(hci1394_ohci_handle_t ohci_hdl, uint_t nodeid)
{
        uint32_t reg;

        ASSERT(ohci_hdl != NULL);

        reg = ((nodeid & 0xFFC00000) >> 16);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->node_id, reg);
}


/*
 * hci1394_ohci_nodeid_info()
 *    Return our current nodeid (bus #/Node #).  This also returns whether or
 *    not our nodeid error bit is set.  This is useful in determining if the
 *    bus reset completed without errors in the selfid complete interrupt
 *    processing.
 */
void
hci1394_ohci_nodeid_info(hci1394_ohci_handle_t ohci_hdl, uint_t *nodeid,
    boolean_t *error)
{
        uint32_t reg;

        ASSERT(ohci_hdl != NULL);
        ASSERT(nodeid != NULL);

        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->node_id);
        *nodeid = reg & 0xFFFF;
        if ((reg & OHCI_NDID_IDVALID) == 0) {
                *error = B_TRUE;
        } else {
                *error = B_FALSE;
        }
}


/*
 * hci1394_ohci_cycletime_get()
 *    Return the current cycle time
 */
void
hci1394_ohci_cycletime_get(hci1394_ohci_handle_t ohci_hdl,
    uint32_t *cycle_time)
{
        ASSERT(ohci_hdl != NULL);
        ASSERT(cycle_time != NULL);
        *cycle_time = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->isoch_cycle_timer);
}


/*
 * hci1394_ohci_cycletime_get()
 *    Set the cycle time
 */
void
hci1394_ohci_cycletime_set(hci1394_ohci_handle_t ohci_hdl,
    uint32_t cycle_time)
{
        ASSERT(ohci_hdl != NULL);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->isoch_cycle_timer, cycle_time);
}


/*
 * hci1394_ohci_bustime_get()
 *    Return the current bus time.
 */
void
hci1394_ohci_bustime_get(hci1394_ohci_handle_t ohci_hdl, uint32_t *bus_time)
{
        uint32_t bus_time1;
        uint32_t bus_time2;
        uint32_t cycle_time;


        ASSERT(ohci_hdl != NULL);
        ASSERT(bus_time != NULL);

        /*
         * The bus time is composed of a portion of the cycle time and the
         * cycle time rollover count (ohci_bustime_count). There is a race
         * condition where we read the rollover count and then the cycle
         * timer rolls over.  This is the reason for the double read of the
         * rollover count.
         */
        do {
                bus_time1 = ohci_hdl->ohci_bustime_count;
                cycle_time = ddi_get32(ohci_hdl->ohci_reg_handle,
                    &ohci_hdl->ohci_regs->isoch_cycle_timer);
                bus_time2 = ohci_hdl->ohci_bustime_count;
        } while (bus_time1 != bus_time2);

        *bus_time = (bus_time2 << 7) | (cycle_time >> 25);
}


/*
 * hci1394_ohci_bustime_set()
 *    Set the cycle timer rollover portion of the bus time.
 */
void
hci1394_ohci_bustime_set(hci1394_ohci_handle_t ohci_hdl, uint32_t bus_time)
{
        ASSERT(ohci_hdl != NULL);

        /*
         * we will start with the cycle 64 seconds interrupt disabled. If this
         * is the first write to bus time, enable the interrupt.
         */
        if (ohci_hdl->ohci_bustime_enabled == B_FALSE) {
                ohci_hdl->ohci_bustime_enabled = B_TRUE;
                /* Clear the cycle64Seconds interrupt then enable it */
                hci1394_ohci_intr_clear(ohci_hdl, OHCI_INTR_CYC_64_SECS);
                hci1394_ohci_intr_enable(ohci_hdl, OHCI_INTR_CYC_64_SECS);
        }
        ohci_hdl->ohci_bustime_count = (bus_time >> 7);
}


/*
 * hci1394_ohci_atreq_retries_get()
 *    Get the number of atreq retries we will perform.
 */
void
hci1394_ohci_atreq_retries_get(hci1394_ohci_handle_t ohci_hdl,
    uint_t *atreq_retries)
{
        uint32_t reg;

        ASSERT(ohci_hdl != NULL);
        ASSERT(atreq_retries != NULL);
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_retries);
        *atreq_retries = reg & OHCI_RET_MAX_ATREQ_MASK;
}


/*
 * hci1394_ohci_atreq_retries_get()
 *    Set the number of atreq retries we will perform.
 */
void
hci1394_ohci_atreq_retries_set(hci1394_ohci_handle_t ohci_hdl,
    uint_t atreq_retries)
{
        uint32_t reg;


        ASSERT(ohci_hdl != NULL);

        mutex_enter(&ohci_hdl->ohci_mutex);
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_retries);
        reg = reg & ~OHCI_RET_MAX_ATREQ_MASK;
        reg = reg | (atreq_retries & OHCI_RET_MAX_ATREQ_MASK);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_retries, reg);
        mutex_exit(&ohci_hdl->ohci_mutex);
}


/*
 * hci1394_ohci_isr_cycle64seconds()
 *    Interrupt handler for the cycle64seconds interrupt.
 */
void
hci1394_ohci_isr_cycle64seconds(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t cycle_time;

        ASSERT(ohci_hdl != NULL);

        hci1394_ohci_intr_clear(ohci_hdl, OHCI_INTR_CYC_64_SECS);
        cycle_time = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->isoch_cycle_timer);

        /*
         * cycle64second interrupts when the MSBit in the cycle timer changes
         * state.  We only care about rollover so we will increment only when
         * the MSBit is set to 0.
         */
        if ((cycle_time & 0x80000000) == 0) {
                ohci_hdl->ohci_bustime_count++;
        }
}


/*
 * hci1394_ohci_isr_phy()
 *    Interrupt handler for a PHY event
 */
void
hci1394_ohci_isr_phy(hci1394_ohci_handle_t ohci_hdl)
{
        uint_t phy_status;
        int status;


        ASSERT(ohci_hdl != NULL);

        /* clear the interrupt */
        hci1394_ohci_intr_clear(ohci_hdl, OHCI_INTR_PHY);

        /* increment the statistics count */
        ohci_hdl->ohci_drvinfo->di_stats.st_phy_isr++;

        /*
         * If the PHY is a 1995 phy, just return since there are no status bits
         * to read.
         */
        if (ohci_hdl->ohci_phy == H1394_PHY_1995) {
                return;
        }

        /* See why we got this interrupt */
        status = hci1394_ohci_phy_read(ohci_hdl, 5, &phy_status);
        if (status != DDI_SUCCESS) {
                return;
        }

        if (phy_status & OHCI_PHY_LOOP_ERR) {
                ohci_hdl->ohci_drvinfo->di_stats.st_phy_loop_err++;
                cmn_err(CE_NOTE, "hci1394(%d): ERROR - bus loop detected",
                    ohci_hdl->ohci_drvinfo->di_instance);
        }
        if (phy_status & OHCI_PHY_PWRFAIL_ERR) {
                ohci_hdl->ohci_drvinfo->di_stats.st_phy_pwrfail_err++;
        }
        if (phy_status & OHCI_PHY_TIMEOUT_ERR) {
                ohci_hdl->ohci_drvinfo->di_stats.st_phy_timeout_err++;
        }
        if (phy_status & OHCI_PHY_PORTEVT_ERR) {
                ohci_hdl->ohci_drvinfo->di_stats.st_phy_portevt_err++;
        }

        /* clear any set status bits */
        status = hci1394_ohci_phy_write(ohci_hdl, 5, phy_status);
        if (status != DDI_SUCCESS) {
                return;
        }

        /*
         * Disable the PHY interrupt. We are getting stuck in this ISR in
         * certain PHY implementations so we will disable the interrupt until
         * we see a selfid complete.
         */
        hci1394_ohci_intr_disable(ohci_hdl, OHCI_INTR_PHY);
}


/*
 * hci1394_ohci_root_check
 *    Returns status about if we are currently the root node on the 1394 bus.
 *    returns B_TRUE if we are the root,  B_FALSE if we are not the root.
 */
boolean_t
hci1394_ohci_root_check(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t reg;
        int status;

        ASSERT(ohci_hdl != NULL);
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->node_id);
        if ((reg & OHCI_REG_NODEID_ROOT) && (reg & OHCI_NDID_IDVALID)) {
                status = B_TRUE;
        } else {
                status = B_FALSE;
        }

        return (status);
}


/*
 * hci1394_ohci_cmc_check()
 *    Returns status about if we are cycle master capable. Returns
 *    B_TRUE if we are the cycle master capable, B_FALSE if we are not the cycle
 *    master capable.
 */
boolean_t
hci1394_ohci_cmc_check(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t reg;
        int status;

        ASSERT(ohci_hdl != NULL);
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->bus_options);
        if (reg & OHCI_REG_BUSOPTIONS_CMC) {
                status = B_TRUE;
        } else {
                status = B_FALSE;
        }

        return (status);
}


/*
 * hci1394_ohci_cycle_master_enable()
 *    Enables us to be cycle master.  If we are root, we will start generating
 *    cycle start packets.
 */
void
hci1394_ohci_cycle_master_enable(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        /* First make sure that cycleTooLong is clear */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->intr_event_clr, OHCI_INTR_CYC_TOO_LONG);

        /* Enable Cycle Master */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->link_ctrl_set, OHCI_LC_CYC_MAST);
}


/*
 * hci1394_ohci_cycle_master_disable()
 *    Disabled us from being cycle master. If we are root, we will stop
 *    generating cycle start packets.
 */
void
hci1394_ohci_cycle_master_disable(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        /* disable cycle master */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->link_ctrl_clr, OHCI_LC_CYC_MAST);
}


/*
 * hci1394_ohci_resume()
 *    Re-initialize the openHCI HW during a resume. (after a power suspend)
 */
int
hci1394_ohci_resume(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t quadlet;
        int status;


        ASSERT(ohci_hdl != NULL);

        /* Re-initialize the OpenHCI chip */
        status = hci1394_ohci_chip_init(ohci_hdl);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        /* Re-initialize the PHY */
        status = hci1394_ohci_phy_resume(ohci_hdl);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        /* Re-initialize any 1394A features we are using */
        status = hci1394_ohci_1394a_resume(ohci_hdl);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        /* Tell OpenHCI where the Config ROM buffer is */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->config_rom_maplo,
            (uint32_t)ohci_hdl->ohci_cfgrom.bi_cookie.dmac_address);

        /* Tell OpenHCI where the SelfId buffer is */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->self_id_buflo,
            (uint32_t)ohci_hdl->ohci_selfid.bi_cookie.dmac_address);

        /* Enable selfid DMA engine */
        hci1394_ohci_selfid_enable(ohci_hdl);

        /*
         * re-setup OHCI bus options and config rom hdr registers. We need to
         * read from the config rom using ddi_rep_get8 since it is stored as
         * a byte stream. We need to swap the config rom header and bus options
         * on an X86 machine since the data is a byte stream and the OHCI
         *  registers expect a big endian 32-bit number.
         */
        ddi_rep_get8(ohci_hdl->ohci_cfgrom.bi_handle, (uint8_t *)&quadlet,
            &((uint8_t *)ohci_hdl->ohci_cfgrom.bi_kaddr)[8], 4,
            DDI_DEV_AUTOINCR);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->bus_options, OHCI_SWAP32(quadlet));
        ddi_rep_get8(ohci_hdl->ohci_cfgrom.bi_handle, (uint8_t *)&quadlet,
            &((uint8_t *)ohci_hdl->ohci_cfgrom.bi_kaddr)[0], 4,
            DDI_DEV_AUTOINCR);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->config_rom_hdr, OHCI_SWAP32(quadlet));

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_selfid_init()
 *    Initialize the selfid buffer
 */
static int
hci1394_ohci_selfid_init(hci1394_ohci_handle_t ohci_hdl)
{
        hci1394_buf_parms_t parms;
        int status;


        ASSERT(ohci_hdl != NULL);

        /*
         * Setup for 2K buffer, aligned on a 2Kbyte address boundary. Make sure
         * that the buffer is not broken up into multiple cookies.  OpenHCI can
         * only handle one address for the selfid buffer location.
         */
        parms.bp_length = 2048;
        parms.bp_max_cookies = 1;
        parms.bp_alignment = 2048;
        status = hci1394_buf_alloc(ohci_hdl->ohci_drvinfo, &parms,
            &ohci_hdl->ohci_selfid, &ohci_hdl->ohci_selfid_handle);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        /* Tell OpenHCI where the buffer is */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->self_id_buflo,
            (uint32_t)ohci_hdl->ohci_selfid.bi_cookie.dmac_address);

        /* Enable selfid DMA engine */
        hci1394_ohci_selfid_enable(ohci_hdl);

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_selfid_enable()
 *    Allow selfid packets to be placed into the selfid buffer.  This should be
 *    called after the selfid buffer address has been setup in the HW.
 */
void
hci1394_ohci_selfid_enable(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        /*
         * Allow selfid packets to be received.  This should be called during
         * driver attach after the selfid buffer address has been initialized.
         *
         * Link Control Register
         *   rscSelfId = 1 <= bit 9
         */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->link_ctrl_set, OHCI_LC_RCV_SELF);
}


/*
 * hci1394_ohci_selfid_read()
 *    Read a word out of the selfid buffer.
 */
void
hci1394_ohci_selfid_read(hci1394_ohci_handle_t ohci_hdl, uint_t offset,
    uint32_t *data)
{
        ASSERT(ohci_hdl != NULL);
        ASSERT(data != NULL);
        *data = ddi_get32(ohci_hdl->ohci_selfid.bi_handle,
            &((uint32_t *)ohci_hdl->ohci_selfid.bi_kaddr)[offset]);
}


/*
 * hci1394_ohci_selfid_info()
 *    Return the current bus generation, the number of bytes currently in the
 *    selfid buffer, and if we have seen any selfid errors.
 */
void
hci1394_ohci_selfid_info(hci1394_ohci_handle_t ohci_hdl, uint_t *busgen,
    uint_t *size, boolean_t *error)
{
        uint32_t reg;


        ASSERT(ohci_hdl != NULL);
        ASSERT(busgen != NULL);
        ASSERT(size != NULL);
        ASSERT(error != NULL);

        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->self_id_count);
        *busgen = (reg & OHCI_SLFC_GEN_MASK) >> OHCI_SLFC_GEN_SHIFT;
        *size = reg & OHCI_SLFC_NUM_QUADS_MASK;
        if ((reg & OHCI_SLFC_ERROR) == 0) {
                *error = B_FALSE;
        } else {
                *error = B_TRUE;
        }
}


/*
 * hci1394_ohci_selfid_buf_current()
 *    Test if the selfid buffer is current.  Return B_TRUE if it is current and
 *    B_FALSE if it is not current.
 */
boolean_t
hci1394_ohci_selfid_buf_current(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t reg;
        int status;

        ASSERT(ohci_hdl != NULL);

        /*
         * if the generation stored in the selfid buffer is not equal to the
         * generation we have previously stored, the selfid buffer is not
         * current. (It maybe older or it maybe newer)
         */
        reg = ddi_get32(ohci_hdl->ohci_selfid.bi_handle,
            &((uint32_t *)ohci_hdl->ohci_selfid.bi_kaddr)[0]);
        if (ohci_hdl->ohci_drvinfo->di_gencnt != ((reg & OHCI_SLFC_GEN_MASK) >>
            OHCI_SLFC_GEN_SHIFT)) {
                status = B_FALSE;
        } else {
                status = B_TRUE;
        }

        return (status);
}


/*
 * hci1394_ohci_selfid_sync()
 *    Perform a ddi_dma_sync on the selfid buffer
 */
void
hci1394_ohci_selfid_sync(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);
        (void) ddi_dma_sync(ohci_hdl->ohci_selfid.bi_dma_handle, 0,
            ohci_hdl->ohci_selfid.bi_length, DDI_DMA_SYNC_FORKERNEL);
}


/*
 * hci1394_ohci_cfgrom_init()
 *    Initialize the configuration ROM buffer
 */
static int
hci1394_ohci_cfgrom_init(hci1394_ohci_handle_t ohci_hdl)
{
        hci1394_buf_parms_t parms;
        int status;


        ASSERT(ohci_hdl != NULL);

        /*
         * Setup for 1K buffer, aligned at 1K address boundary, and allow no
         * less than 4 byte data transfers. Create the Buffer.  Make sure that
         * the buffer is not broken up into multiple cookies.  OpenHCI can only
         * handle one address for the config ROM buffer location.
         */
        parms.bp_length = 1024;
        parms.bp_max_cookies = 1;
        parms.bp_alignment = 1024;
        status = hci1394_buf_alloc(ohci_hdl->ohci_drvinfo, &parms,
            &ohci_hdl->ohci_cfgrom, &ohci_hdl->ohci_cfgrom_handle);
        if (status != DDI_SUCCESS) {
                return (DDI_FAILURE);
        }

        /* Tell OpenHCI where the buffer is */
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->config_rom_maplo,
            (uint32_t)ohci_hdl->ohci_cfgrom.bi_cookie.dmac_address);

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_bus_capabilities()
 *    Return our current bus capabilities
 */
void
hci1394_ohci_bus_capabilities(hci1394_ohci_handle_t ohci_hdl,
    uint32_t *bus_capabilities)
{
        ASSERT(ohci_hdl != NULL);

        /*
         * read in the bus options register.  Set bits saying that we are isoch
         * resource manager capable, Cycle master capable, and Isoch capable
         */
        *bus_capabilities = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->bus_options) | (OHCI_BOPT_IRMC |
            OHCI_BOPT_CMC | OHCI_BOPT_ISC);
}


/*
 * hci1394_ohci_at_active()
 *    Returns status one if either of the AT engines are active.  If either AT
 *    engine is active, we return B_TRUE.  If both AT engines are not active, we
 *    return B_FALSE.
 */
boolean_t
hci1394_ohci_at_active(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t reg;


        ASSERT(ohci_hdl != NULL);

        /* see if atreq active bit set */
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_req.ctxt_ctrl_set);
        if (reg & OHCI_CC_ACTIVE_MASK) {
                /* atreq engine is still active */
                return (B_TRUE);
        }

        /* see if atresp active bit set */
        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_resp.ctxt_ctrl_set);
        if (reg & OHCI_CC_ACTIVE_MASK) {
                /* atresp engine is still active */
                return (B_TRUE);
        }

        /* both atreq and atresp active bits are cleared */
        return (B_FALSE);
}


/*
 * hci1394_ohci_atreq_start()
 *    Start the atreq dma engine.  Set the address of the first descriptor
 *    to read in equal to cmdptr.
 */
void
hci1394_ohci_atreq_start(hci1394_ohci_handle_t ohci_hdl, uint32_t cmdptr)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_req.cmd_ptrlo, cmdptr);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_req.ctxt_ctrl_set, OHCI_CC_RUN_MASK);
}


/*
 * hci1394_ohci_atreq_wake()
 *    Wake up the atreq dma engine.  This should be called when a new descriptor
 *    is added to the Q and the dma engine has already be started.  It it OK to
 *    call this when the DMA engine is active.
 */
void
hci1394_ohci_atreq_wake(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_req.ctxt_ctrl_set, OHCI_CC_WAKE_MASK);
}


/*
 * hci1394_ohci_atreq_stop()
 *    Stop the atreq dma engine.  No further descriptors will be read until
 *    it dma engine is started again.
 */
void
hci1394_ohci_atreq_stop(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_req.ctxt_ctrl_clr, OHCI_CC_RUN_MASK);
}


/*
 * hci1394_ohci_arresp_start()
 *    Start the arresp dma engine.  Set the address of the first descriptor
 *    to read in equal to cmdptr.
 */
void
hci1394_ohci_arresp_start(hci1394_ohci_handle_t ohci_hdl, uint32_t cmdptr)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ar_resp.cmd_ptrlo, cmdptr);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ar_resp.ctxt_ctrl_set, OHCI_CC_RUN_MASK);
}


/*
 * hci1394_ohci_arresp_wake()
 *    Wake up the arresp dma engine.  This should be called when a new
 *    descriptor is added to the Q and the dma engine has already be started.
 *    It is OK to call this when the DMA engine is active.
 */
void
hci1394_ohci_arresp_wake(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ar_resp.ctxt_ctrl_set, OHCI_CC_WAKE_MASK);
}


/*
 * hci1394_ohci_atreq_stop()
 *    Stop the arresp dma engine.  No further data will be received after any
 *    current packets being received have finished.
 */
void
hci1394_ohci_arresp_stop(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ar_resp.ctxt_ctrl_clr, OHCI_CC_RUN_MASK);
}


/*
 * hci1394_ohci_arreq_start()
 *    Start the arreq dma engine.  Set the address of the first descriptor
 *    to read in equal to cmdptr.
 */
void
hci1394_ohci_arreq_start(hci1394_ohci_handle_t ohci_hdl, uint32_t cmdptr)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ar_req.cmd_ptrlo, cmdptr);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ar_req.ctxt_ctrl_set, OHCI_CC_RUN_MASK);
}


/*
 * hci1394_ohci_arreq_wake()
 *    Wake up the arreq dma engine.  This should be called when a new descriptor
 *    is added to the Q and the dma engine has already be started.  It is OK to
 *    call this when the DMA engine is active.
 */
void
hci1394_ohci_arreq_wake(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ar_req.ctxt_ctrl_set, OHCI_CC_WAKE_MASK);
}


/*
 * hci1394_ohci_arreq_stop()
 *    Stop the arreq dma engine.  No further data will be received after any
 *    current packets being received have finished.
 */
void
hci1394_ohci_arreq_stop(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->ar_req.ctxt_ctrl_clr, OHCI_CC_RUN_MASK);
}


/*
 * hci1394_ohci_atresp_start()
 *    Start the atresp dma engine.  Set the address of the first descriptor
 *    to read in equal to cmdptr.
 */
void
hci1394_ohci_atresp_start(hci1394_ohci_handle_t ohci_hdl, uint32_t cmdptr)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_resp.cmd_ptrlo, cmdptr);
        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_resp.ctxt_ctrl_set, OHCI_CC_RUN_MASK);
}


/*
 * hci1394_ohci_atresp_wake()
 *    Wake up the atresp dma engine.  This should be called when a new
 *    descriptor is added to the Q and the dma engine has already be started.
 *    It is OK to call this when the DMA engine is active.
 */
void
hci1394_ohci_atresp_wake(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_resp.ctxt_ctrl_set, OHCI_CC_WAKE_MASK);
}


/*
 * hci1394_ohci_atresp_stop()
 *    Stop the atresp dma engine.  No further descriptors will be read until
 *    it dma engine is started again.
 */
void
hci1394_ohci_atresp_stop(hci1394_ohci_handle_t ohci_hdl)
{
        ASSERT(ohci_hdl != NULL);

        ddi_put32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->at_resp.ctxt_ctrl_clr, OHCI_CC_RUN_MASK);
}


/*
 * hci1394_ohci_1394a_init()
 *    Initialize any 1394a features that we are using.
 */
/* ARGSUSED */
int
hci1394_ohci_1394a_init(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t reg;
        int status;

        ASSERT(ohci_hdl != NULL);

        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->hc_ctrl_set);
        if (reg & OHCI_HC_PROG_PHY_ENBL) {
                ddi_put32(ohci_hdl->ohci_reg_handle,
                    &ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_APHY_ENBL);
                status = hci1394_ohci_phy_set(ohci_hdl, 5,
                    (OHCI_PHY_ENBL_ACCEL | OHCI_PHY_ENBL_MULTI));
                if (status != DDI_SUCCESS) {
                        return (DDI_FAILURE);
                }
        }

        return (DDI_SUCCESS);
}


/*
 * hci1394_ohci_1394a_init()
 *    Re-initialize any 1394a features that we are using.
 */
/* ARGSUSED */
int
hci1394_ohci_1394a_resume(hci1394_ohci_handle_t ohci_hdl)
{
        uint32_t reg;
        int status;

        ASSERT(ohci_hdl != NULL);

        reg = ddi_get32(ohci_hdl->ohci_reg_handle,
            &ohci_hdl->ohci_regs->hc_ctrl_set);
        if (reg & OHCI_HC_PROG_PHY_ENBL) {
                ddi_put32(ohci_hdl->ohci_reg_handle,
                    &ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_APHY_ENBL);
                status = hci1394_ohci_phy_set(ohci_hdl, 5,
                    (OHCI_PHY_ENBL_ACCEL | OHCI_PHY_ENBL_MULTI));
                if (status != DDI_SUCCESS) {
                        return (DDI_FAILURE);
                }
        }

        return (DDI_SUCCESS);
}