Hi Bin, On 15 June 2015 at 02:00, Bin Meng <bmeng...@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...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot