freebsd-dev/sys/i386/pci/pci_pir.c

789 lines
22 KiB
C
Raw Normal View History

/*-
Completely replace the PCI bus driver code to make it better reflect reality. There will be a new call interface, but for now the file pci_compat.c (which is to be deleted, after all drivers are converted) provides an emulation of the old PCI bus driver functions. The only change that might be visible to drivers is, that the type pcici_t (which had been meant to be just a handle, whose exact definition should not be relied on), has been converted into a pcicfgregs* . The Tekram AMD SCSI driver bogusly relied on the definition of pcici_t and has been converted to just call the PCI drivers functions to access configuration space register, instead of inventing its own ... This code is by no means complete, but assumed to be fully operational, and brings the official code base more in line with my development code. A new generic device descriptor data type has to be agreed on. The PCI code will then use that data type to provide new functionality: 1) userconfig support 2) "wired" PCI devices 3) conflicts checking against ISA/EISA 4) maps will depend on the command register enable bits 5) PCI to Anything bridges can be defined as devices, and are probed like any "standard" PCI device. The following features are currently missing, but will be added back, soon: 1) unknown device probe message 2) suppression of "mirrored" devices caused by ancient, broken chip-sets This code relies on generic shared interrupt support just commited to kern_intr.c (plus the modifications of isa.c and isa_device.h).
1997-05-26 15:08:43 +00:00
* Copyright (c) 1997, Stefan Esser <se@freebsd.org>
* Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
* Copyright (c) 2000, BSDi
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* Copyright (c) 2004, John Baldwin <jhb@FreeBSD.org>
Completely replace the PCI bus driver code to make it better reflect reality. There will be a new call interface, but for now the file pci_compat.c (which is to be deleted, after all drivers are converted) provides an emulation of the old PCI bus driver functions. The only change that might be visible to drivers is, that the type pcici_t (which had been meant to be just a handle, whose exact definition should not be relied on), has been converted into a pcicfgregs* . The Tekram AMD SCSI driver bogusly relied on the definition of pcici_t and has been converted to just call the PCI drivers functions to access configuration space register, instead of inventing its own ... This code is by no means complete, but assumed to be fully operational, and brings the official code base more in line with my development code. A new generic device descriptor data type has to be agreed on. The PCI code will then use that data type to provide new functionality: 1) userconfig support 2) "wired" PCI devices 3) conflicts checking against ISA/EISA 4) maps will depend on the command register enable bits 5) PCI to Anything bridges can be defined as devices, and are probed like any "standard" PCI device. The following features are currently missing, but will be added back, soon: 1) unknown device probe message 2) suppression of "mirrored" devices caused by ancient, broken chip-sets This code relies on generic shared interrupt support just commited to kern_intr.c (plus the modifications of isa.c and isa_device.h).
1997-05-26 15:08:43 +00:00
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
2003-06-02 17:01:49 +00:00
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/sysctl.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_param.h>
#include <machine/md_var.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <machine/pci_cfgreg.h>
#include <machine/segments.h>
#include <machine/pc/bios.h>
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
#define NUM_ISA_INTERRUPTS 16
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/*
* A link device. Loosely based on the ACPI PCI link device. This doesn't
* try to support priorities for different ISA interrupts.
*/
struct pci_link {
TAILQ_ENTRY(pci_link) pl_links;
uint8_t pl_id;
uint8_t pl_irq;
uint16_t pl_irqmask;
int pl_references;
int pl_routed;
};
struct pci_link_lookup {
struct pci_link **pci_link_ptr;
int bus;
int device;
int pin;
};
struct pci_dev_lookup {
uint8_t link;
int bus;
int device;
int pin;
};
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
typedef void pir_entry_handler(struct PIR_entry *entry,
struct PIR_intpin* intpin, void *arg);
static void pci_print_irqmask(u_int16_t irqs);
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
static int pci_pir_biosroute(int bus, int device, int func, int pin,
int irq);
static int pci_pir_choose_irq(struct pci_link *pci_link, int irqmask);
static void pci_pir_create_links(struct PIR_entry *entry,
struct PIR_intpin *intpin, void *arg);
static void pci_pir_dump_links(void);
static struct pci_link *pci_pir_find_link(uint8_t link_id);
static void pci_pir_find_link_handler(struct PIR_entry *entry,
struct PIR_intpin *intpin, void *arg);
static void pci_pir_initial_irqs(struct PIR_entry *entry,
struct PIR_intpin *intpin, void *arg);
static void pci_pir_parse(void);
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
static void pci_pir_print_intpin(struct PIR_entry *entry,
struct PIR_intpin *intpin, void *arg);
static void pci_pir_print_table(void);
static uint8_t pci_pir_search_irq(int bus, int device, int pin);
static int pci_pir_valid_irq(struct pci_link *pci_link, int irq);
static void pci_pir_walk_table(pir_entry_handler *handler, void *arg);
static MALLOC_DEFINE(M_PIR, "$PIR", "$PIR structures");
static struct PIR_table *pci_route_table;
static device_t pir_device;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
static int pci_route_count, pir_bios_irqs, pir_parsed;
static TAILQ_HEAD(, pci_link) pci_links;
static int pir_interrupt_weight[NUM_ISA_INTERRUPTS];
/* sysctl vars */
SYSCTL_DECL(_hw_pci);
/* XXX this likely should live in a header file */
2003-08-02 05:14:17 +00:00
#ifdef PC98
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/* IRQs 3, 5, 7, 9, 10, 11, 12, 13 */
2003-08-02 05:14:17 +00:00
#define PCI_IRQ_OVERRIDE_MASK 0x3e68
#else
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/* IRQs 3, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15 */
#define PCI_IRQ_OVERRIDE_MASK 0xdef8
2003-08-02 05:14:17 +00:00
#endif
static uint32_t pci_irq_override_mask = PCI_IRQ_OVERRIDE_MASK;
TUNABLE_INT("hw.pci.irq_override_mask", &pci_irq_override_mask);
SYSCTL_INT(_hw_pci, OID_AUTO, irq_override_mask, CTLFLAG_RDTUN,
2003-08-02 05:14:17 +00:00
&pci_irq_override_mask, PCI_IRQ_OVERRIDE_MASK,
"Mask of allowed irqs to try to route when it has no good clue about\n"
"which irqs it should use.");
/*
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* Look for the interrupt routing table.
*
* We use PCI BIOS's PIR table if it's available. $PIR is the standard way
* to do this. Sadly, some machines are not standards conforming and have
* _PIR instead. We shrug and cope by looking for both.
*/
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
void
pci_pir_open(void)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
struct PIR_table *pt;
uint32_t sigaddr;
int i;
uint8_t ck, *cv;
/* Don't try if we've already found a table. */
if (pci_route_table != NULL)
return;
/* Look for $PIR and then _PIR. */
sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
if (sigaddr == 0)
sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
if (sigaddr == 0)
return;
/* If we found something, check the checksum and length. */
/* XXX - Use pmap_mapdev()? */
pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
if (pt->pt_header.ph_length <= sizeof(struct PIR_header))
return;
for (cv = (u_int8_t *)pt, ck = 0, i = 0;
i < (pt->pt_header.ph_length); i++)
ck += cv[i];
if (ck != 0)
return;
/* Ok, we've got a valid table. */
pci_route_table = pt;
pci_route_count = (pt->pt_header.ph_length -
sizeof(struct PIR_header)) /
sizeof(struct PIR_entry);
if (bootverbose) {
printf("Found $PIR table, %d entries at %p\n",
pci_route_count, pci_route_table);
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_pir_print_table();
}
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/*
* Find the pci_link structure for a given link ID.
*/
static struct pci_link *
pci_pir_find_link(uint8_t link_id)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
struct pci_link *pci_link;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
if (pci_link->pl_id == link_id)
return (pci_link);
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
return (NULL);
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/*
* Find the link device associated with a PCI device in the table.
*/
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
static void
pci_pir_find_link_handler(struct PIR_entry *entry, struct PIR_intpin *intpin,
void *arg)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
struct pci_link_lookup *lookup;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
lookup = (struct pci_link_lookup *)arg;
if (entry->pe_bus == lookup->bus &&
entry->pe_device == lookup->device &&
intpin - entry->pe_intpin == lookup->pin)
*lookup->pci_link_ptr = pci_pir_find_link(intpin->link);
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/*
* Check to see if a possible IRQ setting is valid.
*/
static int
pci_pir_valid_irq(struct pci_link *pci_link, int irq)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
if (!PCI_INTERRUPT_VALID(irq))
return (0);
return (pci_link->pl_irqmask & (1 << irq));
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/*
* Walk the $PIR executing the worker function for each valid intpin entry
* in the table. The handler is passed a pointer to both the entry and
* the intpin in the entry.
*/
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
static void
pci_pir_walk_table(pir_entry_handler *handler, void *arg)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
struct PIR_entry *entry;
struct PIR_intpin *intpin;
int i, pin;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
entry = &pci_route_table->pt_entry[0];
for (i = 0; i < pci_route_count; i++, entry++) {
intpin = &entry->pe_intpin[0];
for (pin = 0; pin < 4; pin++, intpin++)
if (intpin->link != 0)
handler(entry, intpin, arg);
}
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
static void
pci_pir_create_links(struct PIR_entry *entry, struct PIR_intpin *intpin,
void *arg)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
struct pci_link *pci_link;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_link = pci_pir_find_link(intpin->link);
if (pci_link != NULL) {
pci_link->pl_references++;
if (intpin->irqs != pci_link->pl_irqmask) {
if (bootverbose)
printf(
"$PIR: Entry %d.%d.INT%c has different mask for link %#x, merging\n",
entry->pe_bus, entry->pe_device,
(intpin - entry->pe_intpin) + 'A',
pci_link->pl_id);
pci_link->pl_irqmask &= intpin->irqs;
}
} else {
pci_link = malloc(sizeof(struct pci_link), M_PIR, M_WAITOK);
pci_link->pl_id = intpin->link;
pci_link->pl_irqmask = intpin->irqs;
pci_link->pl_irq = PCI_INVALID_IRQ;
pci_link->pl_references = 1;
pci_link->pl_routed = 0;
TAILQ_INSERT_TAIL(&pci_links, pci_link, pl_links);
}
}
/*
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* Look to see if any of the function on the PCI device at bus/device have
* an interrupt routed to intpin 'pin' by the BIOS.
*/
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
static uint8_t
pci_pir_search_irq(int bus, int device, int pin)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
uint32_t value;
uint8_t func, maxfunc;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/* See if we have a valid device at function 0. */
value = pci_cfgregread(bus, device, 0, PCIR_HDRTYPE, 1);
if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
return (PCI_INVALID_IRQ);
if (value & PCIM_MFDEV)
maxfunc = PCI_FUNCMAX;
else
maxfunc = 0;
/* Scan all possible functions at this device. */
for (func = 0; func <= maxfunc; func++) {
value = pci_cfgregread(bus, device, func, PCIR_DEVVENDOR, 4);
if (value == 0xffffffff)
continue;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
value = pci_cfgregread(bus, device, func, PCIR_INTPIN, 1);
/*
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* See if it uses the pin in question. Note that the passed
* in pin uses 0 for A, .. 3 for D whereas the intpin
* register uses 0 for no interrupt, 1 for A, .. 4 for D.
*/
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
if (value != pin + 1)
continue;
value = pci_cfgregread(bus, device, func, PCIR_INTLINE, 1);
if (bootverbose)
printf(
"$PIR: Found matching pin for %d.%d.INT%c at func %d: %d\n",
bus, device, pin + 'A', func, value);
if (value != PCI_INVALID_IRQ)
return (value);
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
return (PCI_INVALID_IRQ);
}
/*
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* Try to initialize IRQ based on this device's IRQ.
*/
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
static void
pci_pir_initial_irqs(struct PIR_entry *entry, struct PIR_intpin *intpin,
void *arg)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
struct pci_link *pci_link;
uint8_t irq, pin;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pin = intpin - entry->pe_intpin;
pci_link = pci_pir_find_link(intpin->link);
irq = pci_pir_search_irq(entry->pe_bus, entry->pe_device, pin);
if (irq == PCI_INVALID_IRQ || irq == pci_link->pl_irq)
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
return;
/* Don't trust any BIOS IRQs greater than 15. */
if (irq >= NUM_ISA_INTERRUPTS) {
printf(
"$PIR: Ignoring invalid BIOS IRQ %d from %d.%d.INT%c for link %#x\n",
irq, entry->pe_bus, entry->pe_device, pin + 'A',
pci_link->pl_id);
return;
}
/*
* If we don't have an IRQ for this link yet, then we trust the
* BIOS, even if it seems invalid from the $PIR entries.
*/
if (pci_link->pl_irq == PCI_INVALID_IRQ) {
if (!pci_pir_valid_irq(pci_link, irq))
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
printf(
"$PIR: Using invalid BIOS IRQ %d from %d.%d.INT%c for link %#x\n",
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
irq, entry->pe_bus, entry->pe_device, pin + 'A',
pci_link->pl_id);
pci_link->pl_irq = irq;
pci_link->pl_routed = 1;
return;
}
/*
* We have an IRQ and it doesn't match the current IRQ for this
* link. If the new IRQ is invalid, then warn about it and ignore
* it. If the old IRQ is invalid and the new IRQ is valid, then
* prefer the new IRQ instead. If both IRQs are valid, then just
* use the first one. Note that if we ever get into this situation
* we are having to guess which setting the BIOS actually routed.
* Perhaps we should just give up instead.
*/
if (!pci_pir_valid_irq(pci_link, irq)) {
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
printf(
"$PIR: BIOS IRQ %d for %d.%d.INT%c is not valid for link %#x\n",
irq, entry->pe_bus, entry->pe_device, pin + 'A',
pci_link->pl_id);
} else if (!pci_pir_valid_irq(pci_link, pci_link->pl_irq)) {
printf(
"$PIR: Preferring valid BIOS IRQ %d from %d.%d.INT%c for link %#x to IRQ %d\n",
irq, entry->pe_bus, entry->pe_device, pin + 'A',
pci_link->pl_id, pci_link->pl_irq);
pci_link->pl_irq = irq;
pci_link->pl_routed = 1;
} else
printf(
"$PIR: BIOS IRQ %d for %d.%d.INT%c does not match link %#x irq %d\n",
irq, entry->pe_bus, entry->pe_device, pin + 'A',
pci_link->pl_id, pci_link->pl_irq);
}
/*
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* Parse $PIR to enumerate link devices and attempt to determine their
* initial state. This could perhaps be cleaner if we had drivers for the
* various interrupt routers as they could read the initial IRQ for each
* link.
*/
static void
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_pir_parse(void)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
char tunable_buffer[64];
struct pci_link *pci_link;
int i, irq;
/* Only parse once. */
if (pir_parsed)
return;
pir_parsed = 1;
/* Enumerate link devices. */
TAILQ_INIT(&pci_links);
pci_pir_walk_table(pci_pir_create_links, NULL);
if (bootverbose) {
printf("$PIR: Links after initial probe:\n");
pci_pir_dump_links();
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/* Check for unique IRQ masks. */
TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
if (pci_link->pl_irqmask != 0 && powerof2(pci_link->pl_irqmask))
pci_link->pl_irq = ffs(pci_link->pl_irqmask) - 1;
}
/*
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* Check to see if the BIOS has already routed any of the links by
* checking each device connected to each link to see if it has a
* valid IRQ.
*/
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_pir_walk_table(pci_pir_initial_irqs, NULL);
if (bootverbose) {
printf("$PIR: Links after initial IRQ discovery:\n");
pci_pir_dump_links();
}
/*
* Allow the user to override the IRQ for a given link device. We
* allow invalid IRQs to be specified but warn about them. An IRQ
* of 255 or 0 clears any preset IRQ.
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
*/
i = 0;
TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
snprintf(tunable_buffer, sizeof(tunable_buffer),
"hw.pci.link.%#x.irq", pci_link->pl_id);
if (getenv_int(tunable_buffer, &irq) == 0)
continue;
if (irq == 0)
irq = PCI_INVALID_IRQ;
if (irq != PCI_INVALID_IRQ &&
!pci_pir_valid_irq(pci_link, irq) && bootverbose)
printf(
"$PIR: Warning, IRQ %d for link %#x is not listed as valid\n",
irq, pci_link->pl_id);
pci_link->pl_routed = 0;
pci_link->pl_irq = irq;
i = 1;
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
if (bootverbose && i) {
printf("$PIR: Links after tunable overrides:\n");
pci_pir_dump_links();
}
/*
* Build initial interrupt weights as well as bitmap of "known-good"
* IRQs that the BIOS has already used for PCI link devices.
*/
TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
if (!PCI_INTERRUPT_VALID(pci_link->pl_irq))
continue;
pir_bios_irqs |= 1 << pci_link->pl_irq;
pir_interrupt_weight[pci_link->pl_irq] +=
pci_link->pl_references;
}
if (bootverbose) {
printf("$PIR: IRQs used by BIOS: ");
pci_print_irqmask(pir_bios_irqs);
printf("\n");
printf("$PIR: Interrupt Weights:\n[ ");
for (i = 0; i < NUM_ISA_INTERRUPTS; i++)
printf(" %3d", i);
printf(" ]\n[ ");
for (i = 0; i < NUM_ISA_INTERRUPTS; i++)
printf(" %3d", pir_interrupt_weight[i]);
printf(" ]\n");
}
}
/*
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* Use the PCI BIOS to route an interrupt for a given device.
*
* Input:
* AX = PCIBIOS_ROUTE_INTERRUPT
* BH = bus
* BL = device [7:3] / function [2:0]
* CH = IRQ
* CL = Interrupt Pin (0x0A = A, ... 0x0D = D)
*/
static int
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_pir_biosroute(int bus, int device, int func, int pin, int irq)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
struct bios_regs args;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
args.eax = PCIBIOS_ROUTE_INTERRUPT;
args.ebx = (bus << 8) | (device << 3) | func;
args.ecx = (irq << 8) | (0xa + pin);
return (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)));
}
/*
* Route a PCI interrupt using a link device from the $PIR.
*/
int
pci_pir_route_interrupt(int bus, int device, int func, int pin)
{
struct pci_link_lookup lookup;
struct pci_link *pci_link;
int error, irq;
if (pci_route_table == NULL)
return (PCI_INVALID_IRQ);
/* Lookup link device for this PCI device/pin. */
pci_link = NULL;
lookup.bus = bus;
lookup.device = device;
lookup.pin = pin - 1;
lookup.pci_link_ptr = &pci_link;
pci_pir_walk_table(pci_pir_find_link_handler, &lookup);
if (pci_link == NULL) {
printf("$PIR: No matching entry for %d.%d.INT%c\n", bus,
device, pin - 1 + 'A');
return (PCI_INVALID_IRQ);
}
/*
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* Pick a new interrupt if we don't have one already. We look for
* an interrupt from several different sets. First, we check the
* set of PCI only interrupts from the $PIR. Second, we check the
* set of known-good interrupts that the BIOS has already used.
* Lastly, we check the "all possible valid IRQs" set.
*/
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) {
irq = pci_pir_choose_irq(pci_link,
pci_route_table->pt_header.ph_pci_irqs);
if (!PCI_INTERRUPT_VALID(irq))
irq = pci_pir_choose_irq(pci_link, pir_bios_irqs);
if (!PCI_INTERRUPT_VALID(irq))
irq = pci_pir_choose_irq(pci_link,
pci_irq_override_mask);
if (!PCI_INTERRUPT_VALID(irq)) {
if (bootverbose)
printf(
"$PIR: Failed to route interrupt for %d:%d INT%c\n",
bus, device, pin - 1 + 'A');
return (PCI_INVALID_IRQ);
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_link->pl_irq = irq;
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/* Ask the BIOS to route this IRQ if we haven't done so already. */
if (!pci_link->pl_routed) {
error = pci_pir_biosroute(bus, device, func, pin - 1,
pci_link->pl_irq);
/* Ignore errors when routing a unique interrupt. */
if (error && !powerof2(pci_link->pl_irqmask)) {
printf("$PIR: ROUTE_INTERRUPT failed.\n");
return (PCI_INVALID_IRQ);
}
pci_link->pl_routed = 1;
/* Ensure the interrupt is set to level/low trigger. */
KASSERT(pir_device != NULL, ("missing pir device"));
BUS_CONFIG_INTR(pir_device, pci_link->pl_irq,
INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
}
if (bootverbose)
printf("$PIR: %d:%d INT%c routed to irq %d\n", bus, device,
pin - 1 + 'A', pci_link->pl_irq);
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
return (pci_link->pl_irq);
}
/*
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* Try to pick an interrupt for the specified link from the interrupts
* set in the mask.
*/
static int
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_pir_choose_irq(struct pci_link *pci_link, int irqmask)
{
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
int i, irq, realmask;
/* XXX: Need to have a #define of known bad IRQs to also mask out? */
realmask = pci_link->pl_irqmask & irqmask;
if (realmask == 0)
return (PCI_INVALID_IRQ);
/* Find IRQ with lowest weight. */
irq = PCI_INVALID_IRQ;
for (i = 0; i < NUM_ISA_INTERRUPTS; i++) {
if (!(realmask & 1 << i))
continue;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
if (irq == PCI_INVALID_IRQ ||
pir_interrupt_weight[i] < pir_interrupt_weight[irq])
irq = i;
}
if (bootverbose && PCI_INTERRUPT_VALID(irq)) {
printf("$PIR: Found IRQ %d for link %#x from ", irq,
pci_link->pl_id);
pci_print_irqmask(realmask);
printf("\n");
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
return (irq);
}
static void
pci_print_irqmask(u_int16_t irqs)
{
int i, first;
if (irqs == 0) {
printf("none");
return;
}
first = 1;
for (i = 0; i < 16; i++, irqs >>= 1)
if (irqs & 1) {
if (!first)
printf(" ");
else
first = 0;
printf("%d", i);
}
}
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
/*
* Dump the contents of a single intpin entry to the console.
*/
static void
pci_pir_print_intpin(struct PIR_entry *entry, struct PIR_intpin *intpin,
void *arg)
{
if (entry->pe_slot == 0)
printf("embedded ");
else
printf("slot %-3d ", entry->pe_slot);
printf(" %3d %3d %c 0x%02x ", entry->pe_bus, entry->pe_device,
intpin - entry->pe_intpin + 'A', intpin->link);
pci_print_irqmask(intpin->irqs);
printf("\n");
}
/*
* Dump the contents of a PCI BIOS Interrupt Routing Table to the console.
*/
static void
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_pir_print_table(void)
{
printf("PCI-Only Interrupts: ");
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_print_irqmask(pci_route_table->pt_header.ph_pci_irqs);
printf("\nLocation Bus Device Pin Link IRQs\n");
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_pir_walk_table(pci_pir_print_intpin, NULL);
}
/*
* Display link devices.
*/
static void
pci_pir_dump_links(void)
{
struct pci_link *pci_link;
printf("Link IRQ Rtd Ref IRQs\n");
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
printf("%#4x %3d %c %3d ", pci_link->pl_id,
pci_link->pl_irq, pci_link->pl_routed ? 'Y' : 'N',
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_link->pl_references);
pci_print_irqmask(pci_link->pl_irqmask);
printf("\n");
}
}
/*
* See if any interrupts for a given PCI bus are routed in the PIR. Don't
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
* even bother looking if the BIOS doesn't support routing anyways. If we
* are probing a PCI-PCI bridge, then require_parse will be true and we should
* only succeed if a host-PCI bridge has already attached and parsed the PIR.
*/
int
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
pci_pir_probe(int bus, int require_parse)
{
int i;
Rework the $PIR (aka PCIBIOS) PCI interrupt routing code and split it off into its own file: - All of the $PIR interrupt routing is now done in a link-centric fashion. When a host-PCI bridge that uses the $PIR attaches, it calls pir_parse() to parse the table. This scans for link devices and merges all the masks for each link device from the table entries. It then looks at the intline register of PCI devices connected to a link to figure out if the BIOS has routed this link and if so to which IRQ. - The IRQ for any given link can be overridden via a hint like so: 'hw.pci.link.0x62.irq=10' Any IRQ set in this matter is treated as if it were set that way by the BIOS. - We only call the BIOS to route each link device once. - When a PCI device wants to route an interrupt, we look it up in the $PIR to find the associated link. If the link is routed, we simply return the IRQ it is using. If it is not routed, we have to pick one. This uses a different algorithm from the old code. First off, when we try to pick an interrupt from a mask of possible interrupts, we try to pick the one that is least loaded as far as PCI devices. We maintain this weight based on the number of devices attached to each link device. When choosing an IRQ, we first attempt to route using any PCI only interrupts (the old code did this as well). If that doesn't work, we try to use the list of IRQs that the BIOS has used. This is a new step that the new code didn't do and avoids using IRQ 3 or 4 for every virgin interrupt routing. If none of the IRQs that the BIOS used worked, then we fall back to trying anything. - The fallback mask for !PC98 was fixed to include IRQ 3 and not allow IRQ 2. - We don't use the $PIR to route interrupts on a PCI-PCI bridge unless it has already been used to route on at least one Host-PCI bridge. This helps to avoid mixing and matching x86 firmware PCI interrupt routing methods (which is a Bad Thing(tm)). Silence on: current@
2004-02-18 22:40:23 +00:00
if (pci_route_table == NULL || (require_parse && !pir_parsed))
return (0);
for (i = 0; i < pci_route_count; i++)
if (pci_route_table->pt_entry[i].pe_bus == bus)
return (1);
return (0);
}
/*
* The driver for the new-bus psuedo device pir0 for the $PIR table.
*/
static int
pir_probe(device_t dev)
{
char buf[64];
snprintf(buf, sizeof(buf), "PCI Interrupt Routing Table: %d Entries",
pci_route_count);
device_set_desc_copy(dev, buf);
return (0);
}
static int
pir_attach(device_t dev)
{
pci_pir_parse();
KASSERT(pir_device == NULL, ("Multiple pir devices"));
pir_device = dev;
return (0);
}
static void
pir_resume_find_device(struct PIR_entry *entry, struct PIR_intpin *intpin,
void *arg)
{
struct pci_dev_lookup *pd;
pd = (struct pci_dev_lookup *)arg;
if (intpin->link != pd->link || pd->bus != -1)
return;
pd->bus = entry->pe_bus;
pd->device = entry->pe_device;
pd->pin = intpin - entry->pe_intpin;
}
static int
pir_resume(device_t dev)
{
struct pci_dev_lookup pd;
struct pci_link *pci_link;
int error;
/* Ask the BIOS to re-route each link that was already routed. */
TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) {
KASSERT(!pci_link->pl_routed,
("link %#x is routed but has invalid PCI IRQ",
pci_link->pl_id));
continue;
}
if (pci_link->pl_routed) {
pd.bus = -1;
pd.link = pci_link->pl_id;
pci_pir_walk_table(pir_resume_find_device, &pd);
KASSERT(pd.bus != -1,
("did not find matching entry for link %#x in the $PIR table",
pci_link->pl_id));
if (bootverbose)
device_printf(dev,
"Using %d.%d.INT%c to route link %#x to IRQ %d\n",
pd.bus, pd.device, pd.pin + 'A',
pci_link->pl_id, pci_link->pl_irq);
error = pci_pir_biosroute(pd.bus, pd.device, 0, pd.pin,
pci_link->pl_irq);
if (error)
device_printf(dev,
"ROUTE_INTERRUPT on resume for link %#x failed.\n",
pci_link->pl_id);
}
}
return (0);
}
static device_method_t pir_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pir_probe),
DEVMETHOD(device_attach, pir_attach),
DEVMETHOD(device_resume, pir_resume),
{ 0, 0 }
};
static driver_t pir_driver = {
"pir",
pir_methods,
1,
};
static devclass_t pir_devclass;
DRIVER_MODULE(pir, legacy, pir_driver, pir_devclass, 0, 0);