Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Jan 2011 13:37:45 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r217936 - stable/8/sys/dev/ata/chipsets
Message-ID:  <201101271337.p0RDbjbb017987@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Thu Jan 27 13:37:45 2011
New Revision: 217936
URL: http://svn.freebsd.org/changeset/base/217936

Log:
  MFC r215449:
  Some VIA SATA controllers provide access to non-standard SATA registers via
  PCI config space. Use them to implement hot-plug and link speed reporting.
  Tested on ASRock PV530 board with VX900 chipset.

Modified:
  stable/8/sys/dev/ata/chipsets/ata-via.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/dev/ata/chipsets/ata-via.c
==============================================================================
--- stable/8/sys/dev/ata/chipsets/ata-via.c	Thu Jan 27 13:16:08 2011	(r217935)
+++ stable/8/sys/dev/ata/chipsets/ata-via.c	Thu Jan 27 13:37:45 2011	(r217936)
@@ -63,6 +63,12 @@ static int ata_via_new_setmode(device_t 
 static int ata_via_sata_ch_attach(device_t dev);
 static int ata_via_sata_getrev(device_t dev, int target);
 static int ata_via_sata_setmode(device_t dev, int target, int mode);
+static void ata_via_sata_reset(device_t dev);
+static int ata_via_sata_scr_read(device_t dev, int port, int reg,
+    u_int32_t *result);
+static int ata_via_sata_scr_write(device_t dev, int port, int reg,
+    u_int32_t value);
+static int ata_via_sata_status(device_t dev);
 
 /* misc defines */
 #define VIA33           0
@@ -153,11 +159,12 @@ ata_via_chipinit(device_t dev)
 	if (ata_ahci_chipinit(dev) != ENXIO)
 	    return (0);
     }
-    /* 2 SATA without SATA registers on first channel + 1 PATA on second */
+    /* 2 SATA with "SATA registers" at PCI config space + PATA on secondary */
     if (ctlr->chip->cfg2 & VIASATA) {
 	ctlr->ch_attach = ata_via_sata_ch_attach;
 	ctlr->setmode = ata_via_sata_setmode;
 	ctlr->getrev = ata_via_sata_getrev;
+	ctlr->reset = ata_via_sata_reset;
 	return 0;
     }
     /* Legacy SATA/SATA+PATA with SATA registers in BAR(5). */
@@ -405,18 +412,30 @@ ata_via_sata_ch_attach(device_t dev)
 
 	if (ata_pci_ch_attach(dev))
 		return ENXIO;
-	if (ch->unit == 0)
+	if (ch->unit == 0) {
+		ch->hw.status = ata_via_sata_status;
+		ch->hw.pm_read = ata_via_sata_scr_read;
+		ch->hw.pm_write = ata_via_sata_scr_write;
+		ch->flags |= ATA_PERIODIC_POLL;
 		ch->flags |= ATA_SATA;
+		ata_sata_scr_write(ch, 0, ATA_SERROR, 0xffffffff);
+		ata_sata_scr_write(ch, 1, ATA_SERROR, 0xffffffff);
+	}
 	return (0);
 }
 
 static int
 ata_via_sata_getrev(device_t dev, int target)
 {
+	device_t parent = device_get_parent(dev);
 	struct ata_channel *ch = device_get_softc(dev);
 
-	if (ch->unit == 0)
-		return (1);
+	if (ch->unit == 0) {
+		if (pci_read_config(parent, 0xa0 + target, 1) & 0x10)
+			return (2);
+		else
+			return (1);
+	}
 	return (0);
 }
 
@@ -430,5 +449,110 @@ ata_via_sata_setmode(device_t dev, int t
 	return (ata_via_old_setmode(dev, target, mode));
 }
 
+static void
+ata_via_sata_reset(device_t dev)
+{
+	struct ata_channel *ch = device_get_softc(dev);
+	int devs;
+
+	if (ch->unit == 0) {
+		devs = ata_sata_phy_reset(dev, 0, 0);
+		DELAY(10000);
+		devs += ata_sata_phy_reset(dev, 1, 0);
+	} else
+		devs = 1;
+	if (devs)
+		ata_generic_reset(dev);
+}
+
+static int
+ata_via_sata_scr_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+	struct ata_channel *ch;
+	device_t parent;
+	uint32_t val;
+
+	parent = device_get_parent(dev);
+	ch = device_get_softc(dev);
+	port = (port == 1) ? 1 : 0;
+	switch (reg) {
+	case ATA_SSTATUS:
+		val = pci_read_config(parent, 0xa0 + port, 1);
+		*result = val & 0x03;
+		if (*result != ATA_SS_DET_NO_DEVICE) {
+			if (val & 0x04)
+				*result |= ATA_SS_IPM_PARTIAL;
+			else if (val & 0x08)
+				*result |= ATA_SS_IPM_SLUMBER;
+			else
+				*result |= ATA_SS_IPM_ACTIVE;
+			if (val & 0x10)
+				*result |= ATA_SS_SPD_GEN2;
+			else
+				*result |= ATA_SS_SPD_GEN1;
+		}
+		break;
+	case ATA_SERROR:
+		*result = pci_read_config(parent, 0xa8 + port * 4, 4);
+		break;
+	case ATA_SCONTROL:
+		val = pci_read_config(parent, 0xa4 + port, 1);
+		*result = 0;
+		if (val & 0x01)
+			*result |= ATA_SC_DET_RESET;
+		if (val & 0x02)
+			*result |= ATA_SC_DET_DISABLE;
+		if (val & 0x04)
+			*result |= ATA_SC_IPM_DIS_PARTIAL;
+		if (val & 0x08)
+			*result |= ATA_SC_IPM_DIS_SLUMBER;
+		break;
+	default:
+		return (EINVAL);
+	}
+	return (0);
+}
+
+static int
+ata_via_sata_scr_write(device_t dev, int port, int reg, u_int32_t value)
+{
+	struct ata_channel *ch;
+	device_t parent;
+	uint32_t val;
+
+	parent = device_get_parent(dev);
+	ch = device_get_softc(dev);
+	port = (port == 1) ? 1 : 0;
+	switch (reg) {
+	case ATA_SERROR:
+		pci_write_config(parent, 0xa8 + port * 4, value, 4);
+		break;
+	case ATA_SCONTROL:
+		val = 0;
+		if (value & ATA_SC_DET_RESET)
+			val |= 0x01;
+		if (value & ATA_SC_DET_DISABLE)
+			val |= 0x02;
+		if (value & ATA_SC_IPM_DIS_PARTIAL)
+			val |= 0x04;
+		if (value & ATA_SC_IPM_DIS_SLUMBER)
+			val |= 0x08;
+		pci_write_config(parent, 0xa4 + port, val, 1);
+		break;
+	default:
+		return (EINVAL);
+	}
+	return (0);
+}
+
+static int
+ata_via_sata_status(device_t dev)
+{
+
+	ata_sata_phy_check_events(dev, 0);
+	ata_sata_phy_check_events(dev, 1);
+	return (ata_pci_status(dev));
+}
+
 ATA_DECLARE_DRIVER(ata_via);
 MODULE_DEPEND(ata_via, ata_ahci, 1, 1, 1);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101271337.p0RDbjbb017987>