Module Name:    src
Committed By:   martin
Date:           Wed Dec 30 15:12:38 UTC 2020

Modified Files:
        src/sys/arch/arm/nvidia [netbsd-9]: tegra_ahcisata.c
        src/sys/dev/ata [netbsd-9]: satareg.h
        src/sys/dev/ic [netbsd-9]: ahcisata_core.c ahcisatavar.h

Log Message:
Pull up following revision(s) (requested by jmcneill in ticket #1167):

        sys/dev/ic/ahcisata_core.c: revision 1.84
        sys/dev/ic/ahcisata_core.c: revision 1.85
        sys/dev/ic/ahcisata_core.c: revision 1.88
        sys/dev/ic/ahcisata_core.c: revision 1.89
        sys/arch/arm/nvidia/tegra_ahcisata.c: revision 1.13
        sys/dev/ic/ahcisatavar.h: revision 1.26
        sys/dev/ic/ahcisata_core.c: revision 1.90
        sys/dev/ic/ahcisata_core.c: revision 1.91
        sys/dev/ic/ahcisata_core.c: revision 1.92
        sys/dev/ata/satareg.h: revision 1.6

ahci_exec_fis: wait for the correct amount of time when AT_WAIT is set

Retry clearing WDCTL_RST a few times before giving up. Makes SATA work in
Solidrun Honeycomb LX2K.

AHCI 1.3.1 specification says that it is good practice for system software
to 'zero-out' the memory allocated and referenced by PxCLB and PxFB.

ahci_intr: use ffs in the port bitmask instead of looping over all 32 bits

AHCI 1.3.1 section 5.5.3 "Processing Completed Commands" says that we
should clear PxIS before IS.IPS.

Add G3 and DevSleep definitions. This changes the mask used by
SControl_IPM_NONE from 0x3 to 0x7.

Make sure to ack IS after PxIS when polling and when using multiple MSI-X
messages.

Remove the AHCI_QUIRK_SKIP_RESET quirk now that the underlying issue is
fixed.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.12.4.1 src/sys/arch/arm/nvidia/tegra_ahcisata.c
cvs rdiff -u -r1.5 -r1.5.94.1 src/sys/dev/ata/satareg.h
cvs rdiff -u -r1.75.4.3 -r1.75.4.4 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.22.4.1 -r1.22.4.2 src/sys/dev/ic/ahcisatavar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/nvidia/tegra_ahcisata.c
diff -u src/sys/arch/arm/nvidia/tegra_ahcisata.c:1.12 src/sys/arch/arm/nvidia/tegra_ahcisata.c:1.12.4.1
--- src/sys/arch/arm/nvidia/tegra_ahcisata.c:1.12	Fri Dec 14 12:29:22 2018
+++ src/sys/arch/arm/nvidia/tegra_ahcisata.c	Wed Dec 30 15:12:38 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_ahcisata.c,v 1.12 2018/12/14 12:29:22 skrll Exp $ */
+/* $NetBSD: tegra_ahcisata.c,v 1.12.4.1 2020/12/30 15:12:38 martin Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_ahcisata.c,v 1.12 2018/12/14 12:29:22 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_ahcisata.c,v 1.12.4.1 2020/12/30 15:12:38 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -202,7 +202,6 @@ tegra_ahcisata_attach(device_t parent, d
 		aprint_error(": couldn't map ahci registers: %d\n", error);
 		return;
 	}
-	sc->sc.sc_ahci_quirks = AHCI_QUIRK_SKIP_RESET;
 
 	aprint_naive("\n");
 	aprint_normal(": SATA\n");

Index: src/sys/dev/ata/satareg.h
diff -u src/sys/dev/ata/satareg.h:1.5 src/sys/dev/ata/satareg.h:1.5.94.1
--- src/sys/dev/ata/satareg.h:1.5	Mon Apr 28 20:23:47 2008
+++ src/sys/dev/ata/satareg.h	Wed Dec 30 15:12:38 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: satareg.h,v 1.5 2008/04/28 20:23:47 martin Exp $	*/
+/*	$NetBSD: satareg.h,v 1.5.94.1 2020/12/30 15:12:38 martin Exp $	*/
 
 /*-
  * Copyright (c) 2003 The NetBSD Foundation, Inc.
@@ -65,6 +65,7 @@
 #define	SStatus_SPD_NONE	(0x0 << 4)	/* no negotiated speed */
 #define	SStatus_SPD_G1		(0x1 << 4)	/* Generation 1 (1.5Gb/s) */
 #define	SStatus_SPD_G2		(0x2 << 4)	/* Generation 2 (3.0Gb/s) */
+#define	SStatus_SPD_G3		(0x3 << 4)	/* Generation 3 (6.0Gb/s) */
 #define	SStatus_SPD_mask	(0xf << 4)
 #define	SStatus_SPD_shift	4
 	/*
@@ -75,6 +76,7 @@
 #define	SStatus_IPM_ACTIVE	(0x1 << 8)	/* ACTIVE state */
 #define	SStatus_IPM_PARTIAL	(0x2 << 8)	/* PARTIAL pm state */
 #define	SStatus_IPM_SLUMBER	(0x6 << 8)	/* SLUMBER pm state */
+#define	SStatus_IPM_DEVSLEEP	(0x8 << 8)	/* DevSleep pm state */
 #define	SStatus_IPM_mask	(0xf << 8)
 #define	SStatus_IPM_shift	8
 
@@ -130,6 +132,7 @@
 #define	SControl_SPD_ANY	(0x0 << 4)	/* No restrictions */
 #define	SControl_SPD_G1		(0x1 << 4)	/* Generation 1 (1.5Gb/s) */
 #define	SControl_SPD_G2		(0x2 << 4)	/* Generation 2 (3.0Gb/s) */
+#define	SControl_SPD_G3		(0x3 << 4)	/* Generation 3 (6.0Gb/s) */
 	/*
 	 * The IPM field represents the enabled interface power management
 	 * states that can be invoked via the Serial ATA interface power
@@ -138,7 +141,8 @@
 #define	SControl_IPM_ANY	(0x0 << 8)	/* No restrictions */
 #define	SControl_IPM_NOPARTIAL	(0x1 << 8)	/* PARTIAL disabled */
 #define	SControl_IPM_NOSLUMBER	(0x2 << 8)	/* SLUMBER disabled */
-#define	SControl_IPM_NONE	(0x3 << 8)	/* No power management */
+#define	SControl_IPM_NODEVSLEEP	(0x4 << 8)	/* DevSleep disabled */
+#define	SControl_IPM_NONE	(0x7 << 8)	/* No power management */
 	/*
 	 * The SPM field selects a power management state.  A non-zero
 	 * value written to this field causes initiation of the selected

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.75.4.3 src/sys/dev/ic/ahcisata_core.c:1.75.4.4
--- src/sys/dev/ic/ahcisata_core.c:1.75.4.3	Tue Jan 21 15:19:51 2020
+++ src/sys/dev/ic/ahcisata_core.c	Wed Dec 30 15:12:38 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.75.4.3 2020/01/21 15:19:51 martin Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.75.4.4 2020/12/30 15:12:38 martin Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.75.4.3 2020/01/21 15:19:51 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.75.4.4 2020/12/30 15:12:38 martin Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -84,6 +84,7 @@ static void ahci_channel_start(struct ah
 				int, int);
 static void ahci_channel_recover(struct ata_channel *, int, uint32_t);
 static int  ahci_dma_setup(struct ata_channel *, int, void *, size_t, int);
+static int ahci_intr_port_common(struct ata_channel *);
 
 #if NATAPIBUS > 0
 static void ahci_atapibus_attach(struct atabus_softc *);
@@ -363,6 +364,9 @@ ahci_attach(struct ahci_softc *sc)
 		return;
 	}
 	sc->sc_cmd_hdr = cmdhp;
+	memset(cmdhp, 0, dmasize);
+	bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_hdrd, 0, dmasize,
+	    BUS_DMASYNC_PREWRITE);
 
 	ahci_enable_intrs(sc);
 
@@ -429,6 +433,9 @@ ahci_attach(struct ahci_softc *sc)
 			    ", error=%d\n", AHCINAME(sc), error);
 			break;
 		}
+		memset(cmdtblp, 0, dmasize);
+		bus_dmamap_sync(sc->sc_dmat, achp->ahcic_cmd_tbld, 0,
+		    dmasize, BUS_DMASYNC_PREWRITE);
 		achp->ahcic_cmdh  = (struct ahci_cmd_header *)
 		    ((char *)cmdhp + AHCI_CMDH_SIZE * port);
 		achp->ahcic_bus_cmdh = sc->sc_cmd_hdrd->dm_segs[0].ds_addr +
@@ -586,17 +593,20 @@ int
 ahci_intr(void *v)
 {
 	struct ahci_softc *sc = v;
-	uint32_t is;
-	int i, r = 0;
+	uint32_t is, ports;
+	int bit, r = 0;
 
 	while ((is = AHCI_READ(sc, AHCI_IS))) {
 		AHCIDEBUG_PRINT(("%s ahci_intr 0x%x\n", AHCINAME(sc), is),
 		    DEBUG_INTR);
 		r = 1;
+		ports = is;
+		while ((bit = ffs(ports)) != 0) {
+			bit--;
+			ahci_intr_port_common(&sc->sc_channels[bit].ata_channel);
+			ports &= ~(1U << bit);
+		}
 		AHCI_WRITE(sc, AHCI_IS, is);
-		for (i = 0; i < AHCI_MAX_PORTS; i++)
-			if (is & (1U << i))
-				ahci_intr_port(&sc->sc_channels[i]);
 	}
 
 	return r;
@@ -608,6 +618,20 @@ ahci_intr_port(void *v)
 	struct ahci_channel *achp = v;
 	struct ata_channel *chp = &achp->ata_channel;
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
+	int ret;
+
+	ret = ahci_intr_port_common(chp);
+	if (ret) {
+		AHCI_WRITE(sc, AHCI_IS, 1U << chp->ch_channel);
+	}
+
+	return ret;
+}
+
+static int
+ahci_intr_port_common(struct ata_channel *chp)
+{
+	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
 	uint32_t is, tfd, sact;
 	struct ata_xfer *xfer;
 	int slot = -1;
@@ -617,8 +641,8 @@ ahci_intr_port(void *v)
 	is = AHCI_READ(sc, AHCI_P_IS(chp->ch_channel));
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), is);
 
-	AHCIDEBUG_PRINT((
-	    "ahci_intr_port %s port %d is 0x%x CI 0x%x SACT 0x%x TFD 0x%x\n",
+	AHCIDEBUG_PRINT(("ahci_intr_port_common %s port %d "
+	    "is 0x%x CI 0x%x SACT 0x%x TFD 0x%x\n",
 	    AHCINAME(sc),
 	    chp->ch_channel, is,
 	    AHCI_READ(sc, AHCI_P_CI(chp->ch_channel)),
@@ -761,14 +785,10 @@ ahci_exec_fis(struct ata_channel *chp, i
 	uint32_t is;
 
 	/*
-	 * Base timeout is specified in ms.
-	 * If we are allowed to sleep, wait a tick each round.
-	 * Otherwise delay for 10ms on each round.
+	 * Base timeout is specified in ms. Delay for 10ms
+	 * on each round.
 	 */
-	if (flags & AT_WAIT)
-		timeout = MAX(1, mstohz(timeout));
-	else
-		timeout = timeout / 10;
+	timeout = timeout / 10;
 
 	AHCI_CMDH_SYNC(sc, achp, slot,
 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -813,7 +833,7 @@ ahci_do_reset_drive(struct ata_channel *
 	struct ahci_cmd_header *cmd_h;
 	int i, error = 0;
 	uint32_t sig, cmd;
-	int noclo_retry = 0;
+	int noclo_retry = 0, retry;
 
 	ata_channel_lock_owned(chp);
 
@@ -851,9 +871,6 @@ again:
 		KASSERT(sc->sc_ahci_cap & AHCI_CAP_SPM);
 	}
 
-	if (sc->sc_ahci_quirks & AHCI_QUIRK_SKIP_RESET)
-		goto skip_reset;
-
 	/* polled command, assume interrupts are disabled */
 
 	cmd_h = &achp->ahcic_cmdh[c_slot];
@@ -895,25 +912,36 @@ again:
 	 */
 	ata_delay(chp, 10, "ahcirstw", flags);
 
-	cmd_h->cmdh_flags = htole16(RHD_FISLEN / 4 |
-	    (drive << AHCI_CMDH_F_PMP_SHIFT));
-	cmd_h->cmdh_prdbc = 0;
-	memset(cmd_tbl->cmdt_cfis, 0, 64);
-	cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE;
-	cmd_tbl->cmdt_cfis[rhd_c] = drive;
-	cmd_tbl->cmdt_cfis[rhd_control] = WDCTL_4BIT;
-	switch (ahci_exec_fis(chp, 310, flags, c_slot)) {
-	case ERR_DF:
-	case TIMEOUT:
+	/*
+	 * Try to clear WDCTL_RST a few times before giving up.
+	 */
+	for (error = EBUSY, retry = 0; error != 0 && retry < 5; retry++) {
+		cmd_h->cmdh_flags = htole16(RHD_FISLEN / 4 |
+		    (drive << AHCI_CMDH_F_PMP_SHIFT));
+		cmd_h->cmdh_prdbc = 0;
+		memset(cmd_tbl->cmdt_cfis, 0, 64);
+		cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE;
+		cmd_tbl->cmdt_cfis[rhd_c] = drive;
+		cmd_tbl->cmdt_cfis[rhd_control] = WDCTL_4BIT;
+		switch (ahci_exec_fis(chp, 310, flags, c_slot)) {
+		case ERR_DF:
+		case TIMEOUT:
+			error = EBUSY;
+			break;
+		default:
+			error = 0;
+			break;
+		}
+		if (error == 0) {
+			break;
+		}
+	}
+	if (error == EBUSY) {
 		aprint_error("%s port %d: clearing WDCTL_RST failed "
 		    "for drive %d\n", AHCINAME(sc), chp->ch_channel, drive);
-		error = EBUSY;
 		goto end;
-	default:
-		break;
 	}
 
-skip_reset:
 	/*
 	 * wait 31s for BSY to clear
 	 * This should not be needed, but some controllers clear the

Index: src/sys/dev/ic/ahcisatavar.h
diff -u src/sys/dev/ic/ahcisatavar.h:1.22.4.1 src/sys/dev/ic/ahcisatavar.h:1.22.4.2
--- src/sys/dev/ic/ahcisatavar.h:1.22.4.1	Tue Jan 21 15:19:51 2020
+++ src/sys/dev/ic/ahcisatavar.h	Wed Dec 30 15:12:38 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisatavar.h,v 1.22.4.1 2020/01/21 15:19:51 martin Exp $	*/
+/*	$NetBSD: ahcisatavar.h,v 1.22.4.2 2020/12/30 15:12:38 martin Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -58,8 +58,7 @@ struct ahci_softc {
 #define AHCI_PCI_QUIRK_FORCE	__BIT(0)  /* force attach */
 #define AHCI_PCI_QUIRK_BAD64	__BIT(1)  /* broken 64-bit DMA */
 #define AHCI_QUIRK_BADPMP	__BIT(2)  /* broken PMP support, ignore */
-#define AHCI_QUIRK_SKIP_RESET	__BIT(4)  /* skip drive reset sequence */
-#define AHCI_QUIRK_BADNCQ	__BIT(5)  /* possibly broken NCQ support, ignore */
+#define AHCI_QUIRK_BADNCQ	__BIT(3)  /* possibly broken NCQ support, ignore */
 
 	uint32_t sc_ahci_cap;	/* copy of AHCI_CAP */
 	int sc_ncmds; /* number of command slots */

Reply via email to