[U-Boot] [PATCH 09/10] x86: Generate a valid MultiProcessor (MP) table
Simon Glass
sjg at chromium.org
Wed Jun 17 15:15:17 CEST 2015
Hi Bin,
On 17 June 2015 at 01:49, Bin Meng <bmeng.cn at gmail.com> wrote:
> Hi Simon,
>
> On Tue, Jun 16, 2015 at 10:46 AM, Simon Glass <sjg at chromium.org> wrote:
>> 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?
>
> 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?
Sounds good - 90% is a pretty good hit rate. We can always expand this
later when needed.
Regards,
Simon
More information about the U-Boot
mailing list