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>
