Skip to contentSkip to conversation

ahci: implement handoff quirk

RFC PATCH In review Tejun Heo 4 participants 9 messages Jun 18, 2008 – Dec 18, 2009

Subsystems (2)
lore
Share & tools
lore

Tejun Heo

author
#0 lore raw

RFC PATCH 1/1 ahci: implement handoff quirk

ahci 1.2 has an exciting! new feature called BIOS/OS handoff which basically is there to allow BIOS to keep tinkering with the controller even after OS starts executing. I have no idea what this is useful for but it's there and we need to do it.

This patch implements the handoff as FIXUP_HEADER as the controller needs to be claimed before the OS changes any configuration including IRQ routing.

I'm yet to see any controller which actually requires this, so it's not for inclusion yet. Maybe keep this in a separate branch?

RFC, DON'T COMMIT

---
 drivers/pci/quirks.c |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)
drivers/pci/quirks.c +109 -0
index 7a222d0..9b77d49 100644
@@ -1207,6 +1207,115 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc);
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc);
 
+/*
+ * We don't want the BIOS to meddle with the controller no matter when
+ * or which driver will get attached to it.  Claim the controller
+ * early.
+ */
+static void quirk_ahci_handoff(struct pci_dev *pdev)
+{
+	enum {
+		ABAR		= 5,
+
+		CTL		= 0x04,
+		CTL_AHCI_EN	= (1 << 31), /* AHCI enabled */
+
+		VERSION		= 0x10,      /* AHCI spec. version compliancy */
+		VER_1_2		= 0x00010200,
+
+		CAP2		= 0x24,	     /* host capabilities extended */
+		CAP2_HANDOFF	= (1 << 0),  /* BIOS/OS handoff */
+
+		HANDOFF		= 0x28,      /* BIOS/OS handoff ctl and stat */
+		HANDOFF_BIOS	= (1 << 0),  /* BIOS owns */
+		HANDOFF_OS	= (1 << 1),  /* OS owns */
+		HANDOFF_OS_CHG_SMI = (1 << 2), /* SMI on OS_CHG */
+		HANDOFF_OS_CHG	= (1 << 3),  /* OS ownership changed */
+		HANDOFF_BUSY	= (1 << 4),  /* BIOS is accessing */
+	};
+	void __iomem *mmio;
+	u32 saved_ctl, version, cap2, handoff;
+	int i;
+
+	/* Fixup can't match class, do it manually.  Add device
+	 * matches here too.
+	 */
+	if (pdev->class == PCI_CLASS_STORAGE_SATA_AHCI)
+		goto is_ahci;
+	return;
+
+ is_ahci:
+	/* map AHCI BAR */
+	mmio = pci_iomap(pdev, ABAR, 0);
+	if (!mmio) {
+		dev_printk(KERN_WARNING, &pdev->dev,
+			   "%s: failed to map AHCI_BAR\n", __FUNCTION__);
+		return;
+	}
+
+	/* turn on AHCI mode and check version */
+	saved_ctl = ioread32(mmio + CTL);
+	if (!(saved_ctl & CTL_AHCI_EN))
+		iowrite32(saved_ctl | CTL_AHCI_EN, mmio + CTL);
+
+	version = ioread32(mmio + VERSION);
+	if (version < VER_1_2)
+		goto out;
+
+	/* test HOST_CAP2_HANDOFF */
+	cap2 = ioread32(mmio + CAP2);
+	if (!(cap2 & CAP2_HANDOFF))
+		goto out;
+
+	/* do we already own it? */
+	handoff = ioread32(mmio + HANDOFF);
+	if ((handoff & (HANDOFF_BIOS|HANDOFF_OS|HANDOFF_BUSY)) == HANDOFF_OS)
+		goto out;
+
+	dev_printk(KERN_INFO, &pdev->dev,
+		   "executing AHCI BIOS/OS handoff (0x%x)\n", handoff);
+
+	handoff |= HANDOFF_OS;
+	iowrite32(handoff, mmio + HANDOFF);
+
+	/* BIOS should set HANDOFF_BUSY in 25ms if necessary, be
+	 * generous and give it 50ms.
+	 */
+	for (i = 0; i < 5; i++) {
+		handoff = ioread32(mmio + HANDOFF);
+		if (handoff & HANDOFF_BUSY)
+			break;
+		msleep(10);
+	}
+
+	/* If BIOS wants to spend a bit more with the controller, let
+	 * it.  Spec says 2s but we're merciful.  Give it one more
+	 * full second.
+	 */
+	if (handoff & HANDOFF_BUSY)
+		for (i = 0; i < 30; i++) {
+			handoff = ioread32(mmio + HANDOFF);
+			if (handoff & HANDOFF_BUSY)
+				break;
+			msleep(100);
+		}
+
+	if ((handoff & (HANDOFF_BIOS|HANDOFF_OS|HANDOFF_BUSY)) == HANDOFF_OS)
+		goto out;
+
+	dev_printk(KERN_WARNING, &pdev->dev,
+		   "AHCI BIOS/OS handoff failed (handoff=0x%x)\n", handoff);
+
+	/* try to override */
+	handoff |= HANDOFF_OS;
+	handoff &= ~(HANDOFF_BIOS | HANDOFF_BUSY);
+	iowrite32(handoff, mmio + HANDOFF);
+ out:
+	iowrite32(saved_ctl, mmio + CTL);
+	pci_iounmap(pdev, mmio);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_ahci_handoff);
+
 #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
 
 /*
#1 lore raw
Quoted 5 lines · Tejun Heo

ahci 1.2 has an exciting! new feature called BIOS/OS handoff which basically is there to allow BIOS to keep tinkering with the controller even after OS starts executing. I have no idea what this is useful for but it's there and we need to do it.

Quoted 8 lines

This patch implements the handoff as FIXUP_HEADER as the controller needs to be claimed before the OS changes any configuration including IRQ routing.

I'm yet to see any controller which actually requires this, so it's not for inclusion yet. Maybe keep this in a separate branch?

RFC, DON'T COMMIT

We probably need to do this...

it's not a controller requirement but a BIOS one, so in theory even an existing, deployed AHCI 1.2 platform could suddenly require BIOS/OS handoff, if a BIOS update suddenly starts doing new and weird stuff in SMI.

Note that we need to do BIOS/OS handoff upon resume as well as at boot time.

Jeff

author
#2 lore raw
Quoted 8 lines · Jeff Garzik

We probably need to do this...

it's not a controller requirement but a BIOS one, so in theory even an existing, deployed AHCI 1.2 platform could suddenly require BIOS/OS handoff, if a BIOS update suddenly starts doing new and weird stuff in SMI.

Note that we need to do BIOS/OS handoff upon resume as well as at boot time.

Yeah, probably. Do you know of any system which makes use of this feature? I'm a bit uneasy about committing it without any testing.

Thanks.

Signature · 1 line
tejun
#3 lore raw
Quoted 7 lines · Tejun Heo
Quoted 6 lines · Jeff Garzik

We probably need to do this...

it's not a controller requirement but a BIOS one, so in theory even an existing, deployed AHCI 1.2 platform could suddenly require BIOS/OS handoff, if a BIOS update suddenly starts doing new and weird stuff in SMI.

Quoted 5 lines
Quoted 2 lines

Note that we need to do BIOS/OS handoff upon resume as well as at boot time.

Yeah, probably. Do you know of any system which makes use of this feature? I'm a bit uneasy about committing it without any testing.

I don't.

But the purpose of the feature is to tell BIOS to cleanup and stop using the hardware. It's a dumb feature, because of compatibility realities, but hey, other network and SCSI drivers have been doing this sort of synchronization with their on-board firmwares for years.

IMO the more dangerous route is to continue loading ahci, without first telling the BIOS to clean up and get out of our way.

Jeff

author
#4 lore raw
Quoted 17 lines · Jeff Garzik
Quoted 8 lines · Tejun Heo
Quoted 7 lines · Jeff Garzik

We probably need to do this...

it's not a controller requirement but a BIOS one, so in theory even an existing, deployed AHCI 1.2 platform could suddenly require BIOS/OS handoff, if a BIOS update suddenly starts doing new and weird stuff in SMI.

Quoted 5 lines
Quoted 2 lines

Note that we need to do BIOS/OS handoff upon resume as well as at boot time.

Yeah, probably. Do you know of any system which makes use of this feature? I'm a bit uneasy about committing it without any testing.

I don't.

Quoted 7 lines

But the purpose of the feature is to tell BIOS to cleanup and stop using the hardware. It's a dumb feature, because of compatibility realities, but hey, other network and SCSI drivers have been doing this sort of synchronization with their on-board firmwares for years.

IMO the more dangerous route is to continue loading ahci, without first telling the BIOS to clean up and get out of our way.

Hmmm.... yeah, I'm just worried a bit about adding a chunk of completely untested code. How about adding a big fat warning message which gets triggered if the handoff thing seems to be active?

Thanks.

Signature · 1 line
tejun
#5 lore raw
Quoted 21 lines · Tejun Heo
Quoted 20 lines · Jeff Garzik
Quoted 8 lines · Tejun Heo
Quoted 7 lines · Jeff Garzik

We probably need to do this...

it's not a controller requirement but a BIOS one, so in theory even an existing, deployed AHCI 1.2 platform could suddenly require BIOS/OS handoff, if a BIOS update suddenly starts doing new and weird stuff in SMI.

Quoted 4 lines
Quoted 2 lines

Note that we need to do BIOS/OS handoff upon resume as well as at boot time.

Yeah, probably. Do you know of any system which makes use of this feature? I'm a bit uneasy about committing it without any testing.

I don't.

But the purpose of the feature is to tell BIOS to cleanup and stop using the hardware. It's a dumb feature, because of compatibility realities, but hey, other network and SCSI drivers have been doing this sort of synchronization with their on-board firmwares for years.

Quoted 6 lines
Quoted 2 lines

IMO the more dangerous route is to continue loading ahci, without first telling the BIOS to clean up and get out of our way.

Hmmm.... yeah, I'm just worried a bit about adding a chunk of completely untested code. How about adding a big fat warning message which gets triggered if the handoff thing seems to be active?

Yeah, printing out something makes a lot of sense, but I would just add it to the flags output in ahci_print_info() or similar. If we don't see any further action from ahci (or the system as a whole), we know something exploded very early in the AHCI driver load.

Or maybe AMD (I see they're CC'd) could test this for us? AMD, what say you?

Jeff

#6 lore raw

Removing Richard since he already leaved AMD...

Hi Jeff and Tejun,

Quoted 5 lines

-----Original Message-----
From: Jeff Garzik [mailto:[email protected]]

Or maybe AMD (I see they're CC'd) could test this for us? AMD, what say you?

I'm okay for the test, please provide me the refined patch when it is ready.

Thanks
Shane

#7 lore raw
In reply to Tejun Heo
Quoted 9 lines · Tejun Heo

ahci 1.2 has an exciting! new feature called BIOS/OS handoff which basically is there to allow BIOS to keep tinkering with the controller even after OS starts executing. I have no idea what this is useful for but it's there and we need to do it.

This patch implements the handoff as FIXUP_HEADER as the controller needs to be claimed before the OS changes any configuration including IRQ routing.

Quoted 7 lines

I'm yet to see any controller which actually requires this, so it's not for inclusion yet. Maybe keep this in a separate branch?

RFC, DON'T COMMIT

---
  drivers/pci/quirks.c |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 109 insertions(+)

Looking through old emails... did AMD ever confirm the usefulness of this patch? Is it actually needed in the field? I'm guessing the silence implies "No"... :)

Jeff

#8 lore raw
Quoted 19 lines · Jeff Garzik
Quoted 9 lines · Tejun Heo

ahci 1.2 has an exciting! new feature called BIOS/OS handoff which basically is there to allow BIOS to keep tinkering with the controller even after OS starts executing. I have no idea what this is useful for but it's there and we need to do it.

This patch implements the handoff as FIXUP_HEADER as the controller needs to be claimed before the OS changes any configuration including IRQ routing.

Quoted 8 lines

I'm yet to see any controller which actually requires this, so it's not for inclusion yet. Maybe keep this in a separate branch?

RFC, DON'T COMMIT
---
drivers/pci/quirks.c | 109
+++++++++++++++++++++++++++++++++++++++++++++++++++

1 file changed, 109 insertions(+)
Quoted 3 lines

Looking through old emails... did AMD ever confirm the usefulness of this patch? Is it actually needed in the field? I'm guessing the silence implies "No"... :)

Well, we only implemented the feature bit displaying for the BOH "capability" recently, so I guess we wouldn't likely have seen it if something did advertise it. However, it's true I don't know why any sane BIOS would want to do this. Can't hurt to have the support, however..