diff mbox

[U-Boot,RESPIN,v2,07/15] x86: Reduce PIRQ routing table size

Message ID BLU437-SMTP738F56569FE8B6B2BA2D7CBFA00@phx.gbl
State Accepted
Delegated to: Simon Glass
Headers show

Commit Message

Bin Meng June 23, 2015, 4:18 a.m. UTC
There is no need to populate multiple irq info entries with the same
bus number and device number, but with different interrupt pin. We
can use the same entry to store all the 4 interrupt pin (INT A/B/C/D)
routing information to reduce the whole PIRQ routing table size.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Simon Glass <sjg@chromium.org>

---

Changes in v2:
- Avoid using u16 and u8 in parameters

 arch/x86/cpu/irq.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 56 insertions(+), 9 deletions(-)

Comments

Simon Glass June 24, 2015, 2:46 a.m. UTC | #1
On 22 June 2015 at 22:18, Bin Meng <bmeng.cn@gmail.com> wrote:
> There is no need to populate multiple irq info entries with the same
> bus number and device number, but with different interrupt pin. We
> can use the same entry to store all the 4 interrupt pin (INT A/B/C/D)
> routing information to reduce the whole PIRQ routing table size.
>
> Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
> Acked-by: Simon Glass <sjg@chromium.org>
>
> ---
>
> Changes in v2:
> - Avoid using u16 and u8 in parameters
>
>  arch/x86/cpu/irq.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 56 insertions(+), 9 deletions(-)

Applied to u-boot-x86, thanks!
diff mbox

Patch

diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c
index df4300c..97dd000 100644
--- a/arch/x86/cpu/irq.c
+++ b/arch/x86/cpu/irq.c
@@ -58,17 +58,28 @@  void pirq_assign_irq(int link, u8 irq)
 		writeb(irq, irq_router.ibase + LINK_N2V(link, base));
 }
 
-static inline void fill_irq_info(struct irq_info **slotp, int *entries, u8 bus,
-				 u8 device, u8 pin, u8 pirq)
+static struct irq_info *check_dup_entry(struct irq_info *slot_base,
+					int entry_num, int bus, int device)
 {
-	struct irq_info *slot = *slotp;
+	struct irq_info *slot = slot_base;
+	int i;
+
+	for (i = 0; i < entry_num; i++) {
+		if (slot->bus == bus && slot->devfn == (device << 3))
+			break;
+		slot++;
+	}
 
+	return (i == entry_num) ? NULL : slot;
+}
+
+static inline void fill_irq_info(struct irq_info *slot, int bus, int device,
+				 int pin, int pirq)
+{
 	slot->bus = bus;
 	slot->devfn = (device << 3) | 0;
 	slot->irq[pin - 1].link = LINK_N2V(pirq, irq_router.link_base);
 	slot->irq[pin - 1].bitmap = irq_router.irq_mask;
-	(*entries)++;
-	(*slotp)++;
 }
 
 __weak void cpu_irq_init(void)
@@ -84,7 +95,7 @@  static int create_pirq_routing_table(void)
 	int len, count;
 	const u32 *cell;
 	struct irq_routing_table *rt;
-	struct irq_info *slot;
+	struct irq_info *slot, *slot_base;
 	int irq_entries = 0;
 	int i;
 	int ret;
@@ -167,7 +178,7 @@  static int create_pirq_routing_table(void)
 	rt->rtr_vendor = PCI_VENDOR_ID_INTEL;
 	rt->rtr_device = PCI_DEVICE_ID_INTEL_ICH7_31;
 
-	slot = rt->slots;
+	slot_base = rt->slots;
 
 	/* Now fill in the irq_info entries in the PIRQ table */
 	for (i = 0; i < count; i++) {
@@ -181,8 +192,44 @@  static int create_pirq_routing_table(void)
 		      i, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
 		      PCI_FUNC(pr.bdf), 'A' + pr.pin - 1,
 		      'A' + pr.pirq);
-		fill_irq_info(&slot, &irq_entries, PCI_BUS(pr.bdf),
-			      PCI_DEV(pr.bdf), pr.pin, pr.pirq);
+
+		slot = check_dup_entry(slot_base, irq_entries,
+				       PCI_BUS(pr.bdf), PCI_DEV(pr.bdf));
+		if (slot) {
+			debug("found entry for bus %d device %d, ",
+			      PCI_BUS(pr.bdf), PCI_DEV(pr.bdf));
+
+			if (slot->irq[pr.pin - 1].link) {
+				debug("skipping\n");
+
+				/*
+				 * Sanity test on the routed PIRQ pin
+				 *
+				 * If they don't match, show a warning to tell
+				 * there might be something wrong with the PIRQ
+				 * routing information in the device tree.
+				 */
+				if (slot->irq[pr.pin - 1].link !=
+					LINK_N2V(pr.pirq, irq_router.link_base))
+					debug("WARNING: Inconsistent PIRQ routing information\n");
+
+				cell += sizeof(struct pirq_routing) /
+					sizeof(u32);
+				continue;
+			} else {
+				debug("writing INT%c\n", 'A' + pr.pin - 1);
+				fill_irq_info(slot, PCI_BUS(pr.bdf),
+					      PCI_DEV(pr.bdf), pr.pin, pr.pirq);
+				cell += sizeof(struct pirq_routing) /
+					sizeof(u32);
+				continue;
+			}
+		}
+
+		slot = slot_base + irq_entries;
+		fill_irq_info(slot, PCI_BUS(pr.bdf), PCI_DEV(pr.bdf),
+			      pr.pin, pr.pirq);
+		irq_entries++;
 		cell += sizeof(struct pirq_routing) / sizeof(u32);
 	}