text: // SPDX-License-Identifier: Apache-2.0
  /* 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 reset_cpu_xive(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 */
  