aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kvm
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2016-01-21 13:27:04 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2016-02-29 13:34:22 -0500
commit623eefa8d04c6c3df69a0630989f10b3762b3b00 (patch)
treeca9bfd8f2c0308ef434df7674194eff0f578b6e0 /arch/arm64/kvm
parentbb0c70bcca6ba3c84afc2da7426f3b923bbe6825 (diff)
arm64: KVM: Switch the sys_reg search to be a binary search
Our 64bit sys_reg table is about 90 entries long (so far, and the PMU support is likely to increase this). This means that on average, it takes 45 comparaisons to find the right entry (and actually the full 90 if we have to search the invariant table). Not the most efficient thing. Specially when you think that this table is already sorted. Switching to a binary search effectively reduces the search to about 7 comparaisons. Slightly better! As an added bonus, the comparison is done by comparing all the fields at once, instead of one at a time. Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm64/kvm')
-rw-r--r--arch/arm64/kvm/sys_regs.c40
1 files changed, 22 insertions, 18 deletions
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index fe15c2310a65..61ba59104845 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -20,6 +20,7 @@
20 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */ 21 */
22 22
23#include <linux/bsearch.h>
23#include <linux/kvm_host.h> 24#include <linux/kvm_host.h>
24#include <linux/mm.h> 25#include <linux/mm.h>
25#include <linux/uaccess.h> 26#include <linux/uaccess.h>
@@ -1453,29 +1454,32 @@ static const struct sys_reg_desc *get_target_table(unsigned target,
1453 } 1454 }
1454} 1455}
1455 1456
1457#define reg_to_match_value(x) \
1458 ({ \
1459 unsigned long val; \
1460 val = (x)->Op0 << 14; \
1461 val |= (x)->Op1 << 11; \
1462 val |= (x)->CRn << 7; \
1463 val |= (x)->CRm << 3; \
1464 val |= (x)->Op2; \
1465 val; \
1466 })
1467
1468static int match_sys_reg(const void *key, const void *elt)
1469{
1470 const unsigned long pval = (unsigned long)key;
1471 const struct sys_reg_desc *r = elt;
1472
1473 return pval - reg_to_match_value(r);
1474}
1475
1456static const struct sys_reg_desc *find_reg(const struct sys_reg_params *params, 1476static const struct sys_reg_desc *find_reg(const struct sys_reg_params *params,
1457 const struct sys_reg_desc table[], 1477 const struct sys_reg_desc table[],
1458 unsigned int num) 1478 unsigned int num)
1459{ 1479{
1460 unsigned int i; 1480 unsigned long pval = reg_to_match_value(params);
1461
1462 for (i = 0; i < num; i++) {
1463 const struct sys_reg_desc *r = &table[i];
1464 1481
1465 if (params->Op0 != r->Op0) 1482 return bsearch((void *)pval, table, num, sizeof(table[0]), match_sys_reg);
1466 continue;
1467 if (params->Op1 != r->Op1)
1468 continue;
1469 if (params->CRn != r->CRn)
1470 continue;
1471 if (params->CRm != r->CRm)
1472 continue;
1473 if (params->Op2 != r->Op2)
1474 continue;
1475
1476 return r;
1477 }
1478 return NULL;
1479} 1483}
1480 1484
1481int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run) 1485int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)