diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/cpu/irq.c | 102 | ||||
-rw-r--r-- | arch/x86/include/asm/irq.h | 32 |
2 files changed, 101 insertions, 33 deletions
diff --git a/arch/x86/cpu/irq.c b/arch/x86/cpu/irq.c index 096c34f563..3adc155818 100644 --- a/arch/x86/cpu/irq.c +++ b/arch/x86/cpu/irq.c @@ -16,18 +16,75 @@ DECLARE_GLOBAL_DATA_PTR; +/** + * pirq_reg_to_linkno() - Convert a PIRQ routing register offset to link number + * + * @priv: IRQ router driver's priv data + * @reg: PIRQ routing register offset from the base address + * @return: PIRQ link number (0 for PIRQA, 1 for PIRQB, etc) + */ +static inline int pirq_reg_to_linkno(struct irq_router *priv, int reg) +{ + int linkno = 0; + + if (priv->has_regmap) { + struct pirq_regmap *map = priv->regmap; + int i; + + for (i = 0; i < priv->link_num; i++) { + if (reg - priv->link_base == map->offset) { + linkno = map->link; + break; + } + map++; + } + } else { + linkno = reg - priv->link_base; + } + + return linkno; +} + +/** + * pirq_linkno_to_reg() - Convert a PIRQ link number to routing register offset + * + * @priv: IRQ router driver's priv data + * @linkno: PIRQ link number (0 for PIRQA, 1 for PIRQB, etc) + * @return: PIRQ routing register offset from the base address + */ +static inline int pirq_linkno_to_reg(struct irq_router *priv, int linkno) +{ + int reg = 0; + + if (priv->has_regmap) { + struct pirq_regmap *map = priv->regmap; + int i; + + for (i = 0; i < priv->link_num; i++) { + if (linkno == map->link) { + reg = map->offset + priv->link_base; + break; + } + map++; + } + } else { + reg = linkno + priv->link_base; + } + + return reg; +} + bool pirq_check_irq_routed(struct udevice *dev, int link, u8 irq) { struct irq_router *priv = dev_get_priv(dev); u8 pirq; - int base = priv->link_base; if (priv->config == PIRQ_VIA_PCI) dm_pci_read_config8(dev->parent, - pirq_linkno_to_reg(link, base), &pirq); + pirq_linkno_to_reg(priv, link), &pirq); else pirq = readb((uintptr_t)priv->ibase + - pirq_linkno_to_reg(link, base)); + pirq_linkno_to_reg(priv, link)); pirq &= 0xf; @@ -42,13 +99,12 @@ int pirq_translate_link(struct udevice *dev, int link) { struct irq_router *priv = dev_get_priv(dev); - return pirq_reg_to_linkno(link, priv->link_base); + return pirq_reg_to_linkno(priv, link); } void pirq_assign_irq(struct udevice *dev, int link, u8 irq) { struct irq_router *priv = dev_get_priv(dev); - int base = priv->link_base; /* IRQ# 0/1/2/8/13 are reserved */ if (irq < 3 || irq == 8 || irq == 13) @@ -56,10 +112,10 @@ void pirq_assign_irq(struct udevice *dev, int link, u8 irq) if (priv->config == PIRQ_VIA_PCI) dm_pci_write_config8(dev->parent, - pirq_linkno_to_reg(link, base), irq); + pirq_linkno_to_reg(priv, link), irq); else writeb(irq, (uintptr_t)priv->ibase + - pirq_linkno_to_reg(link, base)); + pirq_linkno_to_reg(priv, link)); } static struct irq_info *check_dup_entry(struct irq_info *slot_base, @@ -82,7 +138,7 @@ static inline void fill_irq_info(struct irq_router *priv, struct irq_info *slot, { slot->bus = bus; slot->devfn = (device << 3) | 0; - slot->irq[pin - 1].link = pirq_linkno_to_reg(pirq, priv->link_base); + slot->irq[pin - 1].link = pirq_linkno_to_reg(priv, pirq); slot->irq[pin - 1].bitmap = priv->irq_mask; } @@ -93,6 +149,7 @@ static int create_pirq_routing_table(struct udevice *dev) int node; int len, count; const u32 *cell; + struct pirq_regmap *map; struct irq_routing_table *rt; struct irq_info *slot, *slot_base; int irq_entries = 0; @@ -127,6 +184,33 @@ static int create_pirq_routing_table(struct udevice *dev) priv->link_num = CONFIG_MAX_PIRQ_LINKS; } + cell = fdt_getprop(blob, node, "intel,pirq-regmap", &len); + if (cell) { + if (len % sizeof(struct pirq_regmap)) + return -EINVAL; + + count = len / sizeof(struct pirq_regmap); + if (count < priv->link_num) { + printf("Number of pirq-regmap entires is wrong\n"); + return -EINVAL; + } + + count = priv->link_num; + priv->regmap = calloc(count, sizeof(struct pirq_regmap)); + if (!priv->regmap) + return -ENOMEM; + + priv->has_regmap = true; + map = priv->regmap; + for (i = 0; i < count; i++) { + map->link = fdt_addr_to_cpu(cell[0]); + map->offset = fdt_addr_to_cpu(cell[1]); + + cell += sizeof(struct pirq_regmap) / sizeof(u32); + map++; + } + } + priv->irq_mask = fdtdec_get_int(blob, node, "intel,pirq-mask", PIRQ_BITMAP); @@ -209,7 +293,7 @@ static int create_pirq_routing_table(struct udevice *dev) * routing information in the device tree. */ if (slot->irq[pr.pin - 1].link != - pirq_linkno_to_reg(pr.pirq, priv->link_base)) + pirq_linkno_to_reg(priv, pr.pirq)) debug("WARNING: Inconsistent PIRQ routing information\n"); continue; } diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 9ac91f2296..e5c916070c 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -22,6 +22,11 @@ enum pirq_config { PIRQ_VIA_IBASE }; +struct pirq_regmap { + int link; + int offset; +}; + /** * Intel interrupt router control block * @@ -30,6 +35,7 @@ enum pirq_config { * @config: PIRQ_VIA_PCI or PIRQ_VIA_IBASE * @link_base: link value base number * @link_num: number of PIRQ links supported + * @has_regmap: has mapping table between PIRQ link and routing register offset * @irq_mask: IRQ mask reprenting the 16 IRQs in 8259, bit N is 1 means * IRQ N is available to be routed * @lb_bdf: irq router's PCI bus/device/function number encoding @@ -41,6 +47,8 @@ struct irq_router { int config; u32 link_base; int link_num; + bool has_regmap; + struct pirq_regmap *regmap; u16 irq_mask; u32 bdf; u32 ibase; @@ -54,30 +62,6 @@ struct pirq_routing { int pirq; }; -/** - * pirq_reg_to_linkno() - Convert a PIRQ routing register offset to link number - * - * @reg: PIRQ routing register offset from the base address - * @base: PIRQ routing register block base address - * @return: PIRQ link number (0 for PIRQA, 1 for PIRQB, etc) - */ -static inline int pirq_reg_to_linkno(int reg, int base) -{ - return reg - base; -} - -/** - * pirq_linkno_to_reg() - Convert a PIRQ link number to routing register offset - * - * @linkno: PIRQ link number (0 for PIRQA, 1 for PIRQB, etc) - * @base: PIRQ routing register block base address - * @return: PIRQ routing register offset from the base address - */ -static inline int pirq_linkno_to_reg(int linkno, int base) -{ - return linkno + base; -} - #define PIRQ_BITMAP 0xdef8 #endif /* _ARCH_IRQ_H_ */ |