diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2013-07-03 10:30:53 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2013-07-18 06:29:23 -0400 |
commit | 126a5af520eff9b99a0bb1ca4bb4a0b7973f7d5a (patch) | |
tree | 74084d4e3bb3526c132f58b0ca8b9c98065452b9 /virt | |
parent | 1c118b8226922d225a7df4127926ed2a2d73baaf (diff) |
KVM: kvm-io: support cookies
Add new functions kvm_io_bus_{read,write}_cookie() that allows users of
the kvm io infrastructure to use a cookie value to speed up lookup of a
device on an io bus.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/kvm_main.c | 108 |
1 files changed, 92 insertions, 16 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 1580dd4ace4e..71960fb03c2a 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -2863,13 +2863,33 @@ static int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus, | |||
2863 | return off; | 2863 | return off; |
2864 | } | 2864 | } |
2865 | 2865 | ||
2866 | static int __kvm_io_bus_write(struct kvm_io_bus *bus, | ||
2867 | struct kvm_io_range *range, const void *val) | ||
2868 | { | ||
2869 | int idx; | ||
2870 | |||
2871 | idx = kvm_io_bus_get_first_dev(bus, range->addr, range->len); | ||
2872 | if (idx < 0) | ||
2873 | return -EOPNOTSUPP; | ||
2874 | |||
2875 | while (idx < bus->dev_count && | ||
2876 | kvm_io_bus_sort_cmp(range, &bus->range[idx]) == 0) { | ||
2877 | if (!kvm_iodevice_write(bus->range[idx].dev, range->addr, | ||
2878 | range->len, val)) | ||
2879 | return idx; | ||
2880 | idx++; | ||
2881 | } | ||
2882 | |||
2883 | return -EOPNOTSUPP; | ||
2884 | } | ||
2885 | |||
2866 | /* kvm_io_bus_write - called under kvm->slots_lock */ | 2886 | /* kvm_io_bus_write - called under kvm->slots_lock */ |
2867 | int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | 2887 | int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, |
2868 | int len, const void *val) | 2888 | int len, const void *val) |
2869 | { | 2889 | { |
2870 | int idx; | ||
2871 | struct kvm_io_bus *bus; | 2890 | struct kvm_io_bus *bus; |
2872 | struct kvm_io_range range; | 2891 | struct kvm_io_range range; |
2892 | int r; | ||
2873 | 2893 | ||
2874 | range = (struct kvm_io_range) { | 2894 | range = (struct kvm_io_range) { |
2875 | .addr = addr, | 2895 | .addr = addr, |
@@ -2877,14 +2897,52 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | |||
2877 | }; | 2897 | }; |
2878 | 2898 | ||
2879 | bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); | 2899 | bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); |
2880 | idx = kvm_io_bus_get_first_dev(bus, addr, len); | 2900 | r = __kvm_io_bus_write(bus, &range, val); |
2901 | return r < 0 ? r : 0; | ||
2902 | } | ||
2903 | |||
2904 | /* kvm_io_bus_write_cookie - called under kvm->slots_lock */ | ||
2905 | int kvm_io_bus_write_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | ||
2906 | int len, const void *val, long cookie) | ||
2907 | { | ||
2908 | struct kvm_io_bus *bus; | ||
2909 | struct kvm_io_range range; | ||
2910 | |||
2911 | range = (struct kvm_io_range) { | ||
2912 | .addr = addr, | ||
2913 | .len = len, | ||
2914 | }; | ||
2915 | |||
2916 | bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); | ||
2917 | |||
2918 | /* First try the device referenced by cookie. */ | ||
2919 | if ((cookie >= 0) && (cookie < bus->dev_count) && | ||
2920 | (kvm_io_bus_sort_cmp(&range, &bus->range[cookie]) == 0)) | ||
2921 | if (!kvm_iodevice_write(bus->range[cookie].dev, addr, len, | ||
2922 | val)) | ||
2923 | return cookie; | ||
2924 | |||
2925 | /* | ||
2926 | * cookie contained garbage; fall back to search and return the | ||
2927 | * correct cookie value. | ||
2928 | */ | ||
2929 | return __kvm_io_bus_write(bus, &range, val); | ||
2930 | } | ||
2931 | |||
2932 | static int __kvm_io_bus_read(struct kvm_io_bus *bus, struct kvm_io_range *range, | ||
2933 | void *val) | ||
2934 | { | ||
2935 | int idx; | ||
2936 | |||
2937 | idx = kvm_io_bus_get_first_dev(bus, range->addr, range->len); | ||
2881 | if (idx < 0) | 2938 | if (idx < 0) |
2882 | return -EOPNOTSUPP; | 2939 | return -EOPNOTSUPP; |
2883 | 2940 | ||
2884 | while (idx < bus->dev_count && | 2941 | while (idx < bus->dev_count && |
2885 | kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) { | 2942 | kvm_io_bus_sort_cmp(range, &bus->range[idx]) == 0) { |
2886 | if (!kvm_iodevice_write(bus->range[idx].dev, addr, len, val)) | 2943 | if (!kvm_iodevice_read(bus->range[idx].dev, range->addr, |
2887 | return 0; | 2944 | range->len, val)) |
2945 | return idx; | ||
2888 | idx++; | 2946 | idx++; |
2889 | } | 2947 | } |
2890 | 2948 | ||
@@ -2895,9 +2953,9 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | |||
2895 | int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | 2953 | int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, |
2896 | int len, void *val) | 2954 | int len, void *val) |
2897 | { | 2955 | { |
2898 | int idx; | ||
2899 | struct kvm_io_bus *bus; | 2956 | struct kvm_io_bus *bus; |
2900 | struct kvm_io_range range; | 2957 | struct kvm_io_range range; |
2958 | int r; | ||
2901 | 2959 | ||
2902 | range = (struct kvm_io_range) { | 2960 | range = (struct kvm_io_range) { |
2903 | .addr = addr, | 2961 | .addr = addr, |
@@ -2905,18 +2963,36 @@ int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | |||
2905 | }; | 2963 | }; |
2906 | 2964 | ||
2907 | bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); | 2965 | bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); |
2908 | idx = kvm_io_bus_get_first_dev(bus, addr, len); | 2966 | r = __kvm_io_bus_read(bus, &range, val); |
2909 | if (idx < 0) | 2967 | return r < 0 ? r : 0; |
2910 | return -EOPNOTSUPP; | 2968 | } |
2911 | 2969 | ||
2912 | while (idx < bus->dev_count && | 2970 | /* kvm_io_bus_read_cookie - called under kvm->slots_lock */ |
2913 | kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) { | 2971 | int kvm_io_bus_read_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, |
2914 | if (!kvm_iodevice_read(bus->range[idx].dev, addr, len, val)) | 2972 | int len, void *val, long cookie) |
2915 | return 0; | 2973 | { |
2916 | idx++; | 2974 | struct kvm_io_bus *bus; |
2917 | } | 2975 | struct kvm_io_range range; |
2918 | 2976 | ||
2919 | return -EOPNOTSUPP; | 2977 | range = (struct kvm_io_range) { |
2978 | .addr = addr, | ||
2979 | .len = len, | ||
2980 | }; | ||
2981 | |||
2982 | bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); | ||
2983 | |||
2984 | /* First try the device referenced by cookie. */ | ||
2985 | if ((cookie >= 0) && (cookie < bus->dev_count) && | ||
2986 | (kvm_io_bus_sort_cmp(&range, &bus->range[cookie]) == 0)) | ||
2987 | if (!kvm_iodevice_read(bus->range[cookie].dev, addr, len, | ||
2988 | val)) | ||
2989 | return cookie; | ||
2990 | |||
2991 | /* | ||
2992 | * cookie contained garbage; fall back to search and return the | ||
2993 | * correct cookie value. | ||
2994 | */ | ||
2995 | return __kvm_io_bus_read(bus, &range, val); | ||
2920 | } | 2996 | } |
2921 | 2997 | ||
2922 | /* Caller must hold slots_lock. */ | 2998 | /* Caller must hold slots_lock. */ |