/* Copyright 2013-2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __INTERRUPTS_H
#define __INTERRUPTS_H

#include <stdint.h>
#include <ccan/list/list.h>

/*
 * Note about interrupt numbers on P7/P7+
 * ======================================
 *
 * The form of an interrupt number in the system on P7/P7+ is as follow:
 *
 * |  Node  | T| Chip|GX|           BUID           |   Level   |
 * |--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|
 *
 * Where:
 *
 *  - Node   : The 3-bit node number
 *  - T      : 1 for a Torrent chip, 0 otherwise
 *  - Chip   : 2-bit chip number in a node
 *  - GX     : GX bus identifier
 *  - BUID   : Bus identifier (*)
 *  - Level  : Interrupt number
 *
 * (*) The BUID/Level distinction is mostly historical, interrupt
 *     controllers such as the ICS in the PHBs "use" some of the
 *     low BUID bits as an extension to the interrupt number
 *
 * The NodeID and ChipID together form a 5-bit Processor Chip ID as
 * found in the PIR or in the SPIRA data structures (without the T bit)
 *
 * PSI interrupt numbering scheme:
 * -------------------------------
 *
 * This is tentatively deduced from stuff I found in some SCOM regs
 * and in the BookIV. The PSIHB can be used to specify the 9-bit BUID,
 * the Level is always 0. The doc also says that it prepends the 6-bit
 * PowerBus chipID (Node + T + Chip). I *assume* that it also prepends
 * a 0 in place of the GX bit.
 *
 * OPAL seems to be arbitrarily using a BUID value of 0x3, I shall do
 * the same "just in case" :-)
 *
 * NOTE: From grep'ing around the giant SCOM file for "Build", I found
 *       what looks like a register in the GX controller (Mode1
 *       register) where the PSI BUID can be stored as well. From
 *       looking around with the FSP getscom command, it appears
 *       that both pHyp and OPAL set this consistently to the same
 *       value that appears in the PHB configuration.
 *
 * => This is confirmed. The NX needs a similar configuration, this
 *    tells the GX controller not to forward transactions for these
 *    BUIDs down the GX bus.
 *
 * PCI interrupt numbering scheme:
 * -------------------------------
 *
 * See IOCs
 *
 * NX interrupt numbering scheme (p7+):
 * ------------------------------------
 *
 * TBD
 *
 * 
 * Additional note about routing of interrupts in P7 and P7+
 * =========================================================
 *
 * There are two on-chip sources of interrupts on these that need a
 * special treatment: The PSI interrupt and the NX interrupts.
 *
 * The problem is that they use the same BUID space as the IO chips
 * connected to the GX bus, so the GX controller needs to be told
 * about these BUIDs in order to avoid forwarding them down the GX
 * link (and possibly choking due to the lack of reply).
 *
 * The bad news is that it's all undocumented. The good news is that
 * I found the info after chatting with Bill Daly (HW design) and
 * looking at the SCOM register maps.
 *
 * The way to set that up differs between P7 and P7+:
 *
 * - On P7, it's in the GX_MODE1 register at SCOM 0x0201180A, which
 *   among other things, contains those bits:
 *
 *     18:26 PSI_BUID: BUID to be used to indicate the interrupt is
 *                     for the PSI
 *        27 DISABLE_PSI_BUID: set to 1 to disable the buid reservation
 *                             for PSI
 *
 *   So one must write the 9-bit BUID (without the top chipID) of the
 *   PSI interrupt in there and clear the disable bit.
 *
 * - On P7+ it's in the GX_MODE4 register at SCOM 0x02011811
 *
 *         0 ENABLE_NX_BUID: set to 1 to enable the buid reservation for nx
 *       1:9 NX_BUID_BASE: BUID BASE to be used to indicate the interrupt
 *                         is for the nx
 *     10:18 NX_BUID_MASK: BUID mask for the nx buid base
 *     19:27 PSI_BUID: BUID to be used to indicate the interrupt is for
 *                     the PSI
 *        28 DISABLE_PSI_BUID: set to 1 to disable the buid reservation
 *                             for PSI
 *
 * Note: The NX_BUID_MASK should have bits set to 1 that are relevant for
 *       the comparison to NX_BUID_BASE, ie 4 interrupts means a mask
 *       value of b'111111100
 */

#define P7_PSI_IRQ_BUID	0x3	/* 9-bit BUID for the PSI interrupts */

/* Extract individual components of an IRQ number */
#define P7_IRQ_BUID(irq)	(((irq) >>  4) & 0x1ff)
#define P7_IRQ_GXID(irq)	(((irq) >> 13) & 0x1)
#define P7_IRQ_CHIP(irq)	(((irq) >> 14) & 0x3)
#define P7_IRQ_TBIT(irq)	(((irq) >> 16) & 0x1)
#define P7_IRQ_NODE(irq)	(((irq) >> 17) & 0x7)

/* Extract the "full BUID" (extension + BUID) */
#define P7_IRQ_FBUID(irq)	(((irq) >> 4) & 0xffff)

/* BUID Extension (GX + CHIP + T + NODE) */
#define P7_IRQ_BEXT(irq)	(((irq) >> 13) & 0x7f)

/* Strip extension from BUID */
#define P7_BUID_BASE(buid)	((buid) & 0x1ff)


/* 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 */
