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:
Arthur Heymans 2017-12-23 21:47:45 +01:00 committed by Nico Huber
parent 59326f35a9
commit e8620146d9
3 changed files with 77 additions and 58 deletions

View File

@ -23,57 +23,55 @@
#include "acpi_pirq_gen.h" #include "acpi_pirq_gen.h"
enum emit_type { enum emit_type {
EMIT_NONE,
EMIT_APIC, EMIT_APIC,
EMIT_PICM, EMIT_PICM,
}; };
static size_t enumerate_root_pci_pins(const enum emit_type emit, static int create_pirq_matrix(char matrix[32][4])
const char *lpcb_path)
{ {
char buffer[DEVICE_PATH_MAX]; struct device *dev;
device_t dev; int num_devs = 0;
pci_pin_t prev_int_pin = PCI_INT_NONE;
u8 prev_pci_dev = 0;
size_t 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 pci_dev;
u8 int_pin; 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); pci_dev = PCI_SLOT(dev->path.pci.devfn);
int_pin = pci_read_config8(dev, PCI_INTERRUPT_PIN); 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; continue;
pirq = intel_common_map_pirq(dev, int_pin); matrix[pci_dev][int_pin - PCI_INT_A] =
if (emit == EMIT_NONE) /* Only print on the first pass */ intel_common_map_pirq(dev, int_pin);
printk(BIOS_SPEW, "ACPI_PIRQ_GEN: %s: pin=%d pirq=%d\n", 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;
}
if (pirq == PIRQ_NONE) static void gen_pirq_route(const enum emit_type emit, const char *lpcb_path,
continue; char pci_int_mapping[32][4])
{
int pci_dev, int_pin;
char buffer[DEVICE_PATH_MAX];
char pirq;
/* Avoid duplicate entries */ for (pci_dev = 0; pci_dev < 32; pci_dev++) {
if (prev_pci_dev == pci_dev && prev_int_pin == int_pin) { for (int_pin = 0; int_pin < 4; int_pin++) {
continue; pirq = pci_int_mapping[pci_dev][int_pin];
} else { if (pirq == PIRQ_NONE)
prev_int_pin = int_pin; continue;
prev_pci_dev = pci_dev;
}
if (emit != EMIT_NONE) {
acpigen_write_package(4); acpigen_write_package(4);
acpigen_write_dword((pci_dev << 16) | 0xffff); acpigen_write_dword((pci_dev << 16) | 0xffff);
acpigen_write_dword(int_pin - PCI_INT_A); acpigen_write_byte(int_pin);
if (emit == EMIT_APIC) { if (emit == EMIT_APIC) {
acpigen_write_dword(0); acpigen_write_zero();
acpigen_write_dword(16 + (pirq - PIRQ_A)); acpigen_write_dword(16 + pirq - PIRQ_A);
} else { } else {
snprintf(buffer, sizeof(buffer), snprintf(buffer, sizeof(buffer),
"%s.LNK%c", "%s.LNK%c",
@ -83,18 +81,24 @@ static size_t enumerate_root_pci_pins(const enum emit_type emit,
} }
acpigen_pop_len(); 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 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) printk(BIOS_DEBUG, "Generating ACPI PIRQ entries\n");
die("ACPI_PIRQ_GEN: Missing LPCB ACPI path\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_scope("\\_SB.PCI0");
acpigen_write_method("_PRT", 0); 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_namestring("PICM");
acpigen_emit_byte(RETURN_OP); acpigen_emit_byte(RETURN_OP);
acpigen_write_package(num_devs); 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(); /* package */
acpigen_pop_len(); /* if PICM */ acpigen_pop_len(); /* if PICM */
acpigen_write_else(); acpigen_write_else();
acpigen_emit_byte(RETURN_OP); acpigen_emit_byte(RETURN_OP);
acpigen_write_package(num_devs); 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(); /* package */
acpigen_pop_len(); /* else PICM */ acpigen_pop_len(); /* else PICM */
acpigen_pop_len(); /* _PRT */ acpigen_pop_len(); /* _PRT */

View File

@ -16,15 +16,15 @@
#ifndef INTEL_COMMON_ACPI_PIRQ_GEN_H #ifndef INTEL_COMMON_ACPI_PIRQ_GEN_H
#define 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_NONE = 0,
PCI_INT_A, PCI_INT_A,
PCI_INT_B, PCI_INT_B,
PCI_INT_C, PCI_INT_C,
PCI_INT_D, PCI_INT_D,
} pci_pin_t; };
typedef enum pirq { enum pirq {
PIRQ_NONE = 0, PIRQ_NONE = 0,
PIRQ_A, PIRQ_A,
PIRQ_B, PIRQ_B,
@ -34,9 +34,10 @@ typedef enum pirq {
PIRQ_F, PIRQ_F,
PIRQ_G, PIRQ_G,
PIRQ_H, PIRQ_H,
} pirq_t; };
void intel_acpi_gen_def_acpi_pirq(device_t dev); void intel_acpi_gen_def_acpi_pirq(struct device *dev);
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);
#endif #endif

View File

@ -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 <console/console.h>
#include <device/device.h> #include <device/device.h>
#include <device/pci.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, 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 slot = PCI_SLOT(dev->path.pci.devfn);
u8 shift = 4 * (pci_pin - PCI_INT_A); u8 shift = 4 * (pci_pin - PCI_INT_A);
u8 pirq; u8 pirq;
u16 reg; u16 reg;
if (pci_pin < 1 || pci_pin > 4) { if (pci_pin < PCI_INT_A || pci_pin > PCI_INT_D) {
printk(BIOS_ERR, "Slot %d PCI pin %d out of bounds\n", printk(BIOS_ERR,
"ACPI_PIRQ_GEN: Slot %d PCI pin %d out of bounds\n",
slot, pci_pin); slot, pci_pin);
return PIRQ_NONE; 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. */ /* non-PCH devices use 1:1 mapping. */
return pci_pin; return (enum pirq)pci_pin;
} }
reg = pirq_dir_route_reg[slot - MIN_SLOT]; reg = pirq_dir_route_reg[slot - MIN_SLOT];
pirq = ((RCBA16(reg) >> shift) & 0xf); pirq = (RCBA16(reg) >> shift) & 0x7;
if (pirq > 8) {
printk(BIOS_ERR, "Reg 0x%04x PIRQ %c out of bounds\n", return (enum pirq)(PIRQ_A + pirq);
reg, 'A' + pirq);
return PIRQ_NONE;
}
return PIRQ_A + pirq;
} }