| 
									
										
										
										
											2013-04-17 20:30:26 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright 2012 Michael Ellerman, IBM Corporation. | 
					
						
							|  |  |  |  * Copyright 2012 Benjamin Herrenschmidt, IBM Corporation | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License, version 2, as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef _KVM_PPC_BOOK3S_XICS_H
 | 
					
						
							|  |  |  | #define _KVM_PPC_BOOK3S_XICS_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * We use a two-level tree to store interrupt source information. | 
					
						
							|  |  |  |  * There are up to 1024 ICS nodes, each of which can represent | 
					
						
							|  |  |  |  * 1024 sources. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define KVMPPC_XICS_MAX_ICS_ID	1023
 | 
					
						
							|  |  |  | #define KVMPPC_XICS_ICS_SHIFT	10
 | 
					
						
							|  |  |  | #define KVMPPC_XICS_IRQ_PER_ICS	(1 << KVMPPC_XICS_ICS_SHIFT)
 | 
					
						
							|  |  |  | #define KVMPPC_XICS_SRC_MASK	(KVMPPC_XICS_IRQ_PER_ICS - 1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Interrupt source numbers below this are reserved, for example | 
					
						
							|  |  |  |  * 0 is "no interrupt", and 2 is used for IPIs. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define KVMPPC_XICS_FIRST_IRQ	16
 | 
					
						
							|  |  |  | #define KVMPPC_XICS_NR_IRQS	((KVMPPC_XICS_MAX_ICS_ID + 1) * \
 | 
					
						
							|  |  |  | 				 KVMPPC_XICS_IRQ_PER_ICS) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Priority value to use for disabling an interrupt */ | 
					
						
							|  |  |  | #define MASKED	0xff
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* State for one irq source */ | 
					
						
							|  |  |  | struct ics_irq_state { | 
					
						
							|  |  |  | 	u32 number; | 
					
						
							|  |  |  | 	u32 server; | 
					
						
							|  |  |  | 	u8  priority; | 
					
						
							| 
									
										
										
										
											2013-04-17 20:32:04 +00:00
										 |  |  | 	u8  saved_priority; | 
					
						
							| 
									
										
										
										
											2013-04-17 20:30:26 +00:00
										 |  |  | 	u8  resend; | 
					
						
							|  |  |  | 	u8  masked_pending; | 
					
						
							|  |  |  | 	u8  asserted; /* Only for LSI */ | 
					
						
							|  |  |  | 	u8  exists; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Atomic ICP state, updated with a single compare & swap */ | 
					
						
							|  |  |  | union kvmppc_icp_state { | 
					
						
							|  |  |  | 	unsigned long raw; | 
					
						
							|  |  |  | 	struct { | 
					
						
							|  |  |  | 		u8 out_ee:1; | 
					
						
							|  |  |  | 		u8 need_resend:1; | 
					
						
							|  |  |  | 		u8 cppr; | 
					
						
							|  |  |  | 		u8 mfrr; | 
					
						
							|  |  |  | 		u8 pending_pri; | 
					
						
							|  |  |  | 		u32 xisr; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* One bit per ICS */ | 
					
						
							|  |  |  | #define ICP_RESEND_MAP_SIZE	(KVMPPC_XICS_MAX_ICS_ID / BITS_PER_LONG + 1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct kvmppc_icp { | 
					
						
							|  |  |  | 	struct kvm_vcpu *vcpu; | 
					
						
							|  |  |  | 	unsigned long server_num; | 
					
						
							|  |  |  | 	union kvmppc_icp_state state; | 
					
						
							|  |  |  | 	unsigned long resend_map[ICP_RESEND_MAP_SIZE]; | 
					
						
							| 
									
										
										
										
											2013-04-17 20:31:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Real mode might find something too hard, here's the action
 | 
					
						
							|  |  |  | 	 * it might request from virtual mode | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | #define XICS_RM_KICK_VCPU	0x1
 | 
					
						
							|  |  |  | #define XICS_RM_CHECK_RESEND	0x2
 | 
					
						
							|  |  |  | #define XICS_RM_REJECT		0x4
 | 
					
						
							|  |  |  | 	u32 rm_action; | 
					
						
							|  |  |  | 	struct kvm_vcpu *rm_kick_target; | 
					
						
							|  |  |  | 	u32  rm_reject; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Debug stuff for real mode */ | 
					
						
							|  |  |  | 	union kvmppc_icp_state rm_dbgstate; | 
					
						
							|  |  |  | 	struct kvm_vcpu *rm_dbgtgt; | 
					
						
							| 
									
										
										
										
											2013-04-17 20:30:26 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct kvmppc_ics { | 
					
						
							|  |  |  | 	struct mutex lock; | 
					
						
							|  |  |  | 	u16 icsid; | 
					
						
							|  |  |  | 	struct ics_irq_state irq_state[KVMPPC_XICS_IRQ_PER_ICS]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct kvmppc_xics { | 
					
						
							|  |  |  | 	struct kvm *kvm; | 
					
						
							| 
									
										
										
										
											2013-04-27 00:28:37 +00:00
										 |  |  | 	struct kvm_device *dev; | 
					
						
							| 
									
										
										
										
											2013-04-17 20:30:26 +00:00
										 |  |  | 	struct dentry *dentry; | 
					
						
							|  |  |  | 	u32 max_icsid; | 
					
						
							| 
									
										
										
										
											2013-04-17 20:31:15 +00:00
										 |  |  | 	bool real_mode; | 
					
						
							|  |  |  | 	bool real_mode_dbg; | 
					
						
							| 
									
										
										
										
											2013-04-17 20:30:26 +00:00
										 |  |  | 	struct kvmppc_ics *ics[KVMPPC_XICS_MAX_ICS_ID + 1]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline struct kvmppc_icp *kvmppc_xics_find_server(struct kvm *kvm, | 
					
						
							|  |  |  | 							 u32 nr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct kvm_vcpu *vcpu = NULL; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kvm_for_each_vcpu(i, vcpu, kvm) { | 
					
						
							|  |  |  | 		if (vcpu->arch.icp && nr == vcpu->arch.icp->server_num) | 
					
						
							|  |  |  | 			return vcpu->arch.icp; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline struct kvmppc_ics *kvmppc_xics_find_ics(struct kvmppc_xics *xics, | 
					
						
							|  |  |  | 						      u32 irq, u16 *source) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 icsid = irq >> KVMPPC_XICS_ICS_SHIFT; | 
					
						
							|  |  |  | 	u16 src = irq & KVMPPC_XICS_SRC_MASK; | 
					
						
							|  |  |  | 	struct kvmppc_ics *ics; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (source) | 
					
						
							|  |  |  | 		*source = src; | 
					
						
							|  |  |  | 	if (icsid > KVMPPC_XICS_MAX_ICS_ID) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	ics = xics->ics[icsid]; | 
					
						
							|  |  |  | 	if (!ics) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	return ics; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* _KVM_PPC_BOOK3S_XICS_H */
 |