Hi Simon, On Tue, Jun 16, 2015 at 10:46 AM, Simon Glass <s...@chromium.org> wrote: > 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?
Yes, in v2. > Also this one coudl use a comment. > OK. >> +{ >> + 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) > OK >> + } >> + >> + 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? > I wanted to leave an option to have board-specific codes to implement the writing of mp table by using the APIs provided in this file, although I think this weak version could probably fit for 90% boards. We can remove the weak for now, and see how things go? [snip] Regards, Bin _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot