2016-12-19 22:25:00 +03:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2016,2017 ARM Limited, All Rights Reserved.
|
|
|
|
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __LINUX_IRQCHIP_ARM_GIC_V4_H
|
|
|
|
#define __LINUX_IRQCHIP_ARM_GIC_V4_H
|
|
|
|
|
|
|
|
struct its_vpe;
|
|
|
|
|
2017-10-08 20:48:06 +03:00
|
|
|
/*
|
|
|
|
* Maximum number of ITTs when GITS_TYPER.VMOVP == 0, using the
|
|
|
|
* ITSList mechanism to perform inter-ITS synchronization.
|
|
|
|
*/
|
|
|
|
#define GICv4_ITS_LIST_MAX 16
|
|
|
|
|
2016-12-19 22:25:00 +03:00
|
|
|
/* Embedded in kvm.arch */
|
|
|
|
struct its_vm {
|
|
|
|
struct fwnode_handle *fwnode;
|
|
|
|
struct irq_domain *domain;
|
|
|
|
struct page *vprop_page;
|
|
|
|
struct its_vpe **vpes;
|
|
|
|
int nr_vpes;
|
|
|
|
irq_hw_number_t db_lpi_base;
|
|
|
|
unsigned long *db_bitmap;
|
|
|
|
int nr_db_lpis;
|
2017-10-08 20:50:36 +03:00
|
|
|
u32 vlpi_count[GICv4_ITS_LIST_MAX];
|
2016-12-19 22:25:00 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Embedded in kvm_vcpu.arch */
|
|
|
|
struct its_vpe {
|
|
|
|
struct page *vpt_page;
|
|
|
|
struct its_vm *its_vm;
|
|
|
|
/* Doorbell interrupt */
|
|
|
|
int irq;
|
|
|
|
irq_hw_number_t vpe_db_lpi;
|
irqchip/gic-v3-its: Add device proxy for VPE management if !DirectLpi
When we don't have the DirectLPI feature, we must work around the
architecture shortcomings to be able to perform the required
maintenance (interrupt masking, clearing and injection).
For this, we create a fake device whose sole purpose is to
provide a way to issue commands as if we were dealing with LPIs
coming from that device (while they actually originate from
the ITS). This fake device doesn't have LPIs allocated to it,
but instead uses the VPE LPIs.
Of course, this could be a real bottleneck, and a naive
implementation would require 6 commands to issue an invalidation.
Instead, let's allocate at least one event per physical CPU
(rounded up to the next power of 2), and opportunistically
map the VPE doorbell to an event. This doorbell will be mapped
until we roll over and need to reallocate this slot.
This ensures that most of the time, we only need 2 commands
to issue an INV, INT or CLEAR, making the performance a lot
better, given that we always issue a CLEAR on entry, and
an INV on each side of a trapped WFI.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2016-12-20 18:23:22 +03:00
|
|
|
/* VPE proxy mapping */
|
|
|
|
int vpe_proxy_event;
|
2016-12-19 22:25:00 +03:00
|
|
|
/*
|
|
|
|
* This collection ID is used to indirect the target
|
|
|
|
* redistributor for this VPE. The ID itself isn't involved in
|
|
|
|
* programming of the ITS.
|
|
|
|
*/
|
|
|
|
u16 col_idx;
|
|
|
|
/* Unique (system-wide) VPE identifier */
|
|
|
|
u16 vpe_id;
|
|
|
|
/* Implementation Defined Area Invalid */
|
|
|
|
bool idai;
|
|
|
|
/* Pending VLPIs on schedule out? */
|
|
|
|
bool pending_last;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* struct its_vlpi_map: structure describing the mapping of a
|
|
|
|
* VLPI. Only to be interpreted in the context of a physical interrupt
|
|
|
|
* it complements. To be used as the vcpu_info passed to
|
|
|
|
* irq_set_vcpu_affinity().
|
|
|
|
*
|
|
|
|
* @vm: Pointer to the GICv4 notion of a VM
|
|
|
|
* @vpe: Pointer to the GICv4 notion of a virtual CPU (VPE)
|
|
|
|
* @vintid: Virtual LPI number
|
2017-10-26 12:44:07 +03:00
|
|
|
* @properties: Priority and enable bits (as written in the prop table)
|
2016-12-19 22:25:00 +03:00
|
|
|
* @db_enabled: Is the VPE doorbell to be generated?
|
|
|
|
*/
|
|
|
|
struct its_vlpi_map {
|
|
|
|
struct its_vm *vm;
|
|
|
|
struct its_vpe *vpe;
|
|
|
|
u32 vintid;
|
2017-10-26 12:44:07 +03:00
|
|
|
u8 properties;
|
2016-12-19 22:25:00 +03:00
|
|
|
bool db_enabled;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum its_vcpu_info_cmd_type {
|
|
|
|
MAP_VLPI,
|
|
|
|
GET_VLPI,
|
|
|
|
PROP_UPDATE_VLPI,
|
|
|
|
PROP_UPDATE_AND_INV_VLPI,
|
|
|
|
SCHEDULE_VPE,
|
|
|
|
DESCHEDULE_VPE,
|
|
|
|
INVALL_VPE,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct its_cmd_info {
|
|
|
|
enum its_vcpu_info_cmd_type cmd_type;
|
|
|
|
union {
|
|
|
|
struct its_vlpi_map *map;
|
|
|
|
u8 config;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2016-12-20 18:27:52 +03:00
|
|
|
int its_alloc_vcpu_irqs(struct its_vm *vm);
|
|
|
|
void its_free_vcpu_irqs(struct its_vm *vm);
|
2016-12-20 18:31:02 +03:00
|
|
|
int its_schedule_vpe(struct its_vpe *vpe, bool on);
|
|
|
|
int its_invall_vpe(struct its_vpe *vpe);
|
2016-12-22 00:50:32 +03:00
|
|
|
int its_map_vlpi(int irq, struct its_vlpi_map *map);
|
|
|
|
int its_get_vlpi(int irq, struct its_vlpi_map *map);
|
|
|
|
int its_unmap_vlpi(int irq);
|
|
|
|
int its_prop_update_vlpi(int irq, u8 config, bool inv);
|
2016-12-20 18:27:52 +03:00
|
|
|
|
2016-12-20 18:31:54 +03:00
|
|
|
int its_init_v4(struct irq_domain *domain, const struct irq_domain_ops *ops);
|
|
|
|
|
2016-12-19 22:25:00 +03:00
|
|
|
#endif
|