VIA VT8251 SATA support
I added the PCI ID for the VT8251 IDE controller and since then I've been getting a continuous flow of emails from people who think I might have some clue about the SATA side. I don't even own the hardware, but I have backported the patch for inclusion in the Gentoo kernels now that it has been merged into the 2.6.18 tree. This patch is reported to work with 2.6.17.
NOTE: This is unsupported by me, and unsupported the Linux IDE/SATA developers too. The patch is slightly ugly because it includes a backport of the ata_wait_register() function so the end product is that we have some code using ata_wait_register() and some using whatever the predecessor was.
Hoping for fewer emails about this annoying hardware... ;)
Daniel
From: Bastiaan Jacques <[email protected]>
Date: Mon, 17 Apr 2006 12:17:59 +0000 (+0200)
Subject: [PATCH] ahci: add support for VIA VT8251
X-Git-Tag: v2.6.17-rc3
X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=bf2af2a2027e52b653882fbca840620e896ae081
[PATCH] ahci: add support for VIA VT8251
Adds AHCI support for the VIA VT8251.
Includes a workaround for a hardware bug which requires a Command List Override before softreset.
---
Backported to 2.6.17 by Daniel Drake <[email protected]> Includes addition of ata_wait_register() function
drivers/scsi/ahci.c +48 -16
@@ -73,6 +73,7 @@ enum {RX_FIS_D2H_REG =0x40 ,/* offset of D2H Register FIS data */ board_ahci =0 , + board_ahci_vt8251 =1 ,/* global controller registers */ HOST_CAP = 0x00, /* host capabilities */
@@ -153,6 +154,9 @@ enum {/* hpriv->flags bits */ AHCI_FLAG_MSI = (1 <<0 ), + +/* ap->flags bits */ + AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24), }; struct ahci_cmd_hdr {
@@ -255,6 +259,16 @@ static const struct ata_port_info ahci_p .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, }, +/* board_ahci_vt8251 */ + { + .sht = &ahci_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | + AHCI_FLAG_RESET_NEEDS_CLO, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .port_ops = &ahci_ops, + }, };static const struct pci_device_id ahci_pci_tbl[] = {
@@ -296,6 +310,8 @@ static const struct pci_device_id ahci_p board_ahci }, /* ATI SB600 non-raid */ {PCI_VENDOR_ID_ATI ,0x4381 ,PCI_ANY_ID ,PCI_ANY_ID ,0 ,0 , board_ahci }, /* ATI SB600 raid */ + { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci_vt8251 }, /* VIA VT8251 */ { } /* terminate list */ };
@@ -534,9 +550,29 @@ static int ahci_poll_register(void __iomreturn -1 ; } -static int ahci_softreset (struct ata_port *ap,int verbose,unsigned int *class) +static int ahci_clo (struct ata_port *ap) { +void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;struct ahci_host_priv *hpriv = ap->host_set->private_data; +u32 tmp; + +if (!(hpriv->cap &HOST_CAP_CLO )) +return -EOPNOTSUPP ; + + tmp =readl (port_mmio +PORT_CMD ); + tmp |=PORT_CMD_CLO ; +writel (tmp, port_mmio +PORT_CMD ); + + tmp =ata_wait_register (port_mmio +PORT_CMD , +PORT_CMD_CLO ,PORT_CMD_CLO ,1 ,500 ); +if (tmp &PORT_CMD_CLO ) +return -EIO ; + +return 0 ; +} + +static int ahci_softreset (struct ata_port *ap,int verbose,unsigned int *class) +{struct ahci_port_priv *pp = ap->private_data;void __iomem *mmio = ap->host_set->mmio_base;void __iomem *port_mmio =ahci_port_base (mmio, ap->port_no);
@@ -558,23 +594,13 @@ static int ahci_softreset(struct ata_por/* check BUSY/DRQ, perform Command List Override if necessary */ ahci_tf_read (ap, &tf);if (tf.command & (ATA_BUSY |ATA_DRQ )) { -u32 tmp; + rc =ahci_clo (ap); -if (!(hpriv->cap &HOST_CAP_CLO )) { - rc = -EIO ; - reason ="port busy but no CLO" ; +if (rc == -EOPNOTSUPP ) { + reason ="port busy but CLO unavailable" ; goto fail_restart; - } - - tmp =readl (port_mmio +PORT_CMD ); - tmp |=PORT_CMD_CLO ; -writel (tmp, port_mmio +PORT_CMD ); -readl (port_mmio +PORT_CMD );/* flush */ - -if (ahci_poll_register (port_mmio +PORT_CMD ,PORT_CMD_CLO ,0x0 , -1 ,500 )) { - rc = -EIO ; - reason ="CLO failed" ; + }else if (rc) { + reason ="port busy but CLO failed" ; goto fail_restart; } }
@@ -688,6 +714,12 @@ static void ahci_postreset(struct ata_postatic int ahci_probe_reset (struct ata_port *ap,unsigned int *classes) { +if ((ap->flags &AHCI_FLAG_RESET_NEEDS_CLO ) && + (ata_busy_wait (ap,ATA_BUSY ,1000 ) &ATA_BUSY )) { +/* ATA_BUSY hasn't cleared, so send a CLO */ +ahci_clo (ap); + } +return ata_drive_probe_reset (ap, ata_std_probeinit, ahci_softreset, ahci_hardreset, ahci_postreset, classes);
drivers/scsi/libata-core.c +47 -0
59 lines not on this page · raw message
include/linux/libata.h +3 -0
@@ -537,6 +537,9 @@ extern unsigned int ata_busy_sleep(struc unsigned long timeout);extern void ata_port_queue_task (struct ata_port *ap,void (*fn)(void *),void *data,unsigned long delay); +extern u32 ata_wait_register (void __iomem *reg,u32 mask,u32 val, +unsigned long interval_msec, +unsigned long timeout_msec);/* * Default driver ops implementations