/* * 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. */ /* * hci1394_detach.c * HBA detach() routine with associated funtions. */ #include #include #include #include #include #include #include #include #include #include int hci1394_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { hci1394_state_t *soft_state; soft_state = ddi_get_soft_state(hci1394_statep, ddi_get_instance(dip)); if (soft_state == NULL) { return (DDI_FAILURE); } switch (cmd) { case DDI_DETACH: /* Don't allow the HW to generate any more interrupts */ hci1394_ohci_intr_master_disable(soft_state->ohci); hci1394_ohci_it_intr_disable(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_disable(soft_state->ohci, 0xFFFFFFFF); /* Clear any pending interrupts - no longer valid */ hci1394_ohci_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_it_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_clear(soft_state->ohci, 0xFFFFFFFF); /* Make sure we tell others on the bus we are dropping out */ (void) hci1394_ohci_phy_clr(soft_state->ohci, 4, 0xc0); ddi_put32(soft_state->ohci->ohci_reg_handle, &soft_state->ohci->ohci_regs->link_ctrl_clr, 0xFFFFFFFF); /* unregister interrupt handler */ hci1394_isr_handler_fini(soft_state); /* don't accept anymore commands from services layer */ (void) hci1394_state_set(&soft_state->drvinfo, HCI1394_SHUTDOWN); /* Do a long reset on the bus so every one knows we are gone */ (void) hci1394_ohci_bus_reset_nroot(soft_state->ohci); /* Reset the OHCI HW */ (void) hci1394_ohci_soft_reset(soft_state->ohci); /* Flush out async DMA Q's (cancels pendingQ timeouts too) */ hci1394_async_flush(soft_state->async); (void) h1394_detach(&soft_state->drvinfo.di_sl_private, DDI_DETACH); /* remove the minor node */ ddi_remove_minor_node(dip, "devctl"); /* cleanup */ hci1394_detach_hardware(soft_state); /* cleanup Solaris interrupt stuff */ hci1394_isr_fini(soft_state); /* cleanup soft state stuff */ hci1394_soft_state_fini(soft_state); /* free soft state */ ddi_soft_state_free(hci1394_statep, soft_state->drvinfo.di_instance); return (DDI_SUCCESS); case DDI_SUSPEND: /* Don't allow the HW to generate any more interrupts */ hci1394_ohci_intr_master_disable(soft_state->ohci); hci1394_ohci_it_intr_disable(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_disable(soft_state->ohci, 0xFFFFFFFF); /* Clear any pending interrupts - no longer valid */ hci1394_ohci_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_it_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_clear(soft_state->ohci, 0xFFFFFFFF); /* Make sure we tell others on the bus we are dropping out */ (void) hci1394_ohci_phy_clr(soft_state->ohci, 4, 0xc0); ddi_put32(soft_state->ohci->ohci_reg_handle, &soft_state->ohci->ohci_regs->link_ctrl_clr, 0xFFFFFFFF); /* don't accept anymore commands from services layer */ (void) hci1394_state_set(&soft_state->drvinfo, HCI1394_SHUTDOWN); /* Do a long reset on the bus so every one knows we are gone */ (void) hci1394_ohci_bus_reset_nroot(soft_state->ohci); /* Reset the OHCI HW */ (void) hci1394_ohci_soft_reset(soft_state->ohci); /* Make sure async engine is ready to suspend */ hci1394_async_suspend(soft_state->async); (void) h1394_detach(&soft_state->drvinfo.di_sl_private, DDI_SUSPEND); return (DDI_SUCCESS); default: break; } return (DDI_FAILURE); } /* * quiesce(9E) entry point. * * This function is called when the system is single-threaded at high * PIL with preemption disabled. Therefore, this function must not be * blocked. * * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. * DDI_FAILURE indicates an error condition and should almost never happen. */ int hci1394_quiesce(dev_info_t *dip) { hci1394_state_t *soft_state; soft_state = ddi_get_soft_state(hci1394_statep, ddi_get_instance(dip)); if (soft_state == NULL) { return (DDI_FAILURE); } /* Don't allow the HW to generate any more interrupts */ hci1394_ohci_intr_master_disable(soft_state->ohci); hci1394_ohci_it_intr_disable(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_disable(soft_state->ohci, 0xFFFFFFFF); /* Clear any pending interrupts - no longer valid */ hci1394_ohci_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_it_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_clear(soft_state->ohci, 0xFFFFFFFF); /* Make sure we tell others on the bus we are dropping out */ (void) hci1394_ohci_phy_clr(soft_state->ohci, 4, 0xc0); ddi_put32(soft_state->ohci->ohci_reg_handle, &soft_state->ohci->ohci_regs->link_ctrl_clr, 0xFFFFFFFF); /* Do a long reset on the bus so every one knows we are gone */ (void) hci1394_ohci_bus_reset_nroot(soft_state->ohci); /* Reset the OHCI HW */ (void) hci1394_ohci_soft_reset(soft_state->ohci); return (DDI_SUCCESS); } void hci1394_detach_hardware(hci1394_state_t *soft_state) { ASSERT(soft_state != NULL); /* free up vendor specific registers */ hci1394_vendor_fini(&soft_state->vendor); /* cleanup isoch layer */ hci1394_isoch_fini(&soft_state->isoch); /* cleanup async layer */ hci1394_async_fini(&soft_state->async); /* Free up csr register space */ hci1394_csr_fini(&soft_state->csr); /* free up OpenHCI registers */ hci1394_ohci_fini(&soft_state->ohci); /* free up PCI config space */ hci1394_pci_fini(soft_state); } /* * hci1394_pci_fini() * Cleanup after a PCI init. */ void hci1394_pci_fini(hci1394_state_t *soft_state) { ASSERT(soft_state != NULL); pci_config_teardown(&soft_state->pci_config); } /* * hci1394_soft_state_fini() * Cleanup any mutex's, etc. in soft_state. */ void hci1394_soft_state_fini(hci1394_state_t *soft_state) { ASSERT(soft_state != NULL); mutex_destroy(&soft_state->drvinfo.di_drvstate.ds_mutex); }