sb/intel/common/pirq_gen: Rework generating pin-route tables
This creates a pin-route matrix first and then generates the ACPI entries based on that. This approach has the advantage of being simpler (no need for checks on double entries) and requiring less access to the pci config space. A few thing that are also fixed: * Don't declare DEFAULT_RCBA redundantly. * Only loop over PCI devices on bus 0 * Add a license header to rcba_pirq.c * Remove inappropriate use of typedefs * Fix the pin field: needs to be a byte * Fix the source field: it should either be a byte or a path (according to Advanced Configuration and Power Interface Specification rev 2.0c) Change-Id: Ic68a91d0cb55942a4d928b30f73e1c779142420d Signed-off-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-on: https://review.coreboot.org/22979 Reviewed-by: Nico Huber <nico.h@gmx.de> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
59326f35a9
commit
e8620146d9
|
@ -23,57 +23,55 @@
|
|||
#include "acpi_pirq_gen.h"
|
||||
|
||||
enum emit_type {
|
||||
EMIT_NONE,
|
||||
EMIT_APIC,
|
||||
EMIT_PICM,
|
||||
};
|
||||
|
||||
static size_t enumerate_root_pci_pins(const enum emit_type emit,
|
||||
const char *lpcb_path)
|
||||
static int create_pirq_matrix(char matrix[32][4])
|
||||
{
|
||||
char buffer[DEVICE_PATH_MAX];
|
||||
device_t dev;
|
||||
pci_pin_t prev_int_pin = PCI_INT_NONE;
|
||||
u8 prev_pci_dev = 0;
|
||||
size_t num_devs = 0;
|
||||
struct device *dev;
|
||||
int num_devs = 0;
|
||||
|
||||
for (dev = all_devices; dev; dev = dev->next) {
|
||||
for (dev = dev_find_slot(0, PCI_DEVFN(0, 0)); dev; dev = dev->sibling) {
|
||||
u8 pci_dev;
|
||||
u8 int_pin;
|
||||
pirq_t pirq;
|
||||
|
||||
if (dev->path.type != DEVICE_PATH_PCI ||
|
||||
dev->bus->secondary != 0)
|
||||
continue;
|
||||
|
||||
pci_dev = PCI_SLOT(dev->path.pci.devfn);
|
||||
int_pin = pci_read_config8(dev, PCI_INTERRUPT_PIN);
|
||||
|
||||
if (int_pin == PCI_INT_NONE || int_pin > PCI_INT_D)
|
||||
if (int_pin == PCI_INT_NONE || int_pin > PCI_INT_D ||
|
||||
matrix[pci_dev][int_pin - PCI_INT_A]
|
||||
!= PIRQ_NONE)
|
||||
continue;
|
||||
|
||||
pirq = intel_common_map_pirq(dev, int_pin);
|
||||
if (emit == EMIT_NONE) /* Only print on the first pass */
|
||||
matrix[pci_dev][int_pin - PCI_INT_A] =
|
||||
intel_common_map_pirq(dev, int_pin);
|
||||
printk(BIOS_SPEW, "ACPI_PIRQ_GEN: %s: pin=%d pirq=%d\n",
|
||||
dev_path(dev), int_pin, pirq);
|
||||
dev_path(dev), int_pin - PCI_INT_A,
|
||||
matrix[pci_dev][int_pin - PCI_INT_A] - PIRQ_A);
|
||||
num_devs++;
|
||||
}
|
||||
return num_devs;
|
||||
}
|
||||
|
||||
static void gen_pirq_route(const enum emit_type emit, const char *lpcb_path,
|
||||
char pci_int_mapping[32][4])
|
||||
{
|
||||
int pci_dev, int_pin;
|
||||
char buffer[DEVICE_PATH_MAX];
|
||||
char pirq;
|
||||
|
||||
for (pci_dev = 0; pci_dev < 32; pci_dev++) {
|
||||
for (int_pin = 0; int_pin < 4; int_pin++) {
|
||||
pirq = pci_int_mapping[pci_dev][int_pin];
|
||||
if (pirq == PIRQ_NONE)
|
||||
continue;
|
||||
|
||||
/* Avoid duplicate entries */
|
||||
if (prev_pci_dev == pci_dev && prev_int_pin == int_pin) {
|
||||
continue;
|
||||
} else {
|
||||
prev_int_pin = int_pin;
|
||||
prev_pci_dev = pci_dev;
|
||||
}
|
||||
if (emit != EMIT_NONE) {
|
||||
acpigen_write_package(4);
|
||||
acpigen_write_dword((pci_dev << 16) | 0xffff);
|
||||
acpigen_write_dword(int_pin - PCI_INT_A);
|
||||
acpigen_write_byte(int_pin);
|
||||
if (emit == EMIT_APIC) {
|
||||
acpigen_write_dword(0);
|
||||
acpigen_write_dword(16 + (pirq - PIRQ_A));
|
||||
acpigen_write_zero();
|
||||
acpigen_write_dword(16 + pirq - PIRQ_A);
|
||||
} else {
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"%s.LNK%c",
|
||||
|
@ -83,18 +81,24 @@ static size_t enumerate_root_pci_pins(const enum emit_type emit,
|
|||
}
|
||||
acpigen_pop_len();
|
||||
}
|
||||
num_devs++;
|
||||
}
|
||||
return num_devs;
|
||||
}
|
||||
|
||||
void intel_acpi_gen_def_acpi_pirq(device_t dev)
|
||||
void intel_acpi_gen_def_acpi_pirq(struct device *dev)
|
||||
{
|
||||
const char *lpcb_path = acpi_device_path(dev);
|
||||
const size_t num_devs = enumerate_root_pci_pins(EMIT_NONE, lpcb_path);
|
||||
char pci_int_mapping[32][4];
|
||||
int num_devs;
|
||||
|
||||
if (!lpcb_path)
|
||||
die("ACPI_PIRQ_GEN: Missing LPCB ACPI path\n");
|
||||
printk(BIOS_DEBUG, "Generating ACPI PIRQ entries\n");
|
||||
|
||||
if (!lpcb_path) {
|
||||
printk(BIOS_ERR, "ACPI_PIRQ_GEN: Missing LPCB ACPI path\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(pci_int_mapping, 0, sizeof(pci_int_mapping));
|
||||
num_devs = create_pirq_matrix(pci_int_mapping);
|
||||
|
||||
acpigen_write_scope("\\_SB.PCI0");
|
||||
acpigen_write_method("_PRT", 0);
|
||||
|
@ -102,13 +106,13 @@ void intel_acpi_gen_def_acpi_pirq(device_t dev)
|
|||
acpigen_emit_namestring("PICM");
|
||||
acpigen_emit_byte(RETURN_OP);
|
||||
acpigen_write_package(num_devs);
|
||||
enumerate_root_pci_pins(EMIT_APIC, lpcb_path);
|
||||
gen_pirq_route(EMIT_APIC, lpcb_path, pci_int_mapping);
|
||||
acpigen_pop_len(); /* package */
|
||||
acpigen_pop_len(); /* if PICM */
|
||||
acpigen_write_else();
|
||||
acpigen_emit_byte(RETURN_OP);
|
||||
acpigen_write_package(num_devs);
|
||||
enumerate_root_pci_pins(EMIT_PICM, lpcb_path);
|
||||
gen_pirq_route(EMIT_PICM, lpcb_path, pci_int_mapping);
|
||||
acpigen_pop_len(); /* package */
|
||||
acpigen_pop_len(); /* else PICM */
|
||||
acpigen_pop_len(); /* _PRT */
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
#ifndef INTEL_COMMON_ACPI_PIRQ_GEN_H
|
||||
#define INTEL_COMMON_ACPI_PIRQ_GEN_H
|
||||
|
||||
typedef enum pci_pin {
|
||||
enum pci_pin {
|
||||
PCI_INT_NONE = 0,
|
||||
PCI_INT_A,
|
||||
PCI_INT_B,
|
||||
PCI_INT_C,
|
||||
PCI_INT_D,
|
||||
} pci_pin_t;
|
||||
};
|
||||
|
||||
typedef enum pirq {
|
||||
enum pirq {
|
||||
PIRQ_NONE = 0,
|
||||
PIRQ_A,
|
||||
PIRQ_B,
|
||||
|
@ -34,9 +34,10 @@ typedef enum pirq {
|
|||
PIRQ_F,
|
||||
PIRQ_G,
|
||||
PIRQ_H,
|
||||
} pirq_t;
|
||||
};
|
||||
|
||||
void intel_acpi_gen_def_acpi_pirq(device_t dev);
|
||||
enum pirq intel_common_map_pirq(const device_t dev, const pci_pin_t pci_pin);
|
||||
void intel_acpi_gen_def_acpi_pirq(struct device *dev);
|
||||
enum pirq intel_common_map_pirq(const struct device *dev,
|
||||
const enum pci_pin pci_pin);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2017 Arthur Heymans <arthur@aheymans.xyz>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <device/device.h>
|
||||
#include <device/pci.h>
|
||||
|
@ -12,31 +27,30 @@ static const u32 pirq_dir_route_reg[MAX_SLOT - MIN_SLOT + 1] = {
|
|||
D26IR, D27IR, D28IR, D29IR, D30IR, D31IR,
|
||||
};
|
||||
|
||||
enum pirq intel_common_map_pirq(const device_t dev, const pci_pin_t pci_pin)
|
||||
enum pirq intel_common_map_pirq(const struct device *dev,
|
||||
const enum pci_pin pci_pin)
|
||||
{
|
||||
u8 slot = PCI_SLOT(dev->path.pci.devfn);
|
||||
u8 shift = 4 * (pci_pin - PCI_INT_A);
|
||||
u8 pirq;
|
||||
u16 reg;
|
||||
|
||||
if (pci_pin < 1 || pci_pin > 4) {
|
||||
printk(BIOS_ERR, "Slot %d PCI pin %d out of bounds\n",
|
||||
if (pci_pin < PCI_INT_A || pci_pin > PCI_INT_D) {
|
||||
printk(BIOS_ERR,
|
||||
"ACPI_PIRQ_GEN: Slot %d PCI pin %d out of bounds\n",
|
||||
slot, pci_pin);
|
||||
return PIRQ_NONE;
|
||||
}
|
||||
|
||||
if (slot < MIN_SLOT || slot > MAX_SLOT) {
|
||||
/* Slot 24 should not exist and has no D24IR but better be safe here */
|
||||
if (slot < MIN_SLOT || slot > MAX_SLOT || slot == 24) {
|
||||
/* non-PCH devices use 1:1 mapping. */
|
||||
return pci_pin;
|
||||
return (enum pirq)pci_pin;
|
||||
}
|
||||
|
||||
reg = pirq_dir_route_reg[slot - MIN_SLOT];
|
||||
|
||||
pirq = ((RCBA16(reg) >> shift) & 0xf);
|
||||
if (pirq > 8) {
|
||||
printk(BIOS_ERR, "Reg 0x%04x PIRQ %c out of bounds\n",
|
||||
reg, 'A' + pirq);
|
||||
return PIRQ_NONE;
|
||||
}
|
||||
return PIRQ_A + pirq;
|
||||
pirq = (RCBA16(reg) >> shift) & 0x7;
|
||||
|
||||
return (enum pirq)(PIRQ_A + pirq);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue