diff options
author | Jonathan Matthew <jmatthew@cvs.openbsd.org> | 2011-10-27 08:03:51 +0000 |
---|---|---|
committer | Jonathan Matthew <jmatthew@cvs.openbsd.org> | 2011-10-27 08:03:51 +0000 |
commit | 169821d872c8e101e3e932d064f2d0be4184a1d1 (patch) | |
tree | 8cafc81f098722de921d83ba0521a4031fe45418 | |
parent | 1691111ad60eba52ce586a07d639efeac20f3023 (diff) |
Split AHCI port multiplier detection out into a separate function.
As a side effect, we now restore the correct (original) command register
value rather than one read halfway through the reset process, which
gets port multipliers working on some ATI devices. Also tested on JMicron
and Intel AHCIs.
ok dlg@
-rw-r--r-- | sys/dev/pci/ahci.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/sys/dev/pci/ahci.c b/sys/dev/pci/ahci.c index 53cb7a73516..59f163648dc 100644 --- a/sys/dev/pci/ahci.c +++ b/sys/dev/pci/ahci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ahci.c,v 1.183 2011/10/26 10:59:00 jmatthew Exp $ */ +/* $OpenBSD: ahci.c,v 1.184 2011/10/27 08:03:50 jmatthew Exp $ */ /* * Copyright (c) 2006 David Gwynne <dlg@openbsd.org> @@ -606,6 +606,7 @@ int ahci_pwait_eq(struct ahci_port *, bus_size_t, u_int32_t, u_int32_t, int); void ahci_flush_tfd(struct ahci_port *ap); u_int32_t ahci_active_mask(struct ahci_port *); +int ahci_port_detect_pmp(struct ahci_port *); void ahci_pmp_probe_timeout(void *); /* pmp operations */ @@ -2030,10 +2031,7 @@ int ahci_port_portreset(struct ahci_port *ap, int pmp) { u_int32_t cmd, r; - int rc, count, pmp_rc, s; - struct ahci_cmd_hdr *cmd_slot; - struct ahci_ccb *ccb = NULL; - u_int8_t *fis = NULL; + int rc, s; s = splbio(); DPRINTF(AHCI_D_VERBOSE, "%s: port reset\n", PORTNAME(ap)); @@ -2087,12 +2085,35 @@ ahci_port_portreset(struct ahci_port *ap, int pmp) } } - if (pmp == 0 || - (ap->ap_sc->sc_flags & AHCI_F_NO_PMP) || + if (pmp != 0) { + if (ahci_port_detect_pmp(ap) != 0) { + rc = EBUSY; + } + } + +err: + /* Restore preserved port state */ + ahci_pwrite(ap, AHCI_PREG_CMD, cmd); + splx(s); + + return (rc); +} + +int +ahci_port_detect_pmp(struct ahci_port *ap) +{ + int count, pmp_rc, rc; + u_int32_t r, cmd; + struct ahci_cmd_hdr *cmd_slot; + struct ahci_ccb *ccb = NULL; + u_int8_t *fis = NULL; + + if ((ap->ap_sc->sc_flags & AHCI_F_NO_PMP) || !ISSET(ahci_read(ap->ap_sc, AHCI_REG_CAP), AHCI_REG_CAP_SPM)) { - goto err; + return 0; } + rc = 0; pmp_rc = 0; count = 2; do { @@ -2133,7 +2154,7 @@ ahci_port_portreset(struct ahci_port *ap, int pmp) */ /* Restart port */ if (ahci_port_start(ap, 0)) { - rc = 1; + rc = EBUSY; printf("%s: failed to start port, cannot probe PMP\n", PORTNAME(ap)); break; @@ -2280,11 +2301,6 @@ ahci_port_portreset(struct ahci_port *ap, int pmp) ahci_port_portreset(ap, 0); } -err: - /* Restore preserved port state */ - ahci_pwrite(ap, AHCI_PREG_CMD, cmd); - splx(s); - return (rc); } |