[U-Boot] [PATCH 09/10] x86: Generate a valid MultiProcessor (MP) table
Simon Glass
sjg at chromium.org
Tue Jun 16 04:46:53 CEST 2015
Hi Bin,
On 15 June 2015 at 02:00, Bin Meng <bmeng.cn at gmail.com> wrote:
> Implement a weak write_mp_table() to create a minimal working MP
> table. This includes an MP floating table, a configuration table
> header and all of the 5 base configuration table entries. The I/O
> interrupt assignment table entry is created based on the same
> information used in the creation of PIRQ routing table from device
> tree. A check duplicated entry logic is applied to prevent writing
> multiple I/O interrupt entries with the same information.
>
> Use a Kconfig option GENERATE_MP_TABLE to tell U-Boot whether we
> need actually write the MP table at the F seg, just like we did for
> PIRQ routing and SFI tables. With MP table existence, linux kernel
> will switch to I/O APIC and local APIC to process all the peripheral
> interrupts instead of 8259 PICs. This takes full advantage of the
> multicore hardware and the SMP kernel.
>
> Signed-off-by: Bin Meng <bmeng.cn at gmail.com>
> ---
>
> arch/x86/Kconfig | 8 +++
> arch/x86/include/asm/mpspec.h | 10 +++
> arch/x86/lib/mpspec.c | 147 ++++++++++++++++++++++++++++++++++++++++++
> arch/x86/lib/tables.c | 5 ++
> 4 files changed, 170 insertions(+)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 1aeae9d..d4b2772 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -319,6 +319,14 @@ config GENERATE_SFI_TABLE
>
> For more information, see http://simplefirmware.org
>
> +config GENERATE_MP_TABLE
> + bool "Generate an MP (Multi-Processor) table"
> + help
> + Generate an MP (Multi-Processor) table for this board. The MP table
> + provides a way for the operating system to support for symmetric
> + multiprocessing as well as symmetric I/O interrupt handling with
> + the local APIC and I/O APIC.
> +
> endmenu
>
> config MAX_PIRQ_LINKS
> diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h
> index c489a58..e9e1a2a 100644
> --- a/arch/x86/include/asm/mpspec.h
> +++ b/arch/x86/include/asm/mpspec.h
> @@ -431,4 +431,14 @@ void mp_write_compat_address_space(struct mp_config_table *mc, u8 busid,
> */
> u32 mptable_finalize(struct mp_config_table *mc);
>
> +/**
> + * write_mp_table() - Write MP table
> + *
> + * This writes MP table at a given address.
> + *
> + * @addr: start address to write MP table
> + * @return: end address of MP table
> + */
> +u32 write_mp_table(u32 addr);
> +
> #endif /* __ASM_MPSPEC_H */
> diff --git a/arch/x86/lib/mpspec.c b/arch/x86/lib/mpspec.c
> index 657df22..1e3523f 100644
> --- a/arch/x86/lib/mpspec.c
> +++ b/arch/x86/lib/mpspec.c
> @@ -9,13 +9,17 @@
> #include <common.h>
> #include <cpu.h>
> #include <dm.h>
> +#include <fdtdec.h>
> #include <asm/cpu.h>
> +#include <asm/irq.h>
> #include <asm/ioapic.h>
> #include <asm/lapic.h>
> #include <asm/mpspec.h>
> #include <asm/tables.h>
> #include <dm/uclass-internal.h>
>
> +DECLARE_GLOBAL_DATA_PTR;
> +
> struct mp_config_table *mp_write_floating_table(struct mp_floating_table *mf)
> {
> u32 mc;
> @@ -236,3 +240,146 @@ u32 mptable_finalize(struct mp_config_table *mc)
>
> return end;
> }
> +
> +static void mptable_add_isa_interrupts(struct mp_config_table *mc, int bus_isa,
> + u32 apicid, int external_int2)
> +{
> + int i;
> +
> + mp_write_intsrc(mc, external_int2 ? MP_INT : MP_EXTINT,
> + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
> + bus_isa, 0, apicid, 0);
> + mp_write_intsrc(mc, MP_INT, MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
> + bus_isa, 1, apicid, 1);
> + mp_write_intsrc(mc, external_int2 ? MP_EXTINT : MP_INT,
> + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
> + bus_isa, 0, apicid, 2);
> +
> + for (i = 3; i < 16; i++)
> + mp_write_intsrc(mc, MP_INT,
> + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
> + bus_isa, i, apicid, i);
> +}
> +
> +static bool check_dup_entry(struct mpc_config_intsrc *intsrc_base,
> + int entry_num, u8 bus, u8 device, u8 pin)
Again can we avoid u8 on function parameters?
Also this one coudl use a comment.
> +{
> + struct mpc_config_intsrc *intsrc = intsrc_base;
> + int i;
> +
> + for (i = 0; i < entry_num; i++) {
> + if (intsrc->mpc_srcbus == bus &&
> + intsrc->mpc_srcbusirq == ((device << 2) | (pin - 1)))
> + break;
> + intsrc++;
> + }
> +
> + return (i == entry_num) ? false : true;
> +}
> +
> +static void mptable_add_intsrc(struct mp_config_table *mc,
> + int bus_isa, u32 apicid)
> +{
> + struct mpc_config_intsrc *intsrc_base;
> + int intsrc_entries = 0;
> + const void *blob = gd->fdt_blob;
> + int node;
> + int len, count;
> + const u32 *cell;
> + int i;
> +
> + /* Legacy Interrupts */
> + debug("Writing ISA IRQs\n");
> + mptable_add_isa_interrupts(mc, bus_isa, apicid, 0);
> +
> + /* Get I/O interrupt information from device tree */
> + node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_IRQ_ROUTER);
> + if (node < 0) {
> + debug("%s: Cannot find irq router node\n", __func__);
> + return;
return -ENOENT
(and it's caller should check for error)
> + }
> +
> + cell = fdt_getprop(blob, node, "intel,pirq-routing", &len);
> + if (!cell)
> + return;
> +
> + if ((len % sizeof(struct pirq_routing)) == 0)
> + count = len / sizeof(struct pirq_routing);
> + else
> + return;
> +
> + intsrc_base = (struct mpc_config_intsrc *)mp_next_mpc_entry(mc);
> +
> + for (i = 0; i < count; i++) {
> + struct pirq_routing pr;
> +
> + pr.bdf = fdt_addr_to_cpu(cell[0]);
> + pr.pin = fdt_addr_to_cpu(cell[1]);
> + pr.pirq = fdt_addr_to_cpu(cell[2]);
> +
> + if (check_dup_entry(intsrc_base, intsrc_entries,
> + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf), pr.pin)) {
> + debug("found entry for bus %d device %d INT%c, skipping\n",
> + PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
> + 'A' + pr.pin - 1);
> + cell += sizeof(struct pirq_routing) / sizeof(u32);
> + continue;
> + }
> +
> + /* PIRQ[A-H] are always connected to I/O APIC INTPIN#16-23 */
> + mp_write_pci_intsrc(mc, MP_INT, PCI_BUS(pr.bdf),
> + PCI_DEV(pr.bdf), pr.pin, apicid,
> + pr.pirq + 16);
> + intsrc_entries++;
> + cell += sizeof(struct pirq_routing) / sizeof(u32);
> + }
> +}
> +
> +static void mptable_add_lintsrc(struct mp_config_table *mc, u32 bus_isa)
> +{
> + mp_write_lintsrc(mc, MP_EXTINT,
> + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
> + bus_isa, 0, MP_APIC_ALL, 0);
> + mp_write_lintsrc(mc, MP_NMI,
> + MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
> + bus_isa, 0, MP_APIC_ALL, 1);
> +}
> +
> +__weak u32 write_mp_table(u32 addr)
Why does this need to be weak?
> +{
> + struct mp_config_table *mc;
> + int ioapic_id, ioapic_ver;
> + int bus_isa = 0xff;
> + u32 end;
> +
> + /* 16 byte align the table address */
> + addr = ALIGN(addr, 16);
> +
> + /* Write floating table */
> + mc = mp_write_floating_table((struct mp_floating_table *)addr);
> +
> + /* Write configuration table header */
> + mp_config_table_init(mc);
> +
> + /* Write processor entry */
> + mp_write_processor(mc);
> +
> + /* Write bus entry */
> + mp_write_bus(mc, bus_isa, BUSTYPE_ISA);
> +
> + /* Write I/O APIC entry */
> + ioapic_id = io_apic_read(IO_APIC_ID) >> 24;
> + ioapic_ver = io_apic_read(IO_APIC_VER) & 0xff;
> + mp_write_ioapic(mc, ioapic_id, ioapic_ver, IO_APIC_ADDR);
> +
> + /* Write I/O interrupt assignment entry */
> + mptable_add_intsrc(mc, bus_isa, ioapic_id);
> +
> + /* Write local interrupt assignment entry */
> + mptable_add_lintsrc(mc, bus_isa);
> +
> + /* Finalize the MP table */
> + end = mptable_finalize(mc);
> +
> + return end;
> +}
> diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c
> index 8031201..d3bef6f 100644
> --- a/arch/x86/lib/tables.c
> +++ b/arch/x86/lib/tables.c
> @@ -6,6 +6,7 @@
>
> #include <common.h>
> #include <asm/sfi.h>
> +#include <asm/mpspec.h>
> #include <asm/tables.h>
>
> u8 table_compute_checksum(void *v, int len)
> @@ -32,4 +33,8 @@ void write_tables(void)
> rom_table_end = write_sfi_table(rom_table_end);
> rom_table_end = ALIGN(rom_table_end, 1024);
> #endif
> +#ifdef CONFIG_GENERATE_MP_TABLE
> + rom_table_end = write_mp_table(rom_table_end);
> + rom_table_end = ALIGN(rom_table_end, 1024);
> +#endif
> }
> --
> 1.8.2.1
>
Regards,
Simon
More information about the U-Boot
mailing list