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. */ |
