mirror of
https://gitee.com/open-loongarch/linux-5.10.git
synced 2026-10-27 21:47:12 +08:00
574 lines
18 KiB
C
574 lines
18 KiB
C
/*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
* Copyright (C) 2020 Loongson Technology Corporation Limited
|
|
*
|
|
* Author: Chong Qiao <qiaochong@loongson.cn>
|
|
*/
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <asm/processor.h>
|
|
#include <asm/watch.h>
|
|
#include <asm/ptrace.h>
|
|
#include <linux/sched/task_stack.h>
|
|
|
|
unsigned long watch_csrrd(unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 0:
|
|
return csr_readq(LOONGARCH_CSR_IB0ADDR + 8 * 0);
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 1:
|
|
return csr_readq(LOONGARCH_CSR_IB0ADDR + 8 * 1);
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 2:
|
|
return csr_readq(LOONGARCH_CSR_IB0ADDR + 8 * 2);
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 3:
|
|
return csr_readq(LOONGARCH_CSR_IB0ADDR + 8 * 3);
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 4:
|
|
return csr_readq(LOONGARCH_CSR_IB0ADDR + 8 * 4);
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 5:
|
|
return csr_readq(LOONGARCH_CSR_IB0ADDR + 8 * 5);
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 6:
|
|
return csr_readq(LOONGARCH_CSR_IB0ADDR + 8 * 6);
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 7:
|
|
return csr_readq(LOONGARCH_CSR_IB0ADDR + 8 * 7);
|
|
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 0:
|
|
return csr_readq(LOONGARCH_CSR_IB0MASK + 8 * 0);
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 1:
|
|
return csr_readq(LOONGARCH_CSR_IB0MASK + 8 * 1);
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 2:
|
|
return csr_readq(LOONGARCH_CSR_IB0MASK + 8 * 2);
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 3:
|
|
return csr_readq(LOONGARCH_CSR_IB0MASK + 8 * 3);
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 4:
|
|
return csr_readq(LOONGARCH_CSR_IB0MASK + 8 * 4);
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 5:
|
|
return csr_readq(LOONGARCH_CSR_IB0MASK + 8 * 5);
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 6:
|
|
return csr_readq(LOONGARCH_CSR_IB0MASK + 8 * 6);
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 7:
|
|
return csr_readq(LOONGARCH_CSR_IB0MASK + 8 * 7);
|
|
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 0:
|
|
return csr_readq(LOONGARCH_CSR_IB0ASID + 8 * 0);
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 1:
|
|
return csr_readq(LOONGARCH_CSR_IB0ASID + 8 * 1);
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 2:
|
|
return csr_readq(LOONGARCH_CSR_IB0ASID + 8 * 2);
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 3:
|
|
return csr_readq(LOONGARCH_CSR_IB0ASID + 8 * 3);
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 4:
|
|
return csr_readq(LOONGARCH_CSR_IB0ASID + 8 * 4);
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 5:
|
|
return csr_readq(LOONGARCH_CSR_IB0ASID + 8 * 5);
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 6:
|
|
return csr_readq(LOONGARCH_CSR_IB0ASID + 8 * 6);
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 7:
|
|
return csr_readq(LOONGARCH_CSR_IB0ASID + 8 * 7);
|
|
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 0:
|
|
return csr_readq(LOONGARCH_CSR_IB0CTL + 8 * 0);
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 1:
|
|
return csr_readq(LOONGARCH_CSR_IB0CTL + 8 * 1);
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 2:
|
|
return csr_readq(LOONGARCH_CSR_IB0CTL + 8 * 2);
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 3:
|
|
return csr_readq(LOONGARCH_CSR_IB0CTL + 8 * 3);
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 4:
|
|
return csr_readq(LOONGARCH_CSR_IB0CTL + 8 * 4);
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 5:
|
|
return csr_readq(LOONGARCH_CSR_IB0CTL + 8 * 5);
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 6:
|
|
return csr_readq(LOONGARCH_CSR_IB0CTL + 8 * 6);
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 7:
|
|
return csr_readq(LOONGARCH_CSR_IB0CTL + 8 * 7);
|
|
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 0:
|
|
return csr_readq(LOONGARCH_CSR_DB0ADDR + 8 * 0);
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 1:
|
|
return csr_readq(LOONGARCH_CSR_DB0ADDR + 8 * 1);
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 2:
|
|
return csr_readq(LOONGARCH_CSR_DB0ADDR + 8 * 2);
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 3:
|
|
return csr_readq(LOONGARCH_CSR_DB0ADDR + 8 * 3);
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 4:
|
|
return csr_readq(LOONGARCH_CSR_DB0ADDR + 8 * 4);
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 5:
|
|
return csr_readq(LOONGARCH_CSR_DB0ADDR + 8 * 5);
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 6:
|
|
return csr_readq(LOONGARCH_CSR_DB0ADDR + 8 * 6);
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 7:
|
|
return csr_readq(LOONGARCH_CSR_DB0ADDR + 8 * 7);
|
|
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 0:
|
|
return csr_readq(LOONGARCH_CSR_DB0MASK + 8 * 0);
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 1:
|
|
return csr_readq(LOONGARCH_CSR_DB0MASK + 8 * 1);
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 2:
|
|
return csr_readq(LOONGARCH_CSR_DB0MASK + 8 * 2);
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 3:
|
|
return csr_readq(LOONGARCH_CSR_DB0MASK + 8 * 3);
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 4:
|
|
return csr_readq(LOONGARCH_CSR_DB0MASK + 8 * 4);
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 5:
|
|
return csr_readq(LOONGARCH_CSR_DB0MASK + 8 * 5);
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 6:
|
|
return csr_readq(LOONGARCH_CSR_DB0MASK + 8 * 6);
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 7:
|
|
return csr_readq(LOONGARCH_CSR_DB0MASK + 8 * 7);
|
|
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 0:
|
|
return csr_readq(LOONGARCH_CSR_DB0ASID + 8 * 0);
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 1:
|
|
return csr_readq(LOONGARCH_CSR_DB0ASID + 8 * 1);
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 2:
|
|
return csr_readq(LOONGARCH_CSR_DB0ASID + 8 * 2);
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 3:
|
|
return csr_readq(LOONGARCH_CSR_DB0ASID + 8 * 3);
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 4:
|
|
return csr_readq(LOONGARCH_CSR_DB0ASID + 8 * 4);
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 5:
|
|
return csr_readq(LOONGARCH_CSR_DB0ASID + 8 * 5);
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 6:
|
|
return csr_readq(LOONGARCH_CSR_DB0ASID + 8 * 6);
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 7:
|
|
return csr_readq(LOONGARCH_CSR_DB0ASID + 8 * 7);
|
|
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 0:
|
|
return csr_readq(LOONGARCH_CSR_DB0CTL + 8 * 0);
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 1:
|
|
return csr_readq(LOONGARCH_CSR_DB0CTL + 8 * 1);
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 2:
|
|
return csr_readq(LOONGARCH_CSR_DB0CTL + 8 * 2);
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 3:
|
|
return csr_readq(LOONGARCH_CSR_DB0CTL + 8 * 3);
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 4:
|
|
return csr_readq(LOONGARCH_CSR_DB0CTL + 8 * 4);
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 5:
|
|
return csr_readq(LOONGARCH_CSR_DB0CTL + 8 * 5);
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 6:
|
|
return csr_readq(LOONGARCH_CSR_DB0CTL + 8 * 6);
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 7:
|
|
return csr_readq(LOONGARCH_CSR_DB0CTL + 8 * 7);
|
|
|
|
case LOONGARCH_CSR_FWPS:
|
|
return csr_readq(LOONGARCH_CSR_FWPS);
|
|
case LOONGARCH_CSR_MWPS:
|
|
return csr_readq(LOONGARCH_CSR_MWPS);
|
|
case LOONGARCH_CSR_FWPC:
|
|
return csr_readq(LOONGARCH_CSR_FWPC);
|
|
case LOONGARCH_CSR_MWPC:
|
|
return csr_readq(LOONGARCH_CSR_MWPC);
|
|
default:
|
|
printk("read watch register number error %d\n", reg);
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(watch_csrrd);
|
|
|
|
void watch_csrwr(unsigned long val, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 0:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ADDR + 8 * 0);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 1:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ADDR + 8 * 1);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 2:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ADDR + 8 * 2);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 3:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ADDR + 8 * 3);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 4:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ADDR + 8 * 4);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 5:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ADDR + 8 * 5);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 6:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ADDR + 8 * 6);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ADDR + 8 * 7:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ADDR + 8 * 7);
|
|
break;
|
|
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 0:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0MASK + 8 * 0);
|
|
break;
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 1:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0MASK + 8 * 1);
|
|
break;
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 2:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0MASK + 8 * 2);
|
|
break;
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 3:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0MASK + 8 * 3);
|
|
break;
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 4:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0MASK + 8 * 4);
|
|
break;
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 5:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0MASK + 8 * 5);
|
|
break;
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 6:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0MASK + 8 * 6);
|
|
break;
|
|
case LOONGARCH_CSR_IB0MASK + 8 * 7:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0MASK + 8 * 7);
|
|
break;
|
|
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 0:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ASID + 8 * 0);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 1:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ASID + 8 * 1);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 2:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ASID + 8 * 2);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 3:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ASID + 8 * 3);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 4:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ASID + 8 * 4);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 5:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ASID + 8 * 5);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 6:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ASID + 8 * 6);
|
|
break;
|
|
case LOONGARCH_CSR_IB0ASID + 8 * 7:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0ASID + 8 * 7);
|
|
break;
|
|
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 0:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0CTL + 8 * 0);
|
|
break;
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 1:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0CTL + 8 * 1);
|
|
break;
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 2:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0CTL + 8 * 2);
|
|
break;
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 3:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0CTL + 8 * 3);
|
|
break;
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 4:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0CTL + 8 * 4);
|
|
break;
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 5:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0CTL + 8 * 5);
|
|
break;
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 6:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0CTL + 8 * 6);
|
|
break;
|
|
case LOONGARCH_CSR_IB0CTL + 8 * 7:
|
|
csr_writeq(val, LOONGARCH_CSR_IB0CTL + 8 * 7);
|
|
break;
|
|
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 0:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ADDR + 8 * 0);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 1:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ADDR + 8 * 1);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 2:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ADDR + 8 * 2);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 3:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ADDR + 8 * 3);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 4:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ADDR + 8 * 4);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 5:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ADDR + 8 * 5);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 6:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ADDR + 8 * 6);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ADDR + 8 * 7:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ADDR + 8 * 7);
|
|
break;
|
|
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 0:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0MASK + 8 * 0);
|
|
break;
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 1:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0MASK + 8 * 1);
|
|
break;
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 2:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0MASK + 8 * 2);
|
|
break;
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 3:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0MASK + 8 * 3);
|
|
break;
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 4:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0MASK + 8 * 4);
|
|
break;
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 5:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0MASK + 8 * 5);
|
|
break;
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 6:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0MASK + 8 * 6);
|
|
break;
|
|
case LOONGARCH_CSR_DB0MASK + 8 * 7:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0MASK + 8 * 7);
|
|
break;
|
|
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 0:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ASID + 8 * 0);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 1:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ASID + 8 * 1);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 2:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ASID + 8 * 2);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 3:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ASID + 8 * 3);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 4:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ASID + 8 * 4);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 5:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ASID + 8 * 5);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 6:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ASID + 8 * 6);
|
|
break;
|
|
case LOONGARCH_CSR_DB0ASID + 8 * 7:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0ASID + 8 * 7);
|
|
break;
|
|
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 0:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0CTL + 8 * 0);
|
|
break;
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 1:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0CTL + 8 * 1);
|
|
break;
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 2:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0CTL + 8 * 2);
|
|
break;
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 3:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0CTL + 8 * 3);
|
|
break;
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 4:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0CTL + 8 * 4);
|
|
break;
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 5:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0CTL + 8 * 5);
|
|
break;
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 6:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0CTL + 8 * 6);
|
|
break;
|
|
case LOONGARCH_CSR_DB0CTL + 8 * 7:
|
|
csr_writeq(val, LOONGARCH_CSR_DB0CTL + 8 * 7);
|
|
break;
|
|
|
|
case LOONGARCH_CSR_FWPS:
|
|
csr_writeq(val, LOONGARCH_CSR_FWPS);
|
|
break;
|
|
case LOONGARCH_CSR_MWPS:
|
|
csr_writeq(val, LOONGARCH_CSR_MWPS);
|
|
break;
|
|
default:
|
|
printk("write watch register number error %d\n", reg);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(watch_csrwr);
|
|
|
|
/*
|
|
* Install the watch registers for the current thread. A maximum of
|
|
* four registers are installed although the machine may have more.
|
|
*/
|
|
void loongarch_install_watch_registers(struct task_struct *t)
|
|
{
|
|
int i, j, dbcn;
|
|
struct loongarch3264_watch_reg_state *watches = &t->thread.watch.loongarch3264;
|
|
|
|
dbcn = boot_cpu_data.watch_dreg_count;
|
|
for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
|
|
if (watches->irw[i] & (LA_WATCH_R | LA_WATCH_W)) {
|
|
unsigned int dbc = 0x1e;
|
|
|
|
if ((watches->irw[i] & LA_WATCH_R))
|
|
dbc |= 1<<8;
|
|
if ((watches->irw[i] & LA_WATCH_W))
|
|
dbc |= 1<<9;
|
|
|
|
watch_csrwr(watches->addr[i], LOONGARCH_CSR_DB0ADDR + 8*i);
|
|
watch_csrwr(watches->mask[i], LOONGARCH_CSR_DB0MASK + 8*i);
|
|
watch_csrwr(0, LOONGARCH_CSR_DB0ASID + 8*i);
|
|
watch_csrwr(dbc, LOONGARCH_CSR_DB0CTL + 8*i);
|
|
|
|
} else if (watches->irw[i] & LA_WATCH_I) {
|
|
j = i - dbcn;
|
|
watch_csrwr(watches->addr[i], LOONGARCH_CSR_IB0ADDR + 8*j);
|
|
watch_csrwr(watches->mask[i], LOONGARCH_CSR_IB0MASK + 8*j);
|
|
watch_csrwr(0, LOONGARCH_CSR_IB0ASID + 8*j);
|
|
watch_csrwr(0x1e, LOONGARCH_CSR_IB0CTL + 8*j);
|
|
if ((task_pt_regs(t)->csr_era & ~watches->mask[i]) ==
|
|
(watches->addr[i] & ~watches->mask[i]))
|
|
watch_csrwr(0x10000, LOONGARCH_CSR_FWPS);
|
|
} else if (watches->irwmask[i]) {
|
|
if (i < dbcn) {
|
|
watch_csrwr(0x0, LOONGARCH_CSR_DB0CTL + 8*i);
|
|
} else {
|
|
j = i - dbcn;
|
|
watch_csrwr(0x0, LOONGARCH_CSR_IB0CTL + 8*j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(loongarch_install_watch_registers);
|
|
|
|
#define PRMD_WE (1UL<<3) /* PRMD watch enable, restore to CRMD when eret */
|
|
|
|
void loongarch_clear_prev_watch_registers(struct task_struct *prev)
|
|
{
|
|
struct pt_regs *regs = task_pt_regs(prev);
|
|
|
|
loongarch_clear_watch_registers();
|
|
prev->thread.csr_prmd &= ~PRMD_WE;
|
|
regs->csr_prmd &= ~PRMD_WE;
|
|
}
|
|
|
|
void loongarch_install_next_watch_registers(struct task_struct *next)
|
|
{
|
|
struct pt_regs *regs = task_pt_regs(next);
|
|
|
|
loongarch_install_watch_registers(next);
|
|
next->thread.csr_prmd |= PRMD_WE;
|
|
regs->csr_prmd |= PRMD_WE;
|
|
}
|
|
|
|
#define CTRL_WE 1 /* Breakpoint can only be written by hw debugger */
|
|
|
|
void loongarch_update_watch_registers(struct task_struct *t)
|
|
{
|
|
struct loongarch3264_watch_reg_state *watches =
|
|
&t->thread.watch.loongarch3264;
|
|
int i, j, dbcn, ctl;
|
|
|
|
dbcn = boot_cpu_data.watch_dreg_count;
|
|
for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
|
|
if (i < dbcn) {
|
|
ctl = watch_csrrd(LOONGARCH_CSR_DB0CTL + 8*i);
|
|
if (ctl & CTRL_WE)
|
|
watches->irwmask[i] = 0;
|
|
else
|
|
watches->irwmask[i] = LA_WATCH_R | LA_WATCH_W;
|
|
} else {
|
|
j = i - dbcn;
|
|
ctl = watch_csrrd(LOONGARCH_CSR_IB0CTL + 8*j);
|
|
if (ctl & CTRL_WE)
|
|
watches->irwmask[i] = 0;
|
|
else
|
|
watches->irwmask[i] = LA_WATCH_I;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Read back the watchhi registers so the user space debugger has
|
|
* access to the I, R, and W bits. A maximum of four registers are
|
|
* read although the machine may have more.
|
|
*/
|
|
|
|
void loongarch_read_watch_registers(struct pt_regs *regs)
|
|
{
|
|
struct loongarch3264_watch_reg_state *watches =
|
|
¤t->thread.watch.loongarch3264;
|
|
unsigned int i, j, dbcn, ibst, dbst;
|
|
|
|
dbcn = boot_cpu_data.watch_dreg_count;
|
|
ibst = watch_csrrd(LOONGARCH_CSR_FWPS);
|
|
dbst = watch_csrrd(LOONGARCH_CSR_MWPS);
|
|
|
|
for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
|
|
if (i < dbcn) {
|
|
watches->addr[i] = watch_csrrd(LOONGARCH_CSR_DB0ADDR + 8*i);
|
|
watches->mask[i] = watch_csrrd(LOONGARCH_CSR_DB0MASK + 8*i);
|
|
if (dbst & (1u << i)) {
|
|
int dbc = watch_csrrd(LOONGARCH_CSR_DB0CTL + i*8);
|
|
|
|
watches->irwstat[i] = 0;
|
|
if (dbc & (1<<8))
|
|
watches->irwstat[i] |= LA_WATCH_R;
|
|
if (dbc & (1<<9))
|
|
watches->irwstat[i] |= LA_WATCH_W;
|
|
}
|
|
} else {
|
|
j = i - dbcn;
|
|
watches->addr[i] = watch_csrrd(LOONGARCH_CSR_IB0ADDR + 8*j);
|
|
watches->mask[i] = watch_csrrd(LOONGARCH_CSR_IB0MASK + 8*j);
|
|
watches->irwstat[i] = 0;
|
|
if (ibst & (1u << j))
|
|
watches->irwstat[i] |= LA_WATCH_I;
|
|
}
|
|
}
|
|
|
|
if (ibst & 0xffff)
|
|
watch_csrwr(ibst, LOONGARCH_CSR_FWPS);
|
|
if (dbst & 0xffff)
|
|
watch_csrwr(dbst, LOONGARCH_CSR_MWPS);
|
|
}
|
|
|
|
/*
|
|
* Disable all watch registers. Although only four registers are
|
|
* installed, all are cleared to eliminate the possibility of endless
|
|
* looping in the watch handler.
|
|
*/
|
|
void loongarch_clear_watch_registers(void)
|
|
{
|
|
unsigned int i, j, dbcn, ibst, dbst;
|
|
|
|
ibst = watch_csrrd(LOONGARCH_CSR_FWPS);
|
|
dbst = watch_csrrd(LOONGARCH_CSR_MWPS);
|
|
dbcn = boot_cpu_data.watch_dreg_count;
|
|
|
|
/*
|
|
* bit 16: skip next event
|
|
* bit 0-15: breakpoint triggered, W1C
|
|
*/
|
|
|
|
if (ibst & 0x1ffff)
|
|
watch_csrwr(ibst&~0x10000, LOONGARCH_CSR_FWPS);
|
|
if (dbst & 0x1ffff)
|
|
watch_csrwr(dbst&~0x10000, LOONGARCH_CSR_MWPS);
|
|
|
|
for (i = 0; i < current_cpu_data.watch_reg_use_cnt; i++) {
|
|
if (i < dbcn) {
|
|
watch_csrwr(0, LOONGARCH_CSR_DB0ADDR + 8*i);
|
|
watch_csrwr(0, LOONGARCH_CSR_DB0MASK + 8*i);
|
|
watch_csrwr(0, LOONGARCH_CSR_DB0ASID + 8*i);
|
|
watch_csrwr(0, LOONGARCH_CSR_DB0CTL + 8*i);
|
|
} else {
|
|
j = i - dbcn;
|
|
watch_csrwr(0, LOONGARCH_CSR_IB0ADDR + 8*j);
|
|
watch_csrwr(0, LOONGARCH_CSR_IB0MASK + 8*j);
|
|
watch_csrwr(0, LOONGARCH_CSR_IB0ASID + 8*j);
|
|
watch_csrwr(0, LOONGARCH_CSR_IB0CTL + 8*j);
|
|
}
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(loongarch_clear_watch_registers);
|
|
|
|
void loongarch_probe_watch_registers(struct cpuinfo_loongarch *c)
|
|
{
|
|
unsigned int ibcn, dbcn, total;
|
|
|
|
ibcn = watch_csrrd(LOONGARCH_CSR_FWPC) & 0x3f;
|
|
dbcn = watch_csrrd(LOONGARCH_CSR_MWPC) & 0x3f;
|
|
c->watch_dreg_count = dbcn;
|
|
c->watch_ireg_count = ibcn;
|
|
total = ibcn + dbcn;
|
|
c->watch_reg_use_cnt = (total < NUM_WATCH_REGS) ? total : NUM_WATCH_REGS;
|
|
}
|