uboot/arch/x86/lib/pirq_routing.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
   3 *
   4 * Part of this file is ported from coreboot src/arch/x86/boot/pirq_routing.c
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <common.h>
  10#include <pci.h>
  11#include <asm/pci.h>
  12#include <asm/pirq_routing.h>
  13
  14static bool irq_already_routed[16];
  15
  16static u8 pirq_get_next_free_irq(struct udevice *dev, u8 *pirq, u16 bitmap)
  17{
  18        int i, link;
  19        u8 irq = 0;
  20
  21        /* IRQ sharing starts from IRQ#3 */
  22        for (i = 3; i < 16; i++) {
  23                /* Can we assign this IRQ? */
  24                if (!((bitmap >> i) & 1))
  25                        continue;
  26
  27                /* We can, now let's assume we can use this IRQ */
  28                irq = i;
  29
  30                /* Have we already routed it? */
  31                if (irq_already_routed[irq])
  32                        continue;
  33
  34                for (link = 0; link < CONFIG_MAX_PIRQ_LINKS; link++) {
  35                        if (pirq_check_irq_routed(dev, link, irq)) {
  36                                irq_already_routed[irq] = true;
  37                                break;
  38                        }
  39                }
  40
  41                /* If it's not yet routed, use it */
  42                if (!irq_already_routed[irq]) {
  43                        irq_already_routed[irq] = true;
  44                        break;
  45                }
  46
  47                /* But if it was already routed, try the next one */
  48        }
  49
  50        /* Now we get our IRQ */
  51        return irq;
  52}
  53
  54void pirq_route_irqs(struct udevice *dev, struct irq_info *irq, int num)
  55{
  56        unsigned char irq_slot[MAX_INTX_ENTRIES];
  57        unsigned char pirq[CONFIG_MAX_PIRQ_LINKS];
  58        int i, intx;
  59
  60        memset(pirq, 0, CONFIG_MAX_PIRQ_LINKS);
  61
  62        /* Set PCI IRQs */
  63        for (i = 0; i < num; i++) {
  64                debug("PIRQ Entry %d Dev: %d.%x.%d\n", i,
  65                      irq->bus, irq->devfn >> 3, irq->devfn & 7);
  66
  67                for (intx = 0; intx < MAX_INTX_ENTRIES; intx++) {
  68                        int link = irq->irq[intx].link;
  69                        int bitmap = irq->irq[intx].bitmap;
  70                        int irq = 0;
  71
  72                        debug("INT%c link: %x bitmap: %x ",
  73                              'A' + intx, link, bitmap);
  74
  75                        if (!bitmap || !link) {
  76                                debug("not routed\n");
  77                                irq_slot[intx] = irq;
  78                                continue;
  79                        }
  80
  81                        /* translate link value to link number */
  82                        link = pirq_translate_link(dev, link);
  83
  84                        /* yet not routed */
  85                        if (!pirq[link]) {
  86                                irq = pirq_get_next_free_irq(dev, pirq, bitmap);
  87                                pirq[link] = irq;
  88                        } else {
  89                                irq = pirq[link];
  90                        }
  91
  92                        debug("IRQ: %d\n", irq);
  93                        irq_slot[intx] = irq;
  94
  95                        /* Assign IRQ in the interrupt router */
  96                        pirq_assign_irq(dev, link, irq);
  97                }
  98
  99                /* Bus, device, slots IRQs for {A,B,C,D} */
 100                pci_assign_irqs(irq->bus, irq->devfn >> 3, irq_slot);
 101
 102                irq++;
 103        }
 104
 105        for (i = 0; i < CONFIG_MAX_PIRQ_LINKS; i++)
 106                debug("PIRQ%c: %d\n", 'A' + i, pirq[i]);
 107}
 108
 109u32 copy_pirq_routing_table(u32 addr, struct irq_routing_table *rt)
 110{
 111        struct irq_routing_table *rom_rt;
 112
 113        /* Align the table to be 16 byte aligned */
 114        addr = ALIGN(addr, 16);
 115
 116        debug("Copying Interrupt Routing Table to 0x%x\n", addr);
 117        memcpy((void *)addr, rt, rt->size);
 118
 119        /*
 120         * We do the sanity check here against the copied table after memcpy,
 121         * as something might go wrong after the memcpy, which is normally
 122         * due to the F segment decode is not turned on to systeam RAM.
 123         */
 124        rom_rt = (struct irq_routing_table *)addr;
 125        if (rom_rt->signature != PIRQ_SIGNATURE ||
 126            rom_rt->version != PIRQ_VERSION || rom_rt->size % 16) {
 127                printf("Interrupt Routing Table not valid\n");
 128                return addr;
 129        }
 130
 131        return addr + rt->size;
 132}
 133