1258223a3SMatthew Dillon /* 2*fb00c6edSMatthew Dillon * (MPSAFE) 3*fb00c6edSMatthew Dillon * 4258223a3SMatthew Dillon * Copyright (c) 2009 The DragonFly Project. All rights reserved. 5258223a3SMatthew Dillon * 6258223a3SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 7258223a3SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 8258223a3SMatthew Dillon * 9258223a3SMatthew Dillon * Redistribution and use in source and binary forms, with or without 10258223a3SMatthew Dillon * modification, are permitted provided that the following conditions 11258223a3SMatthew Dillon * are met: 12258223a3SMatthew Dillon * 13258223a3SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 14258223a3SMatthew Dillon * notice, this list of conditions and the following disclaimer. 15258223a3SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 16258223a3SMatthew Dillon * notice, this list of conditions and the following disclaimer in 17258223a3SMatthew Dillon * the documentation and/or other materials provided with the 18258223a3SMatthew Dillon * distribution. 19258223a3SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 20258223a3SMatthew Dillon * contributors may be used to endorse or promote products derived 21258223a3SMatthew Dillon * from this software without specific, prior written permission. 22258223a3SMatthew Dillon * 23258223a3SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24258223a3SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25258223a3SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26258223a3SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27258223a3SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28258223a3SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 29258223a3SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30258223a3SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31258223a3SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32258223a3SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33258223a3SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34258223a3SMatthew Dillon * SUCH DAMAGE. 35258223a3SMatthew Dillon */ 36258223a3SMatthew Dillon /* 37258223a3SMatthew Dillon * Primary device and CAM interface to OpenBSD AHCI driver, for DragonFly 38258223a3SMatthew Dillon */ 39258223a3SMatthew Dillon 40258223a3SMatthew Dillon #include "ahci.h" 41258223a3SMatthew Dillon 42afa796d2SMatthew Dillon u_int32_t AhciForceGen1 = 0; 43afa796d2SMatthew Dillon u_int32_t AhciNoFeatures = 0; 44afa796d2SMatthew Dillon 45258223a3SMatthew Dillon /* 46258223a3SMatthew Dillon * Device bus methods 47258223a3SMatthew Dillon */ 48258223a3SMatthew Dillon 49258223a3SMatthew Dillon static int ahci_probe (device_t dev); 50258223a3SMatthew Dillon static int ahci_attach (device_t dev); 51258223a3SMatthew Dillon static int ahci_detach (device_t dev); 52795adb22SMatthew Dillon static int ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS); 53258223a3SMatthew Dillon #if 0 54258223a3SMatthew Dillon static int ahci_shutdown (device_t dev); 55258223a3SMatthew Dillon static int ahci_suspend (device_t dev); 56258223a3SMatthew Dillon static int ahci_resume (device_t dev); 57258223a3SMatthew Dillon #endif 58258223a3SMatthew Dillon 59f4553de1SMatthew Dillon static void ahci_port_thread(void *arg); 60f4553de1SMatthew Dillon 61258223a3SMatthew Dillon static device_method_t ahci_methods[] = { 62258223a3SMatthew Dillon DEVMETHOD(device_probe, ahci_probe), 63258223a3SMatthew Dillon DEVMETHOD(device_attach, ahci_attach), 64258223a3SMatthew Dillon DEVMETHOD(device_detach, ahci_detach), 65258223a3SMatthew Dillon #if 0 66258223a3SMatthew Dillon DEVMETHOD(device_shutdown, ahci_shutdown), 67258223a3SMatthew Dillon DEVMETHOD(device_suspend, ahci_suspend), 68258223a3SMatthew Dillon DEVMETHOD(device_resume, ahci_resume), 69258223a3SMatthew Dillon #endif 70258223a3SMatthew Dillon 71258223a3SMatthew Dillon DEVMETHOD(bus_print_child, bus_generic_print_child), 72258223a3SMatthew Dillon DEVMETHOD(bus_driver_added, bus_generic_driver_added), 73258223a3SMatthew Dillon {0, 0} 74258223a3SMatthew Dillon }; 75258223a3SMatthew Dillon 76258223a3SMatthew Dillon static devclass_t ahci_devclass; 77258223a3SMatthew Dillon 78258223a3SMatthew Dillon static driver_t ahci_driver = { 79258223a3SMatthew Dillon "ahci", 80258223a3SMatthew Dillon ahci_methods, 81258223a3SMatthew Dillon sizeof(struct ahci_softc) 82258223a3SMatthew Dillon }; 83258223a3SMatthew Dillon 84258223a3SMatthew Dillon MODULE_DEPEND(ahci, cam, 1, 1, 1); 85258223a3SMatthew Dillon DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, 0, 0); 86258223a3SMatthew Dillon 87258223a3SMatthew Dillon /* 88258223a3SMatthew Dillon * Device bus method procedures 89258223a3SMatthew Dillon */ 90258223a3SMatthew Dillon static int 91258223a3SMatthew Dillon ahci_probe (device_t dev) 92258223a3SMatthew Dillon { 93258223a3SMatthew Dillon const struct ahci_device *ad; 94258223a3SMatthew Dillon 95c45a2365SMatthew Dillon if (kgetenv("hint.ahci.disabled")) 96c45a2365SMatthew Dillon return(ENXIO); 970700c104SMatthew Dillon if (kgetenv("hint.ahci.force150")) 980700c104SMatthew Dillon AhciForceGen1 = -1; 99afa796d2SMatthew Dillon if (kgetenv("hint.ahci.nofeatures")) 100afa796d2SMatthew Dillon AhciNoFeatures = -1; 101c45a2365SMatthew Dillon 102258223a3SMatthew Dillon ad = ahci_lookup_device(dev); 103258223a3SMatthew Dillon if (ad) { 104258223a3SMatthew Dillon device_set_desc(dev, ad->name); 105258223a3SMatthew Dillon return(-5); /* higher priority the NATA */ 106258223a3SMatthew Dillon } 107258223a3SMatthew Dillon return(ENXIO); 108258223a3SMatthew Dillon } 109258223a3SMatthew Dillon 110258223a3SMatthew Dillon static int 111258223a3SMatthew Dillon ahci_attach (device_t dev) 112258223a3SMatthew Dillon { 113258223a3SMatthew Dillon struct ahci_softc *sc = device_get_softc(dev); 114f17a0cedSMatthew Dillon char name[16]; 115258223a3SMatthew Dillon int error; 116258223a3SMatthew Dillon 117258223a3SMatthew Dillon sc->sc_ad = ahci_lookup_device(dev); 118258223a3SMatthew Dillon if (sc->sc_ad == NULL) 119258223a3SMatthew Dillon return(ENXIO); 120f17a0cedSMatthew Dillon 121f17a0cedSMatthew Dillon sysctl_ctx_init(&sc->sysctl_ctx); 122f17a0cedSMatthew Dillon ksnprintf(name, sizeof(name), "%s%d", 123f17a0cedSMatthew Dillon device_get_name(dev), device_get_unit(dev)); 124f17a0cedSMatthew Dillon sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 125f17a0cedSMatthew Dillon SYSCTL_STATIC_CHILDREN(_hw), 126f17a0cedSMatthew Dillon OID_AUTO, name, CTLFLAG_RD, 0, ""); 127f17a0cedSMatthew Dillon 128258223a3SMatthew Dillon error = sc->sc_ad->ad_attach(dev); 129f17a0cedSMatthew Dillon if (error) { 130f17a0cedSMatthew Dillon sysctl_ctx_free(&sc->sysctl_ctx); 131f17a0cedSMatthew Dillon sc->sysctl_tree = NULL; 132f17a0cedSMatthew Dillon } 133258223a3SMatthew Dillon return (error); 134258223a3SMatthew Dillon } 135258223a3SMatthew Dillon 136258223a3SMatthew Dillon static int 137258223a3SMatthew Dillon ahci_detach (device_t dev) 138258223a3SMatthew Dillon { 139258223a3SMatthew Dillon struct ahci_softc *sc = device_get_softc(dev); 140258223a3SMatthew Dillon int error = 0; 141258223a3SMatthew Dillon 142f17a0cedSMatthew Dillon if (sc->sysctl_tree) { 143f17a0cedSMatthew Dillon sysctl_ctx_free(&sc->sysctl_ctx); 144f17a0cedSMatthew Dillon sc->sysctl_tree = NULL; 145f17a0cedSMatthew Dillon } 146258223a3SMatthew Dillon if (sc->sc_ad) { 147258223a3SMatthew Dillon error = sc->sc_ad->ad_detach(dev); 148258223a3SMatthew Dillon sc->sc_ad = NULL; 149258223a3SMatthew Dillon } 150258223a3SMatthew Dillon return(error); 151258223a3SMatthew Dillon } 152258223a3SMatthew Dillon 153f17a0cedSMatthew Dillon static int 154795adb22SMatthew Dillon ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS) 155f17a0cedSMatthew Dillon { 156f17a0cedSMatthew Dillon struct ahci_port *ap = arg1; 157f17a0cedSMatthew Dillon int error, link_pwr_mgmt; 158f17a0cedSMatthew Dillon 159f17a0cedSMatthew Dillon link_pwr_mgmt = ap->link_pwr_mgmt; 160f17a0cedSMatthew Dillon error = sysctl_handle_int(oidp, &link_pwr_mgmt, 0, req); 161f17a0cedSMatthew Dillon if (error || req->newptr == NULL) 162f17a0cedSMatthew Dillon return error; 163f17a0cedSMatthew Dillon 164f17a0cedSMatthew Dillon ahci_port_link_pwr_mgmt(ap, link_pwr_mgmt); 165f17a0cedSMatthew Dillon return 0; 166f17a0cedSMatthew Dillon } 167f17a0cedSMatthew Dillon 168795adb22SMatthew Dillon static int 169795adb22SMatthew Dillon ahci_sysctl_link_pwr_state (SYSCTL_HANDLER_ARGS) 170795adb22SMatthew Dillon { 171795adb22SMatthew Dillon struct ahci_port *ap = arg1; 172795adb22SMatthew Dillon const char *state_names[] = {"unknown", "active", "partial", "slumber"}; 173795adb22SMatthew Dillon char buf[16]; 174795adb22SMatthew Dillon int state; 175795adb22SMatthew Dillon 176795adb22SMatthew Dillon state = ahci_port_link_pwr_state(ap); 177795adb22SMatthew Dillon if (state < 0 || state >= sizeof(state_names) / sizeof(state_names[0])) 178795adb22SMatthew Dillon state = 0; 179795adb22SMatthew Dillon 180795adb22SMatthew Dillon ksnprintf(buf, sizeof(buf), "%s", state_names[state]); 181795adb22SMatthew Dillon return sysctl_handle_string(oidp, buf, sizeof(buf), req); 182795adb22SMatthew Dillon } 183795adb22SMatthew Dillon 184258223a3SMatthew Dillon #if 0 185258223a3SMatthew Dillon 186258223a3SMatthew Dillon static int 187258223a3SMatthew Dillon ahci_shutdown (device_t dev) 188258223a3SMatthew Dillon { 189258223a3SMatthew Dillon return (0); 190258223a3SMatthew Dillon } 191258223a3SMatthew Dillon 192258223a3SMatthew Dillon static int 193258223a3SMatthew Dillon ahci_suspend (device_t dev) 194258223a3SMatthew Dillon { 195258223a3SMatthew Dillon return (0); 196258223a3SMatthew Dillon } 197258223a3SMatthew Dillon 198258223a3SMatthew Dillon static int 199258223a3SMatthew Dillon ahci_resume (device_t dev) 200258223a3SMatthew Dillon { 201258223a3SMatthew Dillon return (0); 202258223a3SMatthew Dillon } 203258223a3SMatthew Dillon 204258223a3SMatthew Dillon #endif 2053209f581SMatthew Dillon 206831bc9e3SMatthew Dillon /* 207831bc9e3SMatthew Dillon * Sleep (ms) milliseconds, error on the side of caution. 208831bc9e3SMatthew Dillon */ 2093209f581SMatthew Dillon void 2103209f581SMatthew Dillon ahci_os_sleep(int ms) 2113209f581SMatthew Dillon { 2123209f581SMatthew Dillon int ticks; 2133209f581SMatthew Dillon 2143209f581SMatthew Dillon ticks = hz * ms / 1000 + 1; 2153209f581SMatthew Dillon tsleep(&ticks, 0, "ahslp", ticks); 2163209f581SMatthew Dillon } 217831bc9e3SMatthew Dillon 218831bc9e3SMatthew Dillon /* 219831bc9e3SMatthew Dillon * Sleep for a minimum interval and return the number of milliseconds 220831bc9e3SMatthew Dillon * that was. The minimum value returned is 1 221831bc9e3SMatthew Dillon */ 222831bc9e3SMatthew Dillon int 223831bc9e3SMatthew Dillon ahci_os_softsleep(void) 224831bc9e3SMatthew Dillon { 225831bc9e3SMatthew Dillon if (hz >= 1000) { 226831bc9e3SMatthew Dillon tsleep(&ticks, 0, "ahslp", hz / 1000); 227831bc9e3SMatthew Dillon return(1); 228831bc9e3SMatthew Dillon } else { 229831bc9e3SMatthew Dillon tsleep(&ticks, 0, "ahslp", 1); 230831bc9e3SMatthew Dillon return(1000 / hz); 231831bc9e3SMatthew Dillon } 232831bc9e3SMatthew Dillon } 233831bc9e3SMatthew Dillon 234831bc9e3SMatthew Dillon void 235831bc9e3SMatthew Dillon ahci_os_hardsleep(int us) 236831bc9e3SMatthew Dillon { 237831bc9e3SMatthew Dillon DELAY(us); 2383209f581SMatthew Dillon } 239f4553de1SMatthew Dillon 240f4553de1SMatthew Dillon /* 241f4553de1SMatthew Dillon * Create the OS-specific port helper thread and per-port lock. 242f4553de1SMatthew Dillon */ 243f4553de1SMatthew Dillon void 244f4553de1SMatthew Dillon ahci_os_start_port(struct ahci_port *ap) 245f4553de1SMatthew Dillon { 246f17a0cedSMatthew Dillon char name[16]; 247f17a0cedSMatthew Dillon 248e8cf3f55SMatthew Dillon atomic_set_int(&ap->ap_signal, AP_SIGF_INIT | AP_SIGF_THREAD_SYNC); 249f4553de1SMatthew Dillon lockinit(&ap->ap_lock, "ahcipo", 0, 0); 250*fb00c6edSMatthew Dillon lockinit(&ap->ap_sim_lock, "ahcicam", 0, LK_CANRECURSE); 251*fb00c6edSMatthew Dillon lockinit(&ap->ap_sig_lock, "ahport", 0, 0); 252f17a0cedSMatthew Dillon sysctl_ctx_init(&ap->sysctl_ctx); 253f17a0cedSMatthew Dillon ksnprintf(name, sizeof(name), "%d", ap->ap_num); 254f17a0cedSMatthew Dillon ap->sysctl_tree = SYSCTL_ADD_NODE(&ap->sysctl_ctx, 255f17a0cedSMatthew Dillon SYSCTL_CHILDREN(ap->ap_sc->sysctl_tree), 256f17a0cedSMatthew Dillon OID_AUTO, name, CTLFLAG_RD, 0, ""); 257f17a0cedSMatthew Dillon 258f17a0cedSMatthew Dillon if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SALP) && 259f17a0cedSMatthew Dillon (ap->ap_sc->sc_cap & (AHCI_REG_CAP_PSC | AHCI_REG_CAP_SSC))) { 260f17a0cedSMatthew Dillon SYSCTL_ADD_PROC(&ap->sysctl_ctx, 261f17a0cedSMatthew Dillon SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, 262f17a0cedSMatthew Dillon "link_pwr_mgmt", CTLTYPE_INT | CTLFLAG_RW, ap, 0, 263795adb22SMatthew Dillon ahci_sysctl_link_pwr_mgmt, "I", 264795adb22SMatthew Dillon "Link power management policy " 265f17a0cedSMatthew Dillon "(0 = disabled, 1 = medium, 2 = aggressive)"); 266795adb22SMatthew Dillon SYSCTL_ADD_PROC(&ap->sysctl_ctx, 267795adb22SMatthew Dillon SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, 268795adb22SMatthew Dillon "link_pwr_state", CTLTYPE_STRING | CTLFLAG_RD, ap, 0, 269795adb22SMatthew Dillon ahci_sysctl_link_pwr_state, "A", 270795adb22SMatthew Dillon "Link power management state"); 271f17a0cedSMatthew Dillon 272f17a0cedSMatthew Dillon } 273f17a0cedSMatthew Dillon 274f4553de1SMatthew Dillon kthread_create(ahci_port_thread, ap, &ap->ap_thread, 275f4553de1SMatthew Dillon "%s", PORTNAME(ap)); 276f4553de1SMatthew Dillon } 277f4553de1SMatthew Dillon 278f4553de1SMatthew Dillon /* 279f4553de1SMatthew Dillon * Stop the OS-specific port helper thread and kill the per-port lock. 280f4553de1SMatthew Dillon */ 281f4553de1SMatthew Dillon void 282f4553de1SMatthew Dillon ahci_os_stop_port(struct ahci_port *ap) 283f4553de1SMatthew Dillon { 284f17a0cedSMatthew Dillon if (ap->sysctl_tree) { 285f17a0cedSMatthew Dillon sysctl_ctx_free(&ap->sysctl_ctx); 286f17a0cedSMatthew Dillon ap->sysctl_tree = NULL; 287f17a0cedSMatthew Dillon } 288f17a0cedSMatthew Dillon 289f4553de1SMatthew Dillon if (ap->ap_thread) { 290f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_STOP); 291f4553de1SMatthew Dillon ahci_os_sleep(10); 292f4553de1SMatthew Dillon if (ap->ap_thread) { 293f4553de1SMatthew Dillon kprintf("%s: Waiting for thread to terminate\n", 294f4553de1SMatthew Dillon PORTNAME(ap)); 295f4553de1SMatthew Dillon while (ap->ap_thread) 296f4553de1SMatthew Dillon ahci_os_sleep(100); 297f4553de1SMatthew Dillon kprintf("%s: thread terminated\n", 298f4553de1SMatthew Dillon PORTNAME(ap)); 299f4553de1SMatthew Dillon } 300f4553de1SMatthew Dillon } 301f4553de1SMatthew Dillon lockuninit(&ap->ap_lock); 302f4553de1SMatthew Dillon } 303f4553de1SMatthew Dillon 304f4553de1SMatthew Dillon /* 305f4553de1SMatthew Dillon * Add (mask) to the set of bits being sent to the per-port thread helper 306f4553de1SMatthew Dillon * and wake the helper up if necessary. 307f4553de1SMatthew Dillon */ 308f4553de1SMatthew Dillon void 309f4553de1SMatthew Dillon ahci_os_signal_port_thread(struct ahci_port *ap, int mask) 310f4553de1SMatthew Dillon { 311*fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE); 312f4553de1SMatthew Dillon atomic_set_int(&ap->ap_signal, mask); 313f4553de1SMatthew Dillon wakeup(&ap->ap_thread); 314*fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_RELEASE); 315f4553de1SMatthew Dillon } 316f4553de1SMatthew Dillon 317f4553de1SMatthew Dillon /* 318f4553de1SMatthew Dillon * Unconditionally lock the port structure for access. 319f4553de1SMatthew Dillon */ 320f4553de1SMatthew Dillon void 321f4553de1SMatthew Dillon ahci_os_lock_port(struct ahci_port *ap) 322f4553de1SMatthew Dillon { 323f4553de1SMatthew Dillon lockmgr(&ap->ap_lock, LK_EXCLUSIVE); 324f4553de1SMatthew Dillon } 325f4553de1SMatthew Dillon 326f4553de1SMatthew Dillon /* 327f4553de1SMatthew Dillon * Conditionally lock the port structure for access. 328f4553de1SMatthew Dillon * 329f4553de1SMatthew Dillon * Returns 0 on success, non-zero on failure. 330f4553de1SMatthew Dillon */ 331f4553de1SMatthew Dillon int 332f4553de1SMatthew Dillon ahci_os_lock_port_nb(struct ahci_port *ap) 333f4553de1SMatthew Dillon { 334f4553de1SMatthew Dillon return (lockmgr(&ap->ap_lock, LK_EXCLUSIVE | LK_NOWAIT)); 335f4553de1SMatthew Dillon } 336f4553de1SMatthew Dillon 337f4553de1SMatthew Dillon /* 338f4553de1SMatthew Dillon * Unlock a previously locked port. 339f4553de1SMatthew Dillon */ 340f4553de1SMatthew Dillon void 341f4553de1SMatthew Dillon ahci_os_unlock_port(struct ahci_port *ap) 342f4553de1SMatthew Dillon { 343f4553de1SMatthew Dillon lockmgr(&ap->ap_lock, LK_RELEASE); 344f4553de1SMatthew Dillon } 345f4553de1SMatthew Dillon 346f4553de1SMatthew Dillon /* 347f4553de1SMatthew Dillon * Per-port thread helper. This helper thread is responsible for 348f4553de1SMatthew Dillon * atomically retrieving and clearing the signal mask and calling 349f4553de1SMatthew Dillon * the machine-independant driver core. 350f4553de1SMatthew Dillon */ 351f4553de1SMatthew Dillon static 352f4553de1SMatthew Dillon void 353f4553de1SMatthew Dillon ahci_port_thread(void *arg) 354f4553de1SMatthew Dillon { 355f4553de1SMatthew Dillon struct ahci_port *ap = arg; 356f4553de1SMatthew Dillon int mask; 357f4553de1SMatthew Dillon 358*fb00c6edSMatthew Dillon rel_mplock(); 359*fb00c6edSMatthew Dillon 360f4553de1SMatthew Dillon /* 361f4553de1SMatthew Dillon * The helper thread is responsible for the initial port init, 362f4553de1SMatthew Dillon * so all the ports can be inited in parallel. 363f4553de1SMatthew Dillon * 364f4553de1SMatthew Dillon * We also run the state machine which should do all probes. 365f4553de1SMatthew Dillon * Since CAM is not attached yet we will not get out-of-order 366f4553de1SMatthew Dillon * SCSI attachments. 367f4553de1SMatthew Dillon */ 368f4553de1SMatthew Dillon ahci_os_lock_port(ap); 36912feb904SMatthew Dillon ahci_port_init(ap); 370e8cf3f55SMatthew Dillon atomic_clear_int(&ap->ap_signal, AP_SIGF_THREAD_SYNC); 371e8cf3f55SMatthew Dillon wakeup(&ap->ap_signal); 372831bc9e3SMatthew Dillon ahci_port_state_machine(ap, 1); 373f4553de1SMatthew Dillon ahci_os_unlock_port(ap); 374f4553de1SMatthew Dillon atomic_clear_int(&ap->ap_signal, AP_SIGF_INIT); 375f4553de1SMatthew Dillon wakeup(&ap->ap_signal); 376f4553de1SMatthew Dillon 377f4553de1SMatthew Dillon /* 378f4553de1SMatthew Dillon * Then loop on the helper core. 379f4553de1SMatthew Dillon */ 380f4553de1SMatthew Dillon mask = ap->ap_signal; 381f4553de1SMatthew Dillon while ((mask & AP_SIGF_STOP) == 0) { 382f4553de1SMatthew Dillon atomic_clear_int(&ap->ap_signal, mask); 383f4553de1SMatthew Dillon ahci_port_thread_core(ap, mask); 384*fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE); 385*fb00c6edSMatthew Dillon if (ap->ap_signal == 0) { 386*fb00c6edSMatthew Dillon lksleep(&ap->ap_thread, &ap->ap_sig_lock, 0, 387*fb00c6edSMatthew Dillon "ahport", 0); 388*fb00c6edSMatthew Dillon } 389*fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_RELEASE); 390f4553de1SMatthew Dillon mask = ap->ap_signal; 391f4553de1SMatthew Dillon } 392f4553de1SMatthew Dillon ap->ap_thread = NULL; 393f4553de1SMatthew Dillon } 394