/* * 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 #include #include #include #include #include #include #include #include #include /* * 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 | 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, ®); 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, ®); 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, ®); 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, ®); 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, ®); 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); }