KVM: arm64: vgic-its: Add collection allocator/destructor
Instead of spreading random allocations all over the place, consolidate allocation/init/freeing of collections in a pair of constructor/destructor. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
This commit is contained in:
parent
d6c7f865f0
commit
17a21f58ff
@ -581,14 +581,45 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vgic_its_init_collection(struct vgic_its *its,
|
static int vgic_its_alloc_collection(struct vgic_its *its,
|
||||||
struct its_collection *collection,
|
struct its_collection **colp,
|
||||||
u32 coll_id)
|
u32 coll_id)
|
||||||
{
|
{
|
||||||
|
struct its_collection *collection;
|
||||||
|
|
||||||
|
collection = kzalloc(sizeof(*collection), GFP_KERNEL);
|
||||||
|
|
||||||
collection->collection_id = coll_id;
|
collection->collection_id = coll_id;
|
||||||
collection->target_addr = COLLECTION_NOT_MAPPED;
|
collection->target_addr = COLLECTION_NOT_MAPPED;
|
||||||
|
|
||||||
list_add_tail(&collection->coll_list, &its->collection_list);
|
list_add_tail(&collection->coll_list, &its->collection_list);
|
||||||
|
*colp = collection;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
|
||||||
|
{
|
||||||
|
struct its_collection *collection;
|
||||||
|
struct its_device *device;
|
||||||
|
struct its_itte *itte;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clearing the mapping for that collection ID removes the
|
||||||
|
* entry from the list. If there wasn't any before, we can
|
||||||
|
* go home early.
|
||||||
|
*/
|
||||||
|
collection = find_collection(its, coll_id);
|
||||||
|
if (!collection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for_each_lpi_its(device, itte, its)
|
||||||
|
if (itte->collection &&
|
||||||
|
itte->collection->collection_id == coll_id)
|
||||||
|
itte->collection = NULL;
|
||||||
|
|
||||||
|
list_del(&collection->coll_list);
|
||||||
|
kfree(collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -605,6 +636,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
|
|||||||
struct its_device *device;
|
struct its_device *device;
|
||||||
struct its_collection *collection, *new_coll = NULL;
|
struct its_collection *collection, *new_coll = NULL;
|
||||||
int lpi_nr;
|
int lpi_nr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
device = find_its_device(its, device_id);
|
device = find_its_device(its, device_id);
|
||||||
if (!device)
|
if (!device)
|
||||||
@ -612,9 +644,10 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
|
|||||||
|
|
||||||
collection = find_collection(its, coll_id);
|
collection = find_collection(its, coll_id);
|
||||||
if (!collection) {
|
if (!collection) {
|
||||||
new_coll = kzalloc(sizeof(struct its_collection), GFP_KERNEL);
|
ret = vgic_its_alloc_collection(its, &collection, coll_id);
|
||||||
if (!new_coll)
|
if (ret)
|
||||||
return -ENOMEM;
|
return ret;
|
||||||
|
new_coll = collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subcmd == GITS_CMD_MAPTI)
|
if (subcmd == GITS_CMD_MAPTI)
|
||||||
@ -623,27 +656,22 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
|
|||||||
lpi_nr = event_id;
|
lpi_nr = event_id;
|
||||||
if (lpi_nr < GIC_LPI_OFFSET ||
|
if (lpi_nr < GIC_LPI_OFFSET ||
|
||||||
lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser)) {
|
lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser)) {
|
||||||
kfree(new_coll);
|
ret = E_ITS_MAPTI_PHYSICALID_OOR;
|
||||||
return E_ITS_MAPTI_PHYSICALID_OOR;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
itte = find_itte(its, device_id, event_id);
|
itte = find_itte(its, device_id, event_id);
|
||||||
if (!itte) {
|
if (!itte) {
|
||||||
itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
|
itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
|
||||||
if (!itte) {
|
if (!itte) {
|
||||||
kfree(new_coll);
|
ret = -ENOMEM;
|
||||||
return -ENOMEM;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
itte->event_id = event_id;
|
itte->event_id = event_id;
|
||||||
list_add_tail(&itte->itte_list, &device->itt_head);
|
list_add_tail(&itte->itte_list, &device->itt_head);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!collection) {
|
|
||||||
collection = new_coll;
|
|
||||||
vgic_its_init_collection(its, collection, coll_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
itte->collection = collection;
|
itte->collection = collection;
|
||||||
itte->lpi = lpi_nr;
|
itte->lpi = lpi_nr;
|
||||||
itte->irq = vgic_add_lpi(kvm, lpi_nr);
|
itte->irq = vgic_add_lpi(kvm, lpi_nr);
|
||||||
@ -657,6 +685,10 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
|
|||||||
update_lpi_config(kvm, itte->irq, NULL);
|
update_lpi_config(kvm, itte->irq, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
err:
|
||||||
|
if (new_coll)
|
||||||
|
vgic_its_free_collection(its, coll_id);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Requires the its_lock to be held. */
|
/* Requires the its_lock to be held. */
|
||||||
@ -809,34 +841,18 @@ static int vgic_its_cmd_handle_mapc(struct kvm *kvm, struct vgic_its *its,
|
|||||||
if (coll_id >= vgic_its_nr_collection_ids(its))
|
if (coll_id >= vgic_its_nr_collection_ids(its))
|
||||||
return E_ITS_MAPC_COLLECTION_OOR;
|
return E_ITS_MAPC_COLLECTION_OOR;
|
||||||
|
|
||||||
collection = find_collection(its, coll_id);
|
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
struct its_device *device;
|
vgic_its_free_collection(its, coll_id);
|
||||||
struct its_itte *itte;
|
|
||||||
/*
|
|
||||||
* Clearing the mapping for that collection ID removes the
|
|
||||||
* entry from the list. If there wasn't any before, we can
|
|
||||||
* go home early.
|
|
||||||
*/
|
|
||||||
if (!collection)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for_each_lpi_its(device, itte, its)
|
|
||||||
if (itte->collection &&
|
|
||||||
itte->collection->collection_id == coll_id)
|
|
||||||
itte->collection = NULL;
|
|
||||||
|
|
||||||
list_del(&collection->coll_list);
|
|
||||||
kfree(collection);
|
|
||||||
} else {
|
} else {
|
||||||
if (!collection) {
|
collection = find_collection(its, coll_id);
|
||||||
collection = kzalloc(sizeof(struct its_collection),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!collection)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
vgic_its_init_collection(its, collection, coll_id);
|
if (!collection) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = vgic_its_alloc_collection(its, &collection,
|
||||||
|
coll_id);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
collection->target_addr = target_addr;
|
collection->target_addr = target_addr;
|
||||||
} else {
|
} else {
|
||||||
collection->target_addr = target_addr;
|
collection->target_addr = target_addr;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user