cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ubc.c (2858B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * arch/sh/kernel/cpu/sh4a/ubc.c
      4 *
      5 * On-chip UBC support for SH-4A CPUs.
      6 *
      7 * Copyright (C) 2009 - 2010  Paul Mundt
      8 */
      9#include <linux/init.h>
     10#include <linux/err.h>
     11#include <linux/clk.h>
     12#include <linux/io.h>
     13#include <asm/hw_breakpoint.h>
     14
     15#define UBC_CBR(idx)	(0xff200000 + (0x20 * idx))
     16#define UBC_CRR(idx)	(0xff200004 + (0x20 * idx))
     17#define UBC_CAR(idx)	(0xff200008 + (0x20 * idx))
     18#define UBC_CAMR(idx)	(0xff20000c + (0x20 * idx))
     19
     20#define UBC_CCMFR	0xff200600
     21#define UBC_CBCR	0xff200620
     22
     23/* CRR */
     24#define UBC_CRR_PCB	(1 << 1)
     25#define UBC_CRR_BIE	(1 << 0)
     26
     27/* CBR */
     28#define UBC_CBR_CE	(1 << 0)
     29
     30static struct sh_ubc sh4a_ubc;
     31
     32static void sh4a_ubc_enable(struct arch_hw_breakpoint *info, int idx)
     33{
     34	__raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR(idx));
     35	__raw_writel(info->address, UBC_CAR(idx));
     36}
     37
     38static void sh4a_ubc_disable(struct arch_hw_breakpoint *info, int idx)
     39{
     40	__raw_writel(0, UBC_CBR(idx));
     41	__raw_writel(0, UBC_CAR(idx));
     42}
     43
     44static void sh4a_ubc_enable_all(unsigned long mask)
     45{
     46	int i;
     47
     48	for (i = 0; i < sh4a_ubc.num_events; i++)
     49		if (mask & (1 << i))
     50			__raw_writel(__raw_readl(UBC_CBR(i)) | UBC_CBR_CE,
     51				     UBC_CBR(i));
     52}
     53
     54static void sh4a_ubc_disable_all(void)
     55{
     56	int i;
     57
     58	for (i = 0; i < sh4a_ubc.num_events; i++)
     59		__raw_writel(__raw_readl(UBC_CBR(i)) & ~UBC_CBR_CE,
     60			     UBC_CBR(i));
     61}
     62
     63static unsigned long sh4a_ubc_active_mask(void)
     64{
     65	unsigned long active = 0;
     66	int i;
     67
     68	for (i = 0; i < sh4a_ubc.num_events; i++)
     69		if (__raw_readl(UBC_CBR(i)) & UBC_CBR_CE)
     70			active |= (1 << i);
     71
     72	return active;
     73}
     74
     75static unsigned long sh4a_ubc_triggered_mask(void)
     76{
     77	return __raw_readl(UBC_CCMFR);
     78}
     79
     80static void sh4a_ubc_clear_triggered_mask(unsigned long mask)
     81{
     82	__raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR);
     83}
     84
     85static struct sh_ubc sh4a_ubc = {
     86	.name			= "SH-4A",
     87	.num_events		= 2,
     88	.trap_nr		= 0x1e0,
     89	.enable			= sh4a_ubc_enable,
     90	.disable		= sh4a_ubc_disable,
     91	.enable_all		= sh4a_ubc_enable_all,
     92	.disable_all		= sh4a_ubc_disable_all,
     93	.active_mask		= sh4a_ubc_active_mask,
     94	.triggered_mask		= sh4a_ubc_triggered_mask,
     95	.clear_triggered_mask	= sh4a_ubc_clear_triggered_mask,
     96};
     97
     98static int __init sh4a_ubc_init(void)
     99{
    100	struct clk *ubc_iclk = clk_get(NULL, "ubc0");
    101	int i;
    102
    103	/*
    104	 * The UBC MSTP bit is optional, as not all platforms will have
    105	 * it. Just ignore it if we can't find it.
    106	 */
    107	if (IS_ERR(ubc_iclk))
    108		ubc_iclk = NULL;
    109
    110	clk_enable(ubc_iclk);
    111
    112	__raw_writel(0, UBC_CBCR);
    113
    114	for (i = 0; i < sh4a_ubc.num_events; i++) {
    115		__raw_writel(0, UBC_CAMR(i));
    116		__raw_writel(0, UBC_CBR(i));
    117
    118		__raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR(i));
    119
    120		/* dummy read for write posting */
    121		(void)__raw_readl(UBC_CRR(i));
    122	}
    123
    124	clk_disable(ubc_iclk);
    125
    126	sh4a_ubc.clk = ubc_iclk;
    127
    128	return register_sh_ubc(&sh4a_ubc);
    129}
    130arch_initcall(sh4a_ubc_init);