/* * ARM Generic Interrupt Controller support * * Tim Deegan * Copyright (c) 2011 Citrix Systems. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef __ASM_ARM_GIC_H__ #define __ASM_ARM_GIC_H__ #define NR_GIC_LOCAL_IRQS NR_LOCAL_IRQS #define NR_GIC_SGI 16 #define GICD_CTLR (0x000) #define GICD_TYPER (0x004) #define GICD_IIDR (0x008) #define GICD_IGROUPR (0x080) #define GICD_IGROUPRN (0x0FC) #define GICD_ISENABLER (0x100) #define GICD_ISENABLERN (0x17C) #define GICD_ICENABLER (0x180) #define GICD_ICENABLERN (0x1fC) #define GICD_ISPENDR (0x200) #define GICD_ISPENDRN (0x27C) #define GICD_ICPENDR (0x280) #define GICD_ICPENDRN (0x2FC) #define GICD_ISACTIVER (0x300) #define GICD_ISACTIVERN (0x37C) #define GICD_ICACTIVER (0x380) #define GICD_ICACTIVERN (0x3FC) #define GICD_IPRIORITYR (0x400) #define GICD_IPRIORITYRN (0x7F8) #define GICD_ITARGETSR (0x800) #define GICD_ITARGETSR7 (0x81C) #define GICD_ITARGETSR8 (0x820) #define GICD_ITARGETSRN (0xBF8) #define GICD_ICFGR (0xC00) #define GICD_ICFGR1 (0xC04) #define GICD_ICFGR2 (0xC08) #define GICD_ICFGRN (0xCFC) #define GICD_NSACR (0xE00) #define GICD_NSACRN (0xEFC) #define GICD_SGIR (0xF00) #define GICD_CPENDSGIR (0xF10) #define GICD_CPENDSGIRN (0xF1C) #define GICD_SPENDSGIR (0xF20) #define GICD_SPENDSGIRN (0xF2C) #define GICD_ICPIDR2 (0xFE8) #define GICD_SGI_TARGET_LIST_SHIFT (24) #define GICD_SGI_TARGET_LIST_MASK (0x3UL << GICD_SGI_TARGET_LIST_SHIFT) #define GICD_SGI_TARGET_LIST (0UL<> 3) /* GICH_LR and GICH_VMCR only support 5 bits for guest irq priority */ #define GICH_LR_PENDING 1 #define GICH_LR_ACTIVE 2 #ifndef __ASSEMBLY__ #include #include #include #define DT_COMPAT_GIC_CORTEX_A15 "arm,cortex-a15-gic" #define DT_MATCH_GIC_V2 \ DT_MATCH_COMPATIBLE(DT_COMPAT_GIC_CORTEX_A15), \ DT_MATCH_COMPATIBLE("arm,cortex-a7-gic"), \ DT_MATCH_COMPATIBLE("arm,gic-400") #define DT_MATCH_GIC_V3 DT_MATCH_COMPATIBLE("arm,gic-v3") #ifdef CONFIG_HAS_GICV3 /* * GICv3 registers that needs to be saved/restored */ struct gic_v3 { uint32_t hcr, vmcr, sre_el1; uint32_t apr0[4]; uint32_t apr1[4]; uint64_t lr[16]; }; #endif /* * GICv2 register that needs to be saved/restored * on VCPU context switch */ struct gic_v2 { uint32_t hcr; uint32_t vmcr; uint32_t apr; uint32_t lr[64]; }; /* * Union to hold underlying hw version context information */ union gic_state_data { struct gic_v2 v2; #ifdef CONFIG_HAS_GICV3 struct gic_v3 v3; #endif }; /* * Decode LR register content. * The LR register format is different for GIC HW version */ struct gic_lr { /* Physical IRQ */ uint32_t pirq; /* Virtual IRQ */ uint32_t virq; uint8_t priority; uint8_t state; uint8_t hw_status; uint8_t grp; }; enum gic_version { GIC_V2, GIC_V3, }; extern enum gic_version gic_hw_version(void); /* Program the IRQ type into the GIC */ void gic_set_irq_type(struct irq_desc *desc, unsigned int type); /* Program the GIC to route an interrupt */ extern void gic_route_irq_to_xen(struct irq_desc *desc, unsigned int priority); extern int gic_route_irq_to_guest(struct domain *, unsigned int virq, struct irq_desc *desc, unsigned int priority); /* Remove an IRQ passthrough to a guest */ int gic_remove_irq_from_guest(struct domain *d, unsigned int virq, struct irq_desc *desc); extern void gic_inject(void); extern void gic_clear_pending_irqs(struct vcpu *v); extern int gic_events_need_delivery(void); extern void init_maintenance_interrupt(void); extern void gic_raise_guest_irq(struct vcpu *v, unsigned int irq, unsigned int priority); extern void gic_raise_inflight_irq(struct vcpu *v, unsigned int virtual_irq); extern void gic_remove_from_lr_pending(struct vcpu *v, struct pending_irq *p); extern void gic_remove_irq_from_queues(struct vcpu *v, struct pending_irq *p); /* Accept an interrupt from the GIC and dispatch its handler */ extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq); /* Find the interrupt controller and set up the callback to translate * device tree IRQ. */ extern void gic_preinit(void); /* Bring up the interrupt controller, and report # cpus attached */ extern void gic_init(void); /* Bring up a secondary CPU's per-CPU GIC interface */ extern void gic_init_secondary_cpu(void); /* Take down a CPU's per-CPU GIC interface */ extern void gic_disable_cpu(void); /* setup the gic virtual interface for a guest */ extern int gicv_setup(struct domain *d); /* Context switch */ extern void gic_save_state(struct vcpu *v); extern void gic_restore_state(struct vcpu *v); /* SGI (AKA IPIs) */ enum gic_sgi { GIC_SGI_EVENT_CHECK = 0, GIC_SGI_DUMP_STATE = 1, GIC_SGI_CALL_FUNCTION = 2, }; /* SGI irq mode types */ enum gic_sgi_mode { SGI_TARGET_LIST, SGI_TARGET_OTHERS, SGI_TARGET_SELF, }; extern void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi); extern void send_SGI_one(unsigned int cpu, enum gic_sgi sgi); extern void send_SGI_self(enum gic_sgi sgi); extern void send_SGI_allbutself(enum gic_sgi sgi); /* print useful debug info */ extern void gic_dump_info(struct vcpu *v); /* Number of interrupt lines */ extern unsigned int gic_number_lines(void); /* IRQ translation function for the device tree */ int gic_irq_xlate(const u32 *intspec, unsigned int intsize, unsigned int *out_hwirq, unsigned int *out_type); void gic_clear_lrs(struct vcpu *v); struct gic_info { /* GIC version */ enum gic_version hw_version; /* Number of GIC lines supported */ unsigned int nr_lines; /* Number of LR registers */ uint8_t nr_lrs; /* Maintenance irq number */ unsigned int maintenance_irq; /* Pointer to the device tree node representing the interrupt controller */ const struct dt_device_node *node; }; struct gic_hw_operations { /* Hold GIC HW information */ const struct gic_info *info; /* Initialize the GIC and the boot CPU */ int (*init)(void); /* Save GIC registers */ void (*save_state)(struct vcpu *); /* Restore GIC registers */ void (*restore_state)(const struct vcpu *); /* Dump GIC LR register information */ void (*dump_state)(const struct vcpu *); /* hw_irq_controller to enable/disable/eoi host irq */ hw_irq_controller *gic_host_irq_type; /* hw_irq_controller to enable/disable/eoi guest irq */ hw_irq_controller *gic_guest_irq_type; /* End of Interrupt */ void (*eoi_irq)(struct irq_desc *irqd); /* Deactivate/reduce priority of irq */ void (*deactivate_irq)(struct irq_desc *irqd); /* Read IRQ id and Ack */ unsigned int (*read_irq)(void); /* Set IRQ type */ void (*set_irq_type)(struct irq_desc *desc, unsigned int type); /* Set IRQ priority */ void (*set_irq_priority)(struct irq_desc *desc, unsigned int priority); /* Send SGI */ void (*send_SGI)(enum gic_sgi sgi, enum gic_sgi_mode irqmode, const cpumask_t *online_mask); /* Disable CPU physical and virtual interfaces */ void (*disable_interface)(void); /* Update LR register with state and priority */ void (*update_lr)(int lr, const struct pending_irq *pending_irq, unsigned int state); /* Update HCR status register */ void (*update_hcr_status)(uint32_t flag, bool set); /* Clear LR register */ void (*clear_lr)(int lr); /* Read LR register and populate gic_lr structure */ void (*read_lr)(int lr, struct gic_lr *); /* Write LR register from gic_lr structure */ void (*write_lr)(int lr, const struct gic_lr *); /* Read VMCR priority */ unsigned int (*read_vmcr_priority)(void); /* Read APRn register */ unsigned int (*read_apr)(int apr_reg); /* Secondary CPU init */ int (*secondary_init)(void); /* Create GIC node for the hardware domain */ int (*make_hwdom_dt_node)(const struct domain *d, const struct dt_device_node *gic, void *fdt); /* Create MADT table for the hardware domain */ int (*make_hwdom_madt)(const struct domain *d, u32 offset); /* Map extra GIC MMIO, irqs and other hw stuffs to the hardware domain. */ int (*map_hwdom_extra_mappings)(struct domain *d); /* Query the size of hardware domain madt table */ unsigned long (*get_hwdom_extra_madt_size)(const struct domain *d); /* Deny access to GIC regions */ int (*iomem_deny_access)(const struct domain *d); /* Handle LPIs, which require special handling */ void (*do_LPI)(unsigned int lpi); }; void register_gic_ops(const struct gic_hw_operations *ops); int gic_make_hwdom_dt_node(const struct domain *d, const struct dt_device_node *gic, void *fdt); int gic_make_hwdom_madt(const struct domain *d, u32 offset); unsigned long gic_get_hwdom_madt_size(const struct domain *d); int gic_map_hwdom_extra_mappings(struct domain *d); int gic_iomem_deny_access(const struct domain *d); #endif /* __ASSEMBLY__ */ #endif /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * indent-tabs-mode: nil * End: */