Commit 17a21f58 authored by Marc Zyngier's avatar Marc Zyngier

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: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent d6c7f865
...@@ -581,14 +581,45 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 {
collection = find_collection(its, coll_id);
if (!collection) { if (!collection) {
collection = kzalloc(sizeof(struct its_collection), int ret;
GFP_KERNEL);
if (!collection)
return -ENOMEM;
vgic_its_init_collection(its, collection, coll_id); 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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment