Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Jan 2011 09:24:20 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r217774 - head/sys/dev/ata/chipsets
Message-ID:  <201101240924.p0O9OKjN085230@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Mon Jan 24 09:24:20 2011
New Revision: 217774
URL: http://svn.freebsd.org/changeset/base/217774

Log:
  ICH7 SATA controller in legacy mode can provide access to SATA registers
  via AHCI-like memory resource at BAR(5). Use it if BIOS was so kind to
  allocate memory for that BAR. This allows hot-plug support and connection
  speed reporting.
  
  MFC after:	2 weeks

Modified:
  head/sys/dev/ata/chipsets/ata-intel.c

Modified: head/sys/dev/ata/chipsets/ata-intel.c
==============================================================================
--- head/sys/dev/ata/chipsets/ata-intel.c	Mon Jan 24 07:50:29 2011	(r217773)
+++ head/sys/dev/ata/chipsets/ata-intel.c	Mon Jan 24 09:24:20 2011	(r217774)
@@ -60,10 +60,14 @@ static int ata_intel_new_setmode(device_
 static int ata_intel_sch_setmode(device_t dev, int target, int mode);
 static int ata_intel_sata_getrev(device_t dev, int target);
 static int ata_intel_sata_status(device_t dev);
+static int ata_intel_sata_ahci_read(device_t dev, int port,
+    int reg, u_int32_t *result);
 static int ata_intel_sata_cscr_read(device_t dev, int port,
     int reg, u_int32_t *result);
 static int ata_intel_sata_sidpr_read(device_t dev, int port,
     int reg, u_int32_t *result);
+static int ata_intel_sata_ahci_write(device_t dev, int port,
+    int reg, u_int32_t result);
 static int ata_intel_sata_cscr_write(device_t dev, int port,
     int reg, u_int32_t result);
 static int ata_intel_sata_sidpr_write(device_t dev, int port,
@@ -79,6 +83,7 @@ static void ata_intel_31244_reset(device
 #define INTEL_ICH5	2
 #define INTEL_6CH	4
 #define INTEL_6CH2	8
+#define INTEL_ICH7	16
 
 /*
  * Intel chipset support functions
@@ -113,11 +118,11 @@ ata_intel_probe(device_t dev)
      { ATA_I82801FB_R1,  0, INTEL_AHCI, 0, ATA_SA150, "ICH6" },
      { ATA_I82801FBM,    0, INTEL_AHCI, 0, ATA_SA150, "ICH6M" },
      { ATA_I82801GB,     0,          0, 1, ATA_UDMA5, "ICH7" },
-     { ATA_I82801GB_S1,  0,          0, 0, ATA_SA300, "ICH7" },
-     { ATA_I82801GB_R1,  0,          0, 0, ATA_SA300, "ICH7" },
+     { ATA_I82801GB_S1,  0, INTEL_ICH7, 0, ATA_SA300, "ICH7" },
+     { ATA_I82801GB_R1,  0, INTEL_AHCI, 0, ATA_SA300, "ICH7" },
      { ATA_I82801GB_AH,  0, INTEL_AHCI, 0, ATA_SA300, "ICH7" },
-     { ATA_I82801GBM_S1, 0,          0, 0, ATA_SA150, "ICH7M" },
-     { ATA_I82801GBM_R1, 0,          0, 0, ATA_SA150, "ICH7M" },
+     { ATA_I82801GBM_S1, 0, INTEL_ICH7, 0, ATA_SA150, "ICH7M" },
+     { ATA_I82801GBM_R1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" },
      { ATA_I82801GBM_AH, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" },
      { ATA_I63XXESB2,    0,          0, 1, ATA_UDMA5, "63XXESB2" },
      { ATA_I63XXESB2_S1, 0,          0, 0, ATA_SA300, "63XXESB2" },
@@ -250,14 +255,30 @@ ata_intel_chipinit(device_t dev)
 	    (pci_read_config(dev, 0x90, 1) & 0xc0) &&
 	    (ata_ahci_chipinit(dev) != ENXIO))
 	    return 0;
-	
-	/* if BAR(5) is IO it should point to SATA interface registers */
-	ctlr->r_type2 = SYS_RES_IOPORT;
-	ctlr->r_rid2 = PCIR_BAR(5);
-	if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
-						   &ctlr->r_rid2, RF_ACTIVE))
-	    || (ctlr->chip->cfg1 & INTEL_ICH5))
-	    ctlr->getrev = ata_intel_sata_getrev;
+
+	/* BAR(5) may point to SATA interface registers */
+	if ((ctlr->chip->cfg1 & INTEL_ICH7)) {
+		ctlr->r_type2 = SYS_RES_MEMORY;
+		ctlr->r_rid2 = PCIR_BAR(5);
+		ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+		    &ctlr->r_rid2, RF_ACTIVE);
+		if (ctlr->r_res2 != NULL) {
+			/* Set SCRAE bit to enable registers access. */
+			pci_write_config(dev, 0x94,
+			    pci_read_config(dev, 0x94, 4) | (1 << 9), 4);
+			/* Set Ports Implemented register bits. */
+			ATA_OUTL(ctlr->r_res2, 0x0C,
+			    ATA_INL(ctlr->r_res2, 0x0C) | 0xf);
+		}
+	} else {
+		ctlr->r_type2 = SYS_RES_IOPORT;
+		ctlr->r_rid2 = PCIR_BAR(5);
+		ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+		    &ctlr->r_rid2, RF_ACTIVE);
+	}
+	if (ctlr->r_res2 != NULL ||
+	    (ctlr->chip->cfg1 & INTEL_ICH5))
+		ctlr->getrev = ata_intel_sata_getrev;
 	ctlr->setmode = ata_sata_setmode;
     }
     return 0;
