mirror of
https://github.com/torvalds/linux.git
synced 2026-10-14 20:04:03 +02:00
KVM: s390: Enable adapter_indicators_set to use mapped pages
The s390 adapter_indicators_set function can now be optimized to use long-term mapped pages when available so that work can be processed on a fast path when interrupts are disabled. If adapter indicator pages are not mapped then local mapping is done on a slow path as it is prior to this patch. For example, Secure Execution environments will take the local mapping path as it does prior to this patch. Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com> Signed-off-by: Douglas Freimuth <freimuth@linux.ibm.com> Acked-by: Claudio Imbrenda <imbrenda@linux.ibm.com> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com> Message-ID: <20260604192755.203143-3-freimuth@linux.ibm.com>
This commit is contained in:
parent
c9a5688380
commit
1e95e3bc6b
|
|
@ -2892,41 +2892,80 @@ static unsigned long get_ind_bit(__u64 addr, unsigned long bit_nr, bool swap)
|
||||||
return swap ? (bit ^ (BITS_PER_LONG - 1)) : bit;
|
return swap ? (bit ^ (BITS_PER_LONG - 1)) : bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct s390_map_info *get_map_info(struct s390_io_adapter *adapter,
|
||||||
|
u64 addr)
|
||||||
|
{
|
||||||
|
struct s390_map_info *map;
|
||||||
|
|
||||||
|
if (!adapter)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(map, &adapter->maps, list) {
|
||||||
|
if (map->addr == addr)
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int adapter_indicators_set(struct kvm *kvm,
|
static int adapter_indicators_set(struct kvm *kvm,
|
||||||
struct s390_io_adapter *adapter,
|
struct s390_io_adapter *adapter,
|
||||||
struct kvm_s390_adapter_int *adapter_int)
|
struct kvm_s390_adapter_int *adapter_int)
|
||||||
{
|
{
|
||||||
unsigned long bit;
|
unsigned long bit;
|
||||||
int summary_set, idx;
|
int summary_set, idx;
|
||||||
struct page *ind_page, *summary_page;
|
struct s390_map_info *ind_info, *summary_info;
|
||||||
void *map;
|
void *map;
|
||||||
|
struct page *ind_page, *summary_page;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
ind_page = pin_map_page(kvm, adapter_int->ind_addr, 0);
|
ind_page = NULL;
|
||||||
if (!ind_page)
|
|
||||||
return -1;
|
spin_lock_irqsave(&adapter->maps_lock, flags);
|
||||||
summary_page = pin_map_page(kvm, adapter_int->summary_addr, 0);
|
ind_info = get_map_info(adapter, adapter_int->ind_addr);
|
||||||
if (!summary_page) {
|
if (!ind_info) {
|
||||||
|
spin_unlock_irqrestore(&adapter->maps_lock, flags);
|
||||||
|
ind_page = pin_map_page(kvm, adapter_int->ind_addr, 0);
|
||||||
|
if (!ind_page)
|
||||||
|
return -1;
|
||||||
|
idx = srcu_read_lock(&kvm->srcu);
|
||||||
|
map = page_address(ind_page);
|
||||||
|
bit = get_ind_bit(adapter_int->ind_addr,
|
||||||
|
adapter_int->ind_offset, adapter->swap);
|
||||||
|
set_bit(bit, map);
|
||||||
|
mark_page_dirty(kvm, adapter_int->ind_gaddr >> PAGE_SHIFT);
|
||||||
|
set_page_dirty_lock(ind_page);
|
||||||
|
srcu_read_unlock(&kvm->srcu, idx);
|
||||||
unpin_user_page(ind_page);
|
unpin_user_page(ind_page);
|
||||||
return -1;
|
} else {
|
||||||
|
map = page_address(ind_info->page);
|
||||||
|
bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
|
||||||
|
set_bit(bit, map);
|
||||||
|
spin_unlock_irqrestore(&adapter->maps_lock, flags);
|
||||||
|
}
|
||||||
|
spin_lock_irqsave(&adapter->maps_lock, flags);
|
||||||
|
summary_info = get_map_info(adapter, adapter_int->summary_addr);
|
||||||
|
if (!summary_info) {
|
||||||
|
spin_unlock_irqrestore(&adapter->maps_lock, flags);
|
||||||
|
summary_page = pin_map_page(kvm, adapter_int->summary_addr, 0);
|
||||||
|
if (WARN_ON_ONCE(!summary_page))
|
||||||
|
return -1;
|
||||||
|
idx = srcu_read_lock(&kvm->srcu);
|
||||||
|
map = page_address(summary_page);
|
||||||
|
bit = get_ind_bit(adapter_int->summary_addr,
|
||||||
|
adapter_int->summary_offset, adapter->swap);
|
||||||
|
summary_set = test_and_set_bit(bit, map);
|
||||||
|
mark_page_dirty(kvm, adapter_int->summary_gaddr >> PAGE_SHIFT);
|
||||||
|
set_page_dirty_lock(summary_page);
|
||||||
|
srcu_read_unlock(&kvm->srcu, idx);
|
||||||
|
unpin_user_page(summary_page);
|
||||||
|
} else {
|
||||||
|
map = page_address(summary_info->page);
|
||||||
|
bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
|
||||||
|
adapter->swap);
|
||||||
|
summary_set = test_and_set_bit(bit, map);
|
||||||
|
spin_unlock_irqrestore(&adapter->maps_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
idx = srcu_read_lock(&kvm->srcu);
|
|
||||||
map = page_address(ind_page);
|
|
||||||
bit = get_ind_bit(adapter_int->ind_addr,
|
|
||||||
adapter_int->ind_offset, adapter->swap);
|
|
||||||
set_bit(bit, map);
|
|
||||||
mark_page_dirty(kvm, adapter_int->ind_gaddr >> PAGE_SHIFT);
|
|
||||||
set_page_dirty_lock(ind_page);
|
|
||||||
map = page_address(summary_page);
|
|
||||||
bit = get_ind_bit(adapter_int->summary_addr,
|
|
||||||
adapter_int->summary_offset, adapter->swap);
|
|
||||||
summary_set = test_and_set_bit(bit, map);
|
|
||||||
mark_page_dirty(kvm, adapter_int->summary_gaddr >> PAGE_SHIFT);
|
|
||||||
set_page_dirty_lock(summary_page);
|
|
||||||
srcu_read_unlock(&kvm->srcu, idx);
|
|
||||||
|
|
||||||
unpin_user_page(ind_page);
|
|
||||||
unpin_user_page(summary_page);
|
|
||||||
return summary_set ? 0 : 1;
|
return summary_set ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user