|
@@ -887,23 +887,9 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
|
|
* Serial ATA Index/Data Pair Superset Registers access
|
|
* Serial ATA Index/Data Pair Superset Registers access
|
|
*
|
|
*
|
|
* Beginning from ICH8, there's a sane way to access SCRs using index
|
|
* Beginning from ICH8, there's a sane way to access SCRs using index
|
|
- * and data register pair located at BAR5. This creates an
|
|
|
|
- * interesting problem of mapping two SCRs to one port.
|
|
|
|
- *
|
|
|
|
- * Although they have separate SCRs, the master and slave aren't
|
|
|
|
- * independent enough to be treated as separate links - e.g. softreset
|
|
|
|
- * resets both. Also, there's no protocol defined for hard resetting
|
|
|
|
- * singled device sharing the virtual port (no defined way to acquire
|
|
|
|
- * device signature). This is worked around by merging the SCR values
|
|
|
|
- * into one sensible value and requesting follow-up SRST after
|
|
|
|
- * hardreset.
|
|
|
|
- *
|
|
|
|
- * SCR merging is perfomed in nibbles which is the unit contents in
|
|
|
|
- * SCRs are organized. If two values are equal, the value is used.
|
|
|
|
- * When they differ, merge table which lists precedence of possible
|
|
|
|
- * values is consulted and the first match or the last entry when
|
|
|
|
- * nothing matches is used. When there's no merge table for the
|
|
|
|
- * specific nibble, value from the first port is used.
|
|
|
|
|
|
+ * and data register pair located at BAR5 which means that we have
|
|
|
|
+ * separate SCRs for master and slave. This is handled using libata
|
|
|
|
+ * slave_link facility.
|
|
*/
|
|
*/
|
|
static const int piix_sidx_map[] = {
|
|
static const int piix_sidx_map[] = {
|
|
[SCR_STATUS] = 0,
|
|
[SCR_STATUS] = 0,
|
|
@@ -911,125 +897,38 @@ static const int piix_sidx_map[] = {
|
|
[SCR_CONTROL] = 1,
|
|
[SCR_CONTROL] = 1,
|
|
};
|
|
};
|
|
|
|
|
|
-static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg)
|
|
|
|
|
|
+static void piix_sidpr_sel(struct ata_link *link, unsigned int reg)
|
|
{
|
|
{
|
|
- struct ata_port *ap = dev->link->ap;
|
|
|
|
|
|
+ struct ata_port *ap = link->ap;
|
|
struct piix_host_priv *hpriv = ap->host->private_data;
|
|
struct piix_host_priv *hpriv = ap->host->private_data;
|
|
|
|
|
|
- iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg],
|
|
|
|
|
|
+ iowrite32(((ap->port_no * 2 + link->pmp) << 8) | piix_sidx_map[reg],
|
|
hpriv->sidpr + PIIX_SIDPR_IDX);
|
|
hpriv->sidpr + PIIX_SIDPR_IDX);
|
|
}
|
|
}
|
|
|
|
|
|
-static int piix_sidpr_read(struct ata_device *dev, unsigned int reg)
|
|
|
|
-{
|
|
|
|
- struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
|
|
|
|
-
|
|
|
|
- piix_sidpr_sel(dev, reg);
|
|
|
|
- return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
|
|
|
|
-{
|
|
|
|
- struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
|
|
|
|
-
|
|
|
|
- piix_sidpr_sel(dev, reg);
|
|
|
|
- iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
|
|
|
|
-{
|
|
|
|
- u32 val = 0;
|
|
|
|
- int i, mi;
|
|
|
|
-
|
|
|
|
- for (i = 0, mi = 0; i < 32 / 4; i++) {
|
|
|
|
- u8 c0 = (val0 >> (i * 4)) & 0xf;
|
|
|
|
- u8 c1 = (val1 >> (i * 4)) & 0xf;
|
|
|
|
- u8 merged = c0;
|
|
|
|
- const int *cur;
|
|
|
|
-
|
|
|
|
- /* if no merge preference, assume the first value */
|
|
|
|
- cur = merge_tbl[mi];
|
|
|
|
- if (!cur)
|
|
|
|
- goto done;
|
|
|
|
- mi++;
|
|
|
|
-
|
|
|
|
- /* if two values equal, use it */
|
|
|
|
- if (c0 == c1)
|
|
|
|
- goto done;
|
|
|
|
-
|
|
|
|
- /* choose the first match or the last from the merge table */
|
|
|
|
- while (*cur != -1) {
|
|
|
|
- if (c0 == *cur || c1 == *cur)
|
|
|
|
- break;
|
|
|
|
- cur++;
|
|
|
|
- }
|
|
|
|
- if (*cur == -1)
|
|
|
|
- cur--;
|
|
|
|
- merged = *cur;
|
|
|
|
- done:
|
|
|
|
- val |= merged << (i * 4);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return val;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int piix_sidpr_scr_read(struct ata_link *link,
|
|
static int piix_sidpr_scr_read(struct ata_link *link,
|
|
unsigned int reg, u32 *val)
|
|
unsigned int reg, u32 *val)
|
|
{
|
|
{
|
|
- struct ata_port *ap = link->ap;
|
|
|
|
- const int * const sstatus_merge_tbl[] = {
|
|
|
|
- /* DET */ (const int []){ 1, 3, 0, 4, 3, -1 },
|
|
|
|
- /* SPD */ (const int []){ 2, 1, 0, -1 },
|
|
|
|
- /* IPM */ (const int []){ 6, 2, 1, 0, -1 },
|
|
|
|
- NULL,
|
|
|
|
- };
|
|
|
|
- const int * const scontrol_merge_tbl[] = {
|
|
|
|
- /* DET */ (const int []){ 1, 0, 4, 0, -1 },
|
|
|
|
- /* SPD */ (const int []){ 0, 2, 1, 0, -1 },
|
|
|
|
- /* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 },
|
|
|
|
- NULL,
|
|
|
|
- };
|
|
|
|
- u32 v0, v1;
|
|
|
|
|
|
+ struct piix_host_priv *hpriv = link->ap->host->private_data;
|
|
|
|
|
|
if (reg >= ARRAY_SIZE(piix_sidx_map))
|
|
if (reg >= ARRAY_SIZE(piix_sidx_map))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) {
|
|
|
|
- *val = piix_sidpr_read(&ap->link.device[0], reg);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- v0 = piix_sidpr_read(&ap->link.device[0], reg);
|
|
|
|
- v1 = piix_sidpr_read(&ap->link.device[1], reg);
|
|
|
|
-
|
|
|
|
- switch (reg) {
|
|
|
|
- case SCR_STATUS:
|
|
|
|
- *val = piix_merge_scr(v0, v1, sstatus_merge_tbl);
|
|
|
|
- break;
|
|
|
|
- case SCR_ERROR:
|
|
|
|
- *val = v0 | v1;
|
|
|
|
- break;
|
|
|
|
- case SCR_CONTROL:
|
|
|
|
- *val = piix_merge_scr(v0, v1, scontrol_merge_tbl);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ piix_sidpr_sel(link, reg);
|
|
|
|
+ *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int piix_sidpr_scr_write(struct ata_link *link,
|
|
static int piix_sidpr_scr_write(struct ata_link *link,
|
|
unsigned int reg, u32 val)
|
|
unsigned int reg, u32 val)
|
|
{
|
|
{
|
|
- struct ata_port *ap = link->ap;
|
|
|
|
|
|
+ struct piix_host_priv *hpriv = link->ap->host->private_data;
|
|
|
|
|
|
if (reg >= ARRAY_SIZE(piix_sidx_map))
|
|
if (reg >= ARRAY_SIZE(piix_sidx_map))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- piix_sidpr_write(&ap->link.device[0], reg, val);
|
|
|
|
-
|
|
|
|
- if (ap->flags & ATA_FLAG_SLAVE_POSS)
|
|
|
|
- piix_sidpr_write(&ap->link.device[1], reg, val);
|
|
|
|
-
|
|
|
|
|
|
+ piix_sidpr_sel(link, reg);
|
|
|
|
+ iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1370,28 +1269,28 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
|
|
return map;
|
|
return map;
|
|
}
|
|
}
|
|
|
|
|
|
-static void __devinit piix_init_sidpr(struct ata_host *host)
|
|
|
|
|
|
+static int __devinit piix_init_sidpr(struct ata_host *host)
|
|
{
|
|
{
|
|
struct pci_dev *pdev = to_pci_dev(host->dev);
|
|
struct pci_dev *pdev = to_pci_dev(host->dev);
|
|
struct piix_host_priv *hpriv = host->private_data;
|
|
struct piix_host_priv *hpriv = host->private_data;
|
|
- struct ata_device *dev0 = &host->ports[0]->link.device[0];
|
|
|
|
|
|
+ struct ata_link *link0 = &host->ports[0]->link;
|
|
u32 scontrol;
|
|
u32 scontrol;
|
|
- int i;
|
|
|
|
|
|
+ int i, rc;
|
|
|
|
|
|
/* check for availability */
|
|
/* check for availability */
|
|
for (i = 0; i < 4; i++)
|
|
for (i = 0; i < 4; i++)
|
|
if (hpriv->map[i] == IDE)
|
|
if (hpriv->map[i] == IDE)
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
|
|
if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
|
|
if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
|
|
pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
|
|
pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
|
|
if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
|
|
hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
|
|
|
|
|
|
@@ -1399,7 +1298,7 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
|
|
* Give it a test drive by inhibiting power save modes which
|
|
* Give it a test drive by inhibiting power save modes which
|
|
* we'll do anyway.
|
|
* we'll do anyway.
|
|
*/
|
|
*/
|
|
- scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
|
|
|
|
|
|
+ piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
|
|
|
|
|
|
/* if IPM is already 3, SCR access is probably working. Don't
|
|
/* if IPM is already 3, SCR access is probably working. Don't
|
|
* un-inhibit power save modes as BIOS might have inhibited
|
|
* un-inhibit power save modes as BIOS might have inhibited
|
|
@@ -1407,18 +1306,30 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
|
|
*/
|
|
*/
|
|
if ((scontrol & 0xf00) != 0x300) {
|
|
if ((scontrol & 0xf00) != 0x300) {
|
|
scontrol |= 0x300;
|
|
scontrol |= 0x300;
|
|
- piix_sidpr_write(dev0, SCR_CONTROL, scontrol);
|
|
|
|
- scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
|
|
|
|
|
|
+ piix_sidpr_scr_write(link0, SCR_CONTROL, scontrol);
|
|
|
|
+ piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
|
|
|
|
|
|
if ((scontrol & 0xf00) != 0x300) {
|
|
if ((scontrol & 0xf00) != 0x300) {
|
|
dev_printk(KERN_INFO, host->dev, "SCR access via "
|
|
dev_printk(KERN_INFO, host->dev, "SCR access via "
|
|
"SIDPR is available but doesn't work\n");
|
|
"SIDPR is available but doesn't work\n");
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- host->ports[0]->ops = &piix_sidpr_sata_ops;
|
|
|
|
- host->ports[1]->ops = &piix_sidpr_sata_ops;
|
|
|
|
|
|
+ /* okay, SCRs available, set ops and ask libata for slave_link */
|
|
|
|
+ for (i = 0; i < 2; i++) {
|
|
|
|
+ struct ata_port *ap = host->ports[i];
|
|
|
|
+
|
|
|
|
+ ap->ops = &piix_sidpr_sata_ops;
|
|
|
|
+
|
|
|
|
+ if (ap->flags & ATA_FLAG_SLAVE_POSS) {
|
|
|
|
+ rc = ata_slave_link_init(ap);
|
|
|
|
+ if (rc)
|
|
|
|
+ return rc;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
|
|
static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
|
|
@@ -1528,7 +1439,9 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
|
|
/* initialize controller */
|
|
/* initialize controller */
|
|
if (port_flags & ATA_FLAG_SATA) {
|
|
if (port_flags & ATA_FLAG_SATA) {
|
|
piix_init_pcs(host, piix_map_db_table[ent->driver_data]);
|
|
piix_init_pcs(host, piix_map_db_table[ent->driver_data]);
|
|
- piix_init_sidpr(host);
|
|
|
|
|
|
+ rc = piix_init_sidpr(host);
|
|
|
|
+ if (rc)
|
|
|
|
+ return rc;
|
|
}
|
|
}
|
|
|
|
|
|
/* apply IOCFG bit18 quirk */
|
|
/* apply IOCFG bit18 quirk */
|