Author: mav
Date: Thu Nov 18 08:03:40 2010
New Revision: 215449
URL: http://svn.freebsd.org/changeset/base/215449

Log:
  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:
  head/sys/dev/ata/chipsets/ata-via.c

Modified: head/sys/dev/ata/chipsets/ata-via.c
==============================================================================
--- head/sys/dev/ata/chipsets/ata-via.c Thu Nov 18 02:16:06 2010        
(r215448)
+++ head/sys/dev/ata/chipsets/ata-via.c Thu Nov 18 08:03:40 2010        
(r215449)
@@ -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);
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to