Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be77e43a authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

ata_piix: drop merged SCR access and use slave_link instead



Now that libata has slave_link, there's no need to keep ugly merged
SCR access.  Drop it and use slave_link instead.  This results in
simpler code and much better separate link handling for master and
slave.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent b1c72916
Loading
Loading
Loading
Loading
+40 −127
Original line number Diff line number Diff line
@@ -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
 *
 * 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[] = {
	[SCR_STATUS]	= 0,
@@ -911,125 +897,38 @@ static const int piix_sidx_map[] = {
	[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;

	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);
}

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,
			       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))
		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;
}

static int piix_sidpr_scr_write(struct ata_link *link,
				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))
		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;
}

@@ -1370,28 +1269,28 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
	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 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;
	int i;
	int i, rc;

	/* check for availability */
	for (i = 0; i < 4; i++)
		if (hpriv->map[i] == IDE)
			return;
			return 0;

	if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
		return;
		return 0;

	if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
	    pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
		return;
		return 0;

	if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
		return;
		return 0;

	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
	 * 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
	 * 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) {
		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) {
			dev_printk(KERN_INFO, host->dev, "SCR access via "
				   "SIDPR is available but doesn't work\n");
			return;
			return 0;
		}
	}

	/* 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;
		}
	}

	host->ports[0]->ops = &piix_sidpr_sata_ops;
	host->ports[1]->ops = &piix_sidpr_sata_ops;
	return 0;
}

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 */
	if (port_flags & ATA_FLAG_SATA) {
		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 */