1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*
28 * hci1394_detach.c
29 * HBA detach() routine with associated funtions.
30 */
31
32 #include <sys/types.h>
33 #include <sys/kmem.h>
34 #include <sys/conf.h>
35 #include <sys/ddi.h>
36 #include <sys/modctl.h>
37 #include <sys/stat.h>
38 #include <sys/sunddi.h>
39
40 #include <sys/1394/h1394.h>
41 #include <sys/1394/adapters/hci1394.h>
42 #include <sys/1394/adapters/hci1394_extern.h>
43
44
45
46 int
hci1394_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)47 hci1394_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
48 {
49 hci1394_state_t *soft_state;
50
51
52 TNF_PROBE_0_DEBUG(hci1394_detach_enter, HCI1394_TNF_HAL_STACK, "");
53
54 soft_state = ddi_get_soft_state(hci1394_statep, ddi_get_instance(dip));
55 if (soft_state == NULL) {
56 TNF_PROBE_1(hci1394_detach_ssn_fail, HCI1394_TNF_HAL_ERROR, "",
57 tnf_string, errmsg, "soft_state = NULL");
58 TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK,
59 "");
60 return (DDI_FAILURE);
61 }
62
63 switch (cmd) {
64 case DDI_DETACH:
65 /* Don't allow the HW to generate any more interrupts */
66 hci1394_ohci_intr_master_disable(soft_state->ohci);
67 hci1394_ohci_it_intr_disable(soft_state->ohci, 0xFFFFFFFF);
68 hci1394_ohci_ir_intr_disable(soft_state->ohci, 0xFFFFFFFF);
69
70 /* Clear any pending interrupts - no longer valid */
71 hci1394_ohci_intr_clear(soft_state->ohci, 0xFFFFFFFF);
72 hci1394_ohci_it_intr_clear(soft_state->ohci, 0xFFFFFFFF);
73 hci1394_ohci_ir_intr_clear(soft_state->ohci, 0xFFFFFFFF);
74
75 /* Make sure we tell others on the bus we are dropping out */
76 (void) hci1394_ohci_phy_clr(soft_state->ohci, 4, 0xc0);
77 ddi_put32(soft_state->ohci->ohci_reg_handle,
78 &soft_state->ohci->ohci_regs->link_ctrl_clr,
79 0xFFFFFFFF);
80
81 /* unregister interrupt handler */
82 hci1394_isr_handler_fini(soft_state);
83
84 /* don't accept anymore commands from services layer */
85 (void) hci1394_state_set(&soft_state->drvinfo,
86 HCI1394_SHUTDOWN);
87
88 /* Do a long reset on the bus so every one knows we are gone */
89 (void) hci1394_ohci_bus_reset_nroot(soft_state->ohci);
90
91 /* Reset the OHCI HW */
92 (void) hci1394_ohci_soft_reset(soft_state->ohci);
93
94 /* Flush out async DMA Q's (cancels pendingQ timeouts too) */
95 hci1394_async_flush(soft_state->async);
96
97 (void) h1394_detach(&soft_state->drvinfo.di_sl_private,
98 DDI_DETACH);
99
100 /* remove the minor node */
101 ddi_remove_minor_node(dip, "devctl");
102
103 /* cleanup */
104 hci1394_detach_hardware(soft_state);
105
106 /* cleanup Solaris interrupt stuff */
107 hci1394_isr_fini(soft_state);
108
109 /* cleanup soft state stuff */
110 hci1394_soft_state_fini(soft_state);
111
112 /* free soft state */
113 ddi_soft_state_free(hci1394_statep,
114 soft_state->drvinfo.di_instance);
115
116 TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK,
117 "");
118 return (DDI_SUCCESS);
119
120 case DDI_SUSPEND:
121 /* Don't allow the HW to generate any more interrupts */
122 hci1394_ohci_intr_master_disable(soft_state->ohci);
123 hci1394_ohci_it_intr_disable(soft_state->ohci, 0xFFFFFFFF);
124 hci1394_ohci_ir_intr_disable(soft_state->ohci, 0xFFFFFFFF);
125
126 /* Clear any pending interrupts - no longer valid */
127 hci1394_ohci_intr_clear(soft_state->ohci, 0xFFFFFFFF);
128 hci1394_ohci_it_intr_clear(soft_state->ohci, 0xFFFFFFFF);
129 hci1394_ohci_ir_intr_clear(soft_state->ohci, 0xFFFFFFFF);
130
131 /* Make sure we tell others on the bus we are dropping out */
132 (void) hci1394_ohci_phy_clr(soft_state->ohci, 4, 0xc0);
133 ddi_put32(soft_state->ohci->ohci_reg_handle,
134 &soft_state->ohci->ohci_regs->link_ctrl_clr,
135 0xFFFFFFFF);
136
137 /* don't accept anymore commands from services layer */
138 (void) hci1394_state_set(&soft_state->drvinfo,
139 HCI1394_SHUTDOWN);
140
141 /* Do a long reset on the bus so every one knows we are gone */
142 (void) hci1394_ohci_bus_reset_nroot(soft_state->ohci);
143
144 /* Reset the OHCI HW */
145 (void) hci1394_ohci_soft_reset(soft_state->ohci);
146
147 /* Make sure async engine is ready to suspend */
148 hci1394_async_suspend(soft_state->async);
149
150 (void) h1394_detach(&soft_state->drvinfo.di_sl_private,
151 DDI_SUSPEND);
152
153 TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK,
154 "");
155 return (DDI_SUCCESS);
156
157 default:
158 TNF_PROBE_1(hci1394_detach_fail, HCI1394_TNF_HAL_ERROR, "",
159 tnf_string, errmsg, "in detach default");
160 break;
161 }
162
163 TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK, "");
164
165 return (DDI_FAILURE);
166 }
167
168 /*
169 * quiesce(9E) entry point.
170 *
171 * This function is called when the system is single-threaded at high
172 * PIL with preemption disabled. Therefore, this function must not be
173 * blocked.
174 *
175 * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
176 * DDI_FAILURE indicates an error condition and should almost never happen.
177 */
178 int
hci1394_quiesce(dev_info_t * dip)179 hci1394_quiesce(dev_info_t *dip)
180 {
181 hci1394_state_t *soft_state;
182
183 soft_state = ddi_get_soft_state(hci1394_statep, ddi_get_instance(dip));
184
185 if (soft_state == NULL) {
186 return (DDI_FAILURE);
187 }
188
189 /* Don't allow the HW to generate any more interrupts */
190 hci1394_ohci_intr_master_disable(soft_state->ohci);
191 hci1394_ohci_it_intr_disable(soft_state->ohci, 0xFFFFFFFF);
192 hci1394_ohci_ir_intr_disable(soft_state->ohci, 0xFFFFFFFF);
193
194 /* Clear any pending interrupts - no longer valid */
195 hci1394_ohci_intr_clear(soft_state->ohci, 0xFFFFFFFF);
196 hci1394_ohci_it_intr_clear(soft_state->ohci, 0xFFFFFFFF);
197 hci1394_ohci_ir_intr_clear(soft_state->ohci, 0xFFFFFFFF);
198
199 /* Make sure we tell others on the bus we are dropping out */
200 (void) hci1394_ohci_phy_clr(soft_state->ohci, 4, 0xc0);
201 ddi_put32(soft_state->ohci->ohci_reg_handle,
202 &soft_state->ohci->ohci_regs->link_ctrl_clr, 0xFFFFFFFF);
203
204 /* Do a long reset on the bus so every one knows we are gone */
205 (void) hci1394_ohci_bus_reset_nroot(soft_state->ohci);
206
207 /* Reset the OHCI HW */
208 (void) hci1394_ohci_soft_reset(soft_state->ohci);
209
210 return (DDI_SUCCESS);
211 }
212
213 void
hci1394_detach_hardware(hci1394_state_t * soft_state)214 hci1394_detach_hardware(hci1394_state_t *soft_state)
215 {
216 ASSERT(soft_state != NULL);
217 TNF_PROBE_0_DEBUG(hci1394_detach_hardware_enter, HCI1394_TNF_HAL_STACK,
218 "");
219
220 /* free up vendor specific registers */
221 hci1394_vendor_fini(&soft_state->vendor);
222
223 /* cleanup isoch layer */
224 hci1394_isoch_fini(&soft_state->isoch);
225
226 /* cleanup async layer */
227 hci1394_async_fini(&soft_state->async);
228
229 /* Free up csr register space */
230 hci1394_csr_fini(&soft_state->csr);
231
232 /* free up OpenHCI registers */
233 hci1394_ohci_fini(&soft_state->ohci);
234
235 /* free up PCI config space */
236 hci1394_pci_fini(soft_state);
237
238 TNF_PROBE_0_DEBUG(hci1394_detach_hardware_exit, HCI1394_TNF_HAL_STACK,
239 "");
240 }
241
242
243 /*
244 * hci1394_pci_fini()
245 * Cleanup after a PCI init.
246 */
247 void
hci1394_pci_fini(hci1394_state_t * soft_state)248 hci1394_pci_fini(hci1394_state_t *soft_state)
249 {
250 ASSERT(soft_state != NULL);
251 TNF_PROBE_0_DEBUG(hci1394_pci_fini_enter, HCI1394_TNF_HAL_STACK, "");
252 pci_config_teardown(&soft_state->pci_config);
253 TNF_PROBE_0_DEBUG(hci1394_pci_fini_exit, HCI1394_TNF_HAL_STACK, "");
254 }
255
256
257 /*
258 * hci1394_soft_state_fini()
259 * Cleanup any mutex's, etc. in soft_state.
260 */
261 void
hci1394_soft_state_fini(hci1394_state_t * soft_state)262 hci1394_soft_state_fini(hci1394_state_t *soft_state)
263 {
264 ASSERT(soft_state != NULL);
265 TNF_PROBE_0_DEBUG(hci1394_soft_state_fini_enter, HCI1394_TNF_HAL_STACK,
266 "");
267 mutex_destroy(&soft_state->drvinfo.di_drvstate.ds_mutex);
268 TNF_PROBE_0_DEBUG(hci1394_soft_state_fini_exit, HCI1394_TNF_HAL_STACK,
269 "");
270 }
271