@@ -336,8 +357,13 @@ ata_intel_ch_attach(device_t dev)
 			} else if (ctlr->r_res2) {
 				ch->flags |= ATA_PERIODIC_POLL;
 				ch->hw.status = ata_intel_sata_status;
-				ch->hw.pm_read = ata_intel_sata_sidpr_read;
-				ch->hw.pm_write = ata_intel_sata_sidpr_write;
+				if ((ctlr->chip->cfg1 & INTEL_ICH7)) {
+					ch->hw.pm_read = ata_intel_sata_ahci_read;
+					ch->hw.pm_write = ata_intel_sata_ahci_write;
+				} else {
+					ch->hw.pm_read = ata_intel_sata_sidpr_read;
+					ch->hw.pm_write = ata_intel_sata_sidpr_write;
+				};
 			}
 			if (ch->hw.pm_write != NULL) {
 				ata_sata_scr_write(ch, 0,
@@ -537,6 +563,38 @@ ata_intel_sata_status(device_t dev)
 }
 
 static int
+ata_intel_sata_ahci_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+	struct ata_pci_controller *ctlr;
+	struct ata_channel *ch;
+	device_t parent;
+	u_char *smap;
+	int offset;
+
+	parent = device_get_parent(dev);
+	ctlr = device_get_softc(parent);
+	ch = device_get_softc(dev);
+	port = (port == 1) ? 1 : 0;
+	smap = (u_char *)&ctlr->chipset_data + ch->unit * 2;
+	offset = 0x100 + smap[port] * 0x80;
+	switch (reg) {
+	case ATA_SSTATUS:
+	    reg = 0x28;
+	    break;
+	case ATA_SCONTROL:
+	    reg = 0x2c;
+	    break;
+	case ATA_SERROR:
+	    reg = 0x30;
+	    break;
+	default:
+	    return (EINVAL);
+	}
+	*result = ATA_INL(ctlr->r_res2, offset + reg);
+	return (0);
+}
+
+static int
 ata_intel_sata_cscr_read(device_t dev, int port, int reg, u_int32_t *result)
 {
 	struct ata_pci_controller *ctlr;
@@ -598,6 +656,38 @@ ata_intel_sata_sidpr_read(device_t dev, 
 }
 
 static int
+ata_intel_sata_ahci_write(device_t dev, int port, int reg, u_int32_t value)
+{
+	struct ata_pci_controller *ctlr;
+	struct ata_channel *ch;
+	device_t parent;
+	u_char *smap;
+	int offset;
+
+	parent = device_get_parent(dev);
+	ctlr = device_get_softc(parent);
+	ch = device_get_softc(dev);
+	port = (port == 1) ? 1 : 0;
+	smap = (u_char *)&ctlr->chipset_data + ch->unit * 2;
+	offset = 0x100 + smap[port] * 0x80;
+	switch (reg) {
+	case ATA_SSTATUS:
+	    reg = 0x28;
+	    break;
+	case ATA_SCONTROL:
+	    reg = 0x2c;
+	    break;
+	case ATA_SERROR:
+	    reg = 0x30;
+	    break;
+	default:
+	    return (EINVAL);
+	}
+	ATA_OUTL(ctlr->r_res2, offset + reg, value);
+	return (0);
+}
+
+static int
 ata_intel_sata_cscr_write(device_t dev, int port, int reg, u_int32_t value)
 {
 	struct ata_pci_controller *ctlr;



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