diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/skiboot/include/interrupts.h | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/skiboot/include/interrupts.h')
-rw-r--r-- | roms/skiboot/include/interrupts.h | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/roms/skiboot/include/interrupts.h b/roms/skiboot/include/interrupts.h new file mode 100644 index 000000000..7ffcc6c4f --- /dev/null +++ b/roms/skiboot/include/interrupts.h @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2013-2019 IBM Corp. */ + +#ifndef __INTERRUPTS_H +#define __INTERRUPTS_H + +#include <stdint.h> +#include <ccan/list/list.h> + +/* Note about interrupt numbers on P8 + * ================================== + * + * On P8 the interrupts numbers are just a flat space of 19-bit, + * there is no BUID or similar. + * + * However, various unit tend to require blocks of interrupt that + * are naturally power-of-two aligned + * + * Our P8 Interrupt map consits thus of dividing the chip space + * into "blocks" of 2048 interrupts. Block 0 is for random chip + * interrupt sources (NX, PSI, OCC, ...) and keeps sources 0..15 + * clear to avoid conflits with IPIs etc.... Block 1..n are assigned + * to PHB 0..n respectively. The number of blocks is determined by the + * number of bits assigned to chips. + * + * That gives us an interrupt number made of: + * 18 n+1 n 11 10 0 + * | | | | | | + * +--------------------+------+-----------------------------+ + * | Chip# | PHB# | IVE# | + * +--------------------+------+-----------------------------+ + * + * Where n = 18 - p8_chip_id_bits + * + * For P8 we have 6 bits for Chip# as defined by p8_chip_id_bits. We + * therefore support a max of 2^6 = 64 chips. + * + * For P8NVL we have an extra PHB and so we assign 5 bits for Chip# + * and therefore support a max of 32 chips. + * + * Each PHB supports 2K interrupt sources, which is shared by + * LSI and MSI. With default configuration, MSI would use range + * [0, 0x7f7] and LSI would use [0x7f8, 0x7ff]. The interrupt + * source should be combined with IRSN to form final hardware + * IRQ. + * + */ + +uint32_t p8_chip_irq_block_base(uint32_t chip, uint32_t block); +uint32_t p8_chip_irq_phb_base(uint32_t chip, uint32_t phb); +uint32_t p8_irq_to_chip(uint32_t irq); +uint32_t p8_irq_to_block(uint32_t irq); +uint32_t p8_irq_to_phb(uint32_t irq); + +/* Total number of bits in the P8 interrupt space */ +#define P8_IRQ_BITS 19 + +/* Number of bits per block */ +#define P8_IVE_BITS 11 + +#define P8_IRQ_BLOCK_MISC 0 +#define P8_IRQ_BLOCK_PHB_BASE 1 + +/* Assignment of the "MISC" block: + * ------------------------------- + * + * PSI interface has 6 interrupt sources: + * + * FSP, OCC, FSI, LPC, Local error, Host error + * + * and thus needs a block of 8 + */ +#define P8_IRQ_MISC_PSI_BASE 0x10 /* 0x10..0x17 */ + +/* These are handled by skiboot */ +#define P8_IRQ_PSI_FSP 0 +#define P8_IRQ_PSI_OCC 1 +#define P8_IRQ_PSI_FSI 2 +#define P8_IRQ_PSI_LPC 3 +#define P8_IRQ_PSI_LOCAL_ERR 4 +#define P8_IRQ_PSI_EXTERNAL 5 /* Used for UART */ +#define P8_IRQ_PSI_IRQ_COUNT 6 + +/* TBD: NX, AS, ... + */ + +/* Note about interrupt numbers on P9 + * ================================== + * + * P9 uses a completely different interrupt controller, XIVE. + * + * It targets objects using a combination of block number and + * index within a block. However, we try to avoid exposing that + * split to the OS in order to keep some abstraction in case the + * way we allocate these change. + * + * The lowest level entity in Xive is the ESB (state bits). + * + * Those are spread between PHBs, PSI bridge and XIVE itself which + * provide a large amount of state bits for IPIs and other SW and HW + * generated interrupts by sources that don't have their own ESB logic + * + * Due to that spread, they aren't a good representation of a global + * interrupt number. + * + * Each such source however needs to be targetted at an EAS (IVT) + * entry in a table which will control targetting information and + * associate that interrupt with a logical number. + * + * Thus that table entry number represents a good "global interrupt + * number". Additionally, for the host OS, we will keep the logical + * number equal to the global number. + * + * The details of how these are assigned on P9 can be found in + * hw/xive.c. P9 HW will only use a subset of the definitions and + * functions in this file (or the corresponding core/interrupts.c). + */ + +struct irq_source; + +/* + * IRQ sources register themselves here. + * + * The "attributes" callback provides various attributes specific to + * a given interrupt, such as whether it's targetted at OPAL or the + * OS, or whether it's frequent or infrequent. The latter will be used + * later to optimize the lookup of the sources array by providing a small + * cache of the frequent interrupts. + * + * The "eoi" callback is used for XIVE interrupts in XICS emulation + * though we might expose it at some point in XIVE native mode for + * interrupts that require special EOI operations such as possibly + * the LPC interrupts on P9 that need a latch cleared in the LPCHC. + * + * The "name" callback returns a name for the interrupt in a new + * malloc()'ed block. The caller will free() it. NULL is acceptable. + */ +struct irq_source_ops { + int64_t (*set_xive)(struct irq_source *is, uint32_t isn, + uint16_t server, uint8_t priority); + int64_t (*get_xive)(struct irq_source *is, uint32_t isn, + uint16_t *server, uint8_t *priority); + uint64_t (*attributes)(struct irq_source *is, uint32_t isn); +/* LSB is the target */ +#define IRQ_ATTR_TARGET_OPAL 0x0 +#define IRQ_ATTR_TARGET_LINUX 0x1 +/* For OPAL interrupts, estimate frequency */ +#define IRQ_ATTR_TARGET_RARE 0x0 +#define IRQ_ATTR_TARGET_FREQUENT 0x2 +/* For OPAL interrupts, level vs. edge setting */ +#define IRQ_ATTR_TYPE_LSI 0x0 +#define IRQ_ATTR_TYPE_MSI 0x4 + void (*interrupt)(struct irq_source *is, uint32_t isn); + void (*eoi)(struct irq_source *is, uint32_t isn); + char *(*name)(struct irq_source *is, uint32_t isn); +}; + +struct irq_source { + uint32_t start; + uint32_t end; + const struct irq_source_ops *ops; + void *data; + struct list_node link; +}; + +extern void __register_irq_source(struct irq_source *is, bool secondary); +extern void register_irq_source(const struct irq_source_ops *ops, void *data, + uint32_t start, uint32_t count); +extern void unregister_irq_source(uint32_t start, uint32_t count); +extern struct irq_source *irq_find_source(uint32_t isn); + +/* Warning: callback is called with internal source lock held + * so don't call back into any of our irq_ APIs from it + */ +extern void irq_for_each_source(void (*cb)(struct irq_source *, void *), + void *data); + +extern uint32_t get_psi_interrupt(uint32_t chip_id); + +extern struct dt_node *add_ics_node(void); +extern void add_opal_interrupts(void); +extern uint32_t get_ics_phandle(void); + +struct cpu_thread; + +extern void reset_cpu_icp(void); +extern void icp_send_eoi(uint32_t interrupt); +extern void icp_prep_for_pm(void); +extern void icp_kick_cpu(struct cpu_thread *cpu); + +extern void init_interrupts(void); + +extern bool irq_source_eoi(uint32_t isn); +extern bool __irq_source_eoi(struct irq_source *is, uint32_t isn); + + +#endif /* __INTERRUPTS_H */ |