diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2016-07-17 15:01:46 -0400 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2016-07-18 13:15:18 -0400 |
commit | 17a21f58ff3e60fef3df788561b65e576a0b494d (patch) | |
tree | ee028f95d99b2e0f307cd06e7526f0bcbca13658 | |
parent | d6c7f865f00adf98ca79712167fb0f1b9dccb272 (diff) |
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>
-rw-r--r-- | virt/kvm/arm/vgic/vgic-its.c | 92 |
1 files changed, 54 insertions, 38 deletions
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index 2faf1f458e8a..d6f68e9c946d 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c | |||
@@ -581,14 +581,45 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its, | |||
581 | return 0; | 581 | return 0; |
582 | } | 582 | } |
583 | 583 | ||
584 | static void vgic_its_init_collection(struct vgic_its *its, | 584 | static int vgic_its_alloc_collection(struct vgic_its *its, |
585 | struct its_collection *collection, | 585 | struct its_collection **colp, |
586 | u32 coll_id) | 586 | u32 coll_id) |
587 | { | 587 | { |
588 | struct its_collection *collection; | ||
589 | |||
590 | collection = kzalloc(sizeof(*collection), GFP_KERNEL); | ||
591 | |||
588 | collection->collection_id = coll_id; | 592 | collection->collection_id = coll_id; |
589 | collection->target_addr = COLLECTION_NOT_MAPPED; | 593 | collection->target_addr = COLLECTION_NOT_MAPPED; |
590 | 594 | ||
591 | list_add_tail(&collection->coll_list, &its->collection_list); | 595 | list_add_tail(&collection->coll_list, &its->collection_list); |
596 | *colp = collection; | ||
597 | |||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id) | ||
602 | { | ||
603 | struct its_collection *collection; | ||
604 | struct its_device *device; | ||
605 | struct its_itte *itte; | ||
606 | |||
607 | /* | ||
608 | * Clearing the mapping for that collection ID removes the | ||
609 | * entry from the list. If there wasn't any before, we can | ||
610 | * go home early. | ||
611 | */ | ||
612 | collection = find_collection(its, coll_id); | ||
613 | if (!collection) | ||
614 | return; | ||
615 | |||
616 | for_each_lpi_its(device, itte, its) | ||
617 | if (itte->collection && | ||
618 | itte->collection->collection_id == coll_id) | ||
619 | itte->collection = NULL; | ||
620 | |||
621 | list_del(&collection->coll_list); | ||
622 | kfree(collection); | ||
592 | } | 623 | } |
593 | 624 | ||
594 | /* | 625 | /* |
@@ -605,6 +636,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its, | |||
605 | struct its_device *device; | 636 | struct its_device *device; |
606 | struct its_collection *collection, *new_coll = NULL; | 637 | struct its_collection *collection, *new_coll = NULL; |
607 | int lpi_nr; | 638 | int lpi_nr; |
639 | int ret; | ||
608 | 640 | ||
609 | device = find_its_device(its, device_id); | 641 | device = find_its_device(its, device_id); |
610 | if (!device) | 642 | if (!device) |
@@ -612,9 +644,10 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its, | |||
612 | 644 | ||
613 | collection = find_collection(its, coll_id); | 645 | collection = find_collection(its, coll_id); |
614 | if (!collection) { | 646 | if (!collection) { |
615 | new_coll = kzalloc(sizeof(struct its_collection), GFP_KERNEL); | 647 | ret = vgic_its_alloc_collection(its, &collection, coll_id); |
616 | if (!new_coll) | 648 | if (ret) |
617 | return -ENOMEM; | 649 | return ret; |
650 | new_coll = collection; | ||
618 | } | 651 | } |
619 | 652 | ||
620 | if (subcmd == GITS_CMD_MAPTI) | 653 | if (subcmd == GITS_CMD_MAPTI) |
@@ -623,27 +656,22 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its, | |||
623 | lpi_nr = event_id; | 656 | lpi_nr = event_id; |
624 | if (lpi_nr < GIC_LPI_OFFSET || | 657 | if (lpi_nr < GIC_LPI_OFFSET || |
625 | lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser)) { | 658 | lpi_nr >= max_lpis_propbaser(kvm->arch.vgic.propbaser)) { |
626 | kfree(new_coll); | 659 | ret = E_ITS_MAPTI_PHYSICALID_OOR; |
627 | return E_ITS_MAPTI_PHYSICALID_OOR; | 660 | goto err; |
628 | } | 661 | } |
629 | 662 | ||
630 | itte = find_itte(its, device_id, event_id); | 663 | itte = find_itte(its, device_id, event_id); |
631 | if (!itte) { | 664 | if (!itte) { |
632 | itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL); | 665 | itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL); |
633 | if (!itte) { | 666 | if (!itte) { |
634 | kfree(new_coll); | 667 | ret = -ENOMEM; |
635 | return -ENOMEM; | 668 | goto err; |
636 | } | 669 | } |
637 | 670 | ||
638 | itte->event_id = event_id; | 671 | itte->event_id = event_id; |
639 | list_add_tail(&itte->itte_list, &device->itt_head); | 672 | list_add_tail(&itte->itte_list, &device->itt_head); |
640 | } | 673 | } |
641 | 674 | ||
642 | if (!collection) { | ||
643 | collection = new_coll; | ||
644 | vgic_its_init_collection(its, collection, coll_id); | ||
645 | } | ||
646 | |||
647 | itte->collection = collection; | 675 | itte->collection = collection; |
648 | itte->lpi = lpi_nr; | 676 | itte->lpi = lpi_nr; |
649 | itte->irq = vgic_add_lpi(kvm, lpi_nr); | 677 | 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 | update_lpi_config(kvm, itte->irq, NULL); | 685 | update_lpi_config(kvm, itte->irq, NULL); |
658 | 686 | ||
659 | return 0; | 687 | return 0; |
688 | err: | ||
689 | if (new_coll) | ||
690 | vgic_its_free_collection(its, coll_id); | ||
691 | return ret; | ||
660 | } | 692 | } |
661 | 693 | ||
662 | /* Requires the its_lock to be held. */ | 694 | /* 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 | if (coll_id >= vgic_its_nr_collection_ids(its)) | 841 | if (coll_id >= vgic_its_nr_collection_ids(its)) |
810 | return E_ITS_MAPC_COLLECTION_OOR; | 842 | return E_ITS_MAPC_COLLECTION_OOR; |
811 | 843 | ||
812 | collection = find_collection(its, coll_id); | ||
813 | |||
814 | if (!valid) { | 844 | if (!valid) { |
815 | struct its_device *device; | 845 | vgic_its_free_collection(its, coll_id); |
816 | struct its_itte *itte; | ||
817 | /* | ||
818 | * Clearing the mapping for that collection ID removes the | ||
819 | * entry from the list. If there wasn't any before, we can | ||
820 | * go home early. | ||
821 | */ | ||
822 | if (!collection) | ||
823 | return 0; | ||
824 | |||
825 | for_each_lpi_its(device, itte, its) | ||
826 | if (itte->collection && | ||
827 | itte->collection->collection_id == coll_id) | ||
828 | itte->collection = NULL; | ||
829 | |||
830 | list_del(&collection->coll_list); | ||
831 | kfree(collection); | ||
832 | } else { | 846 | } else { |
847 | collection = find_collection(its, coll_id); | ||
848 | |||
833 | if (!collection) { | 849 | if (!collection) { |
834 | collection = kzalloc(sizeof(struct its_collection), | 850 | int ret; |
835 | GFP_KERNEL); | ||
836 | if (!collection) | ||
837 | return -ENOMEM; | ||
838 | 851 | ||
839 | vgic_its_init_collection(its, collection, coll_id); | 852 | ret = vgic_its_alloc_collection(its, &collection, |
853 | coll_id); | ||
854 | if (ret) | ||
855 | return ret; | ||
840 | collection->target_addr = target_addr; | 856 | collection->target_addr = target_addr; |
841 | } else { | 857 | } else { |
842 | collection->target_addr = target_addr; | 858 | collection->target_addr = target_addr; |