summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Matthew <jmatthew@cvs.openbsd.org>2011-10-27 08:03:51 +0000
committerJonathan Matthew <jmatthew@cvs.openbsd.org>2011-10-27 08:03:51 +0000
commit169821d872c8e101e3e932d064f2d0be4184a1d1 (patch)
tree8cafc81f098722de921d83ba0521a4031fe45418
parent1691111ad60eba52ce586a07d639efeac20f3023 (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.c44
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);
}