Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Nov 2003 21:48:56 -0500
From:      Alexandre "Sunny" Kovalenko <Alex.Kovalenko@verizon.net>
To:        freebsd-current@freebsd.org
Subject:   ThinkPad 560Z & ACPI
Message-ID:  <20031124214856.116be74c.Alex.Kovalenko@verizon.net>

index | next in thread | raw e-mail

[-- Attachment #1 --]
	Good people,

	I have managed to crowbar ACPI support into working on ThinkPad 560Z
	with the attached patch. The problem seems to be that TP returns 
	everything and a kitchen sink in the list of available IRQs, but expects
	OS to use one you have set up using TP Configuration Program (intuitively
	named PS2 ;). Thus with the current approach of taking first IRQ
	from the list, IRQ 3 gets everything routed to it, and since it is
	used by serial port, cardbus bridge, USB controller and fxp in the
	docking station fail rather miserably. fxp reports timeouts on the
	regular basis and the rest silently does nothing.

	I have added kernel environment variable "hw.acpi.pci.preferred_irq" 
	which would allow user to specify IRQ to be used (only in the case
	when it is in the list of available IRQs). If variable is not
	specified or if IRQ is not on the list of available ones, behaviour
	will revert to the original, which is to use first IRQ from the list.

	I do not know if this is the right way to address this problem and
	would appreciate any comments from people who actually know something
	about ACPI (as opposed to me). If there is the better way, I would 
	really appreciate a pointer, since ACPI on this machine is fairly 
	enjoyable. I have throtted CPU down to 25% and it is cool (in the 
	literal meaning of the word) and battery lasted for 2 hours+ while
	using wireless card.

	Conversely if there is a value in this approach, maybe some kind soul
	could stick it into the codebase. This way I would not have to aplly
	patch every time I cvsup ;)
	
-- 
Alexandre "Sunny" Kovalenko.

[-- Attachment #2 --]
--- acpi_pcib.c	Mon Nov 24 21:24:16 2003
+++ acpi_pcib.c.NEW	Mon Nov 24 21:23:59 2003
@@ -324,6 +324,48 @@
 	printf("  %d", Interrupts[i]);
     printf("\n");
 
+    /*************************************************************/
+    /* This is the ugly hack to see if it will be working at all */
+    /* We will look for environment variable 'hw.acpi.pci.preferred_irq' 
+     * then check if IRQ in question is in the list of available ones
+     * and if it is available, we will use it. If it is not available
+     * we will fall back on "unscientific" first available interrupt
+     * (basically the way code worked before).
+     */
+    int preferred_irq_idx = 0;
+    char *pPreferredIRQ = getenv("hw.acpi.pci.preferred_irq");
+    if(pPreferredIRQ != NULL)
+    {
+      register char *pc;
+      /* I'm sure there is a better way ;) */
+      /* strlen + isdigit */
+      register int irq = 0;
+      for(pc = pPreferredIRQ; *pc != '\0'; pc++)
+      {
+	if((*pc < '0') || (*pc > '9'))
+	{
+	  device_printf(pcib, "Invalid preferred IRQ: %s, "
+			"falling back on first available\n", 
+			pPreferredIRQ);
+	  goto fallBackOnZero;
+	}
+	irq = (irq << 3) + (irq << 1) + (*pc - '0');
+      }
+      /* Looking for slot with the IRQ in question */
+      for(register int i = 0; i < NumberOfInterrupts; i++)
+      {
+	if(Interrupts[i] == irq)
+	{
+	  preferred_irq_idx = i;
+	  break;
+	}
+      }
+      device_printf(pcib, "User suggested IRQ: %d (slot %d)\n", 
+		    irq, preferred_irq_idx); 
+    }
+ fallBackOnZero:
+    /*************************************************************/
+
     if (crsbuf.Pointer != NULL)			/* should never happen */
 	AcpiOsFree(crsbuf.Pointer);
     crsbuf.Pointer = NULL;
@@ -332,29 +374,29 @@
 	resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
 	resbuf.Data.Irq = prsres->Data.Irq;		/* structure copy other fields */
 	resbuf.Data.Irq.NumberOfInterrupts = 1;
-	resbuf.Data.Irq.Interrupts[0] = Interrupts[0];	/* just take first... */
+	resbuf.Data.Irq.Interrupts[0] = Interrupts[preferred_irq_idx];	/* just take first... */
     } else {
 	resbuf.Id = ACPI_RSTYPE_EXT_IRQ;
 	resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
 	resbuf.Data.ExtendedIrq = prsres->Data.ExtendedIrq;	/* structure copy other fields */
 	resbuf.Data.ExtendedIrq.NumberOfInterrupts = 1;
-	resbuf.Data.ExtendedIrq.Interrupts[0] = Interrupts[0];	/* just take first... */
+	resbuf.Data.ExtendedIrq.Interrupts[0] = Interrupts[preferred_irq_idx];	/* just take first... */
     }
     if (ACPI_FAILURE(status = acpi_AppendBufferResource(&crsbuf, &resbuf))) {
 	device_printf(pcib, "couldn't route interrupt %d via %s, interrupt resource build failed - %s\n",
-		      Interrupts[0], acpi_name(lnkdev), AcpiFormatException(status));
+		      Interrupts[preferred_irq_idx], acpi_name(lnkdev), AcpiFormatException(status));
 	goto out;
     }
     if (ACPI_FAILURE(status = AcpiSetCurrentResources(lnkdev, &crsbuf))) {
 	device_printf(pcib, "couldn't route interrupt %d via %s - %s\n",
-		      Interrupts[0], acpi_name(lnkdev), AcpiFormatException(status));
+		      Interrupts[preferred_irq_idx], acpi_name(lnkdev), AcpiFormatException(status));
 	goto out;
     }
     
     /* successful, return the interrupt we just routed */
     device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", 
-	pci_get_slot(dev), 'A' + pin, Interrupts[0], acpi_name(lnkdev));
-    interrupt = Interrupts[0];
+	pci_get_slot(dev), 'A' + pin, Interrupts[preferred_irq_idx], acpi_name(lnkdev));
+    interrupt = Interrupts[preferred_irq_idx];
 
  out:
     if (crsbuf.Pointer != NULL)
help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20031124214856.116be74c.Alex.Kovalenko>