summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2006-06-28 09:59:09 +0000
committersos <sos@FreeBSD.org>2006-06-28 09:59:09 +0000
commitf05cca68da2a8fafe17976376ee3790dbb91b7df (patch)
treecdeadbf6668194c5f0c5dcf2a205713c93f6cf9a /sys/dev/ata
parent752a9a7e28c70b5935908ab4b6ca0eaca88de6eb (diff)
downloadFreeBSD-src-f05cca68da2a8fafe17976376ee3790dbb91b7df.zip
FreeBSD-src-f05cca68da2a8fafe17976376ee3790dbb91b7df.tar.gz
Update AHCI support to be more generic.
Add support for AHCI on the VIA VT8251.
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata-all.h2
-rw-r--r--sys/dev/ata/ata-chipset.c169
2 files changed, 104 insertions, 67 deletions
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h
index 8f98589..f8b2fd5 100644
--- a/sys/dev/ata/ata-all.h
+++ b/sys/dev/ata/ata-all.h
@@ -149,6 +149,8 @@
/* SATA AHCI v1.0 register defines */
#define ATA_AHCI_CAP 0x00
#define ATA_AHCI_NPMASK 0x1f
+#define ATA_AHCI_CAP_CLO 0x01000000
+#define ATA_AHCI_CAP_64BIT 0x80000000
#define ATA_AHCI_GHC 0x04
#define ATA_AHCI_GHC_AE 0x80000000
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index 1b24f40..d392106 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -59,6 +59,7 @@ static void ata_sata_phy_enable(struct ata_channel *ch);
static void ata_sata_phy_event(void *context, int dummy);
static int ata_sata_connect(struct ata_channel *ch);
static void ata_sata_setmode(device_t dev, int mode);
+static int ata_ahci_chipinit(device_t dev);
static int ata_ahci_allocate(device_t dev);
static int ata_ahci_status(device_t dev);
static int ata_ahci_begin_transaction(struct ata_request *request);
@@ -394,6 +395,54 @@ struct ata_ahci_cmd_list {
static int
+ata_ahci_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ u_int32_t version;
+
+ /* reset AHCI controller */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_HR);
+ DELAY(1000000);
+ if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) {
+ bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2);
+ device_printf(dev, "AHCI controller reset failure\n");
+ return ENXIO;
+ }
+
+ /* enable AHCI mode */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_AE);
+
+ /* get the number of HW channels */
+ ctlr->channels = (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK)+1;
+
+ /* clear interrupts */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS));
+
+ /* enable AHCI interrupts */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE);
+
+ ctlr->reset = ata_ahci_reset;
+ ctlr->dmainit = ata_ahci_dmainit;
+ ctlr->allocate = ata_ahci_allocate;
+ ctlr->setmode = ata_sata_setmode;
+
+ /* enable PCI interrupt */
+ pci_write_config(dev, PCIR_COMMAND,
+ pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
+
+ /* announce we support the HW */
+ version = ATA_INL(ctlr->r_res2, ATA_AHCI_VS);
+ device_printf(dev,
+ "AHCI Version %x%x.%x%x controller with %d ports detected\n",
+ (version >> 24) & 0xff, (version >> 16) & 0xff,
+ (version >> 8) & 0xff, version & 0xff, ctlr->channels);
+ return 0;
+}
+
+static int
ata_ahci_allocate(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
@@ -459,7 +508,8 @@ ata_ahci_status(device_t dev)
int offset = (ch->unit << 7);
int tag = 0;
- if ((action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS)) & (1 << ch->unit)) {
+ action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS);
+ if (action & (1 << ch->unit)) {
istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset);
issued = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset);
sstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SSTS + offset);
@@ -472,7 +522,7 @@ ata_ahci_status(device_t dev)
/* do we have cold connect surprise */
if (istatus & ATA_AHCI_P_IX_CPD) {
- printf("ata_ahci_intr status=%08x sstatus=%08x error=%08x\n",
+ printf("ata_ahci_status status=%08x sstatus=%08x error=%08x\n",
istatus, sstatus, error);
}
@@ -521,8 +571,8 @@ ata_ahci_begin_transaction(struct ata_request *request)
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
struct ata_ahci_cmd_tab *ctp;
struct ata_ahci_cmd_list *clp;
- int fis_size, entries;
- int tag = 0;
+ int tag = 0, entries = 0;
+ int fis_size;
/* get a piece of the workspace for this request */
ctp = (struct ata_ahci_cmd_tab *)
@@ -608,15 +658,37 @@ ata_ahci_reset(device_t dev)
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
struct ata_channel *ch = device_get_softc(dev);
u_int32_t cmd;
- int offset = (ch->unit << 7);
+ int timeout, offset = (ch->unit << 7);
/* kill off all activity on this channel */
cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- cmd & ~(ATA_AHCI_P_CMD_CR | ATA_AHCI_P_CMD_FR |
- ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
-
- DELAY(500000); /* XXX SOS this is not entirely wrong */
+ cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
+
+ /* XXX SOS this is not entirely wrong */
+ timeout = 0;
+ do {
+ DELAY(1000);
+ if (timeout++ > 500)
+ device_printf(dev, "stopping AHCI engine failed\n");
+ break;
+ }
+ while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
+
+ /* issue Command List Override if supported */
+ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_CLO) {
+ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
+ cmd |= ATA_AHCI_P_CMD_CLO;
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd);
+ timeout = 0;
+ do {
+ DELAY(1000);
+ if (timeout++ > 500)
+ device_printf(dev, "executing CLO failed\n");
+ break;
+ }
+ while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO);
+ }
/* spin up device */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_AHCI_P_CMD_SUD);
@@ -1653,43 +1725,18 @@ ata_intel_chipinit(device_t dev)
ctlr->allocate = ata_intel_allocate;
ctlr->reset = ata_intel_reset;
- /* if we have AHCI capability and BAR(5) as a memory resource */
- if (ctlr->chip->cfg1 == AHCI) {
+ /*
+ * if we have AHCI capability and BAR(5) as a memory resource
+ * and AHCI or RAID mode enabled in BIOS we go for AHCI mode
+ */
+ if ((ctlr->chip->cfg1 == AHCI) &&
+ (pci_read_config(dev, 0x90, 1) & 0xc0)) {
ctlr->r_type2 = SYS_RES_MEMORY;
ctlr->r_rid2 = PCIR_BAR(5);
if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
&ctlr->r_rid2,
- RF_ACTIVE))) {
- /* is AHCI or RAID mode enabled in BIOS ? */
- if (pci_read_config(dev, 0x90, 1) & 0xc0) {
-
- /* reset AHCI controller */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
- ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_HR);
- DELAY(1000000);
- if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) {
- bus_release_resource(dev, ctlr->r_type2,
- ctlr->r_rid2, ctlr->r_res2);
- device_printf(dev, "AHCI controller reset failure\n");
- return ENXIO;
- }
-
- /* enable AHCI mode */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
-
- /* get the number of HW channels */
- ctlr->channels = (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) &
- ATA_AHCI_NPMASK) + 1;
-
- /* enable AHCI interrupts */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
- ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) |
- ATA_AHCI_GHC_IE);
- ctlr->allocate = ata_ahci_allocate;
- ctlr->reset = ata_ahci_reset;
- ctlr->dmainit = ata_ahci_dmainit;
- }
- }
+ RF_ACTIVE)))
+ return ata_ahci_chipinit(dev);
}
ctlr->setmode = ata_sata_setmode;
@@ -2091,6 +2138,7 @@ static int
ata_jmicron_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
+ int error;
if (ata_setup_interrupt(dev))
return ENXIO;
@@ -2108,30 +2156,8 @@ ata_jmicron_chipinit(device_t dev)
ctlr->r_rid2 = PCIR_BAR(5);
if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
&ctlr->r_rid2, RF_ACTIVE))) {
- /* reset AHCI controller */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
- ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_HR);
- DELAY(1000000);
- if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) {
- bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2,ctlr->r_res2);
- device_printf(dev, "AHCI controller reset failure\n");
- return ENXIO;
- }
-
- /* enable AHCI mode */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
- ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_AE);
-
- /* clear interrupts */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS));
-
- /* enable AHCI interrupts */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
- ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE);
-
- /* enable PCI interrupt */
- pci_write_config(dev, PCIR_COMMAND,
- pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
+ if ((error = ata_ahci_chipinit(dev)))
+ return error;
}
/* set the number of HW channels */
@@ -4612,7 +4638,7 @@ ata_via_ident(device_t dev)
{{ ATA_VIA6410, 0x00, 0, 0x00, ATA_UDMA6, "6410" },
{ ATA_VIA6420, 0x00, 7, 0x00, ATA_SA150, "6420" },
{ ATA_VIA6421, 0x00, 6, VIABAR, ATA_SA150, "6421" },
- { ATA_VIA8251, 0x00, 0, VIAAHCI, ATA_SA150, "8251" },
+ { ATA_VIA8251, 0x00, 0, VIAAHCI, ATA_SA300, "8251" },
{ 0, 0, 0, 0, 0, 0 }};
char buffer[64];
@@ -4642,6 +4668,15 @@ ata_via_chipinit(device_t dev)
return ENXIO;
if (ctlr->chip->max_dma >= ATA_SA150) {
+ if (ctlr->chip->cfg2 == VIAAHCI) {
+ ctlr->r_type2 = SYS_RES_MEMORY;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2,
+ RF_ACTIVE))) {
+ return ata_ahci_chipinit(dev);
+ }
+ }
ctlr->r_type2 = SYS_RES_IOPORT;
ctlr->r_rid2 = PCIR_BAR(5);
if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
OpenPOWER on IntegriCloud