Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 181070
b: refs/heads/master
c: 4352fc1
h: refs/heads/master
v: v3
  • Loading branch information
Paul Mundt committed Jan 5, 2010
1 parent d454536 commit 0c9ea9c
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 79 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c4761815ab49feca904776dec464046bc7138d3a
refs/heads/master: 4352fc1b12fae4c753a063a2f162ddf9277af774
22 changes: 18 additions & 4 deletions trunk/arch/sh/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@

#include <linux/kdebug.h>
#include <linux/types.h>
#include <asm/ubc.h>

#ifdef __KERNEL__
#define __ARCH_HW_BREAKPOINT_H

struct arch_hw_breakpoint {
char *name; /* Contains name of the symbol to set bkpt */
unsigned long address;
unsigned long asid;
u16 len;
u16 type;
};
Expand All @@ -27,13 +25,28 @@ enum {
SH_BREAKPOINT_LEN_8 = (1 << 14),
};

/* Total number of available UBC channels */
#define HBP_NUM 1 /* XXX */
struct sh_ubc {
const char *name;
unsigned int num_events;
unsigned int trap_nr;
void (*enable)(struct arch_hw_breakpoint *, int);
void (*disable)(struct arch_hw_breakpoint *, int);
void (*enable_all)(unsigned long);
void (*disable_all)(void);
unsigned long (*active_mask)(void);
unsigned long (*triggered_mask)(void);
void (*clear_triggered_mask)(unsigned long);
struct clk *clk; /* optional interface clock / MSTP bit */
};

struct perf_event;
struct task_struct;
struct pmu;

/* Maximum number of UBC channels */
#define HBP_NUM 2

/* arch/sh/kernel/hw_breakpoint.c */
extern int arch_check_va_in_userspace(unsigned long va, u16 hbp_len);
extern int arch_validate_hwbkpt_settings(struct perf_event *bp,
struct task_struct *tsk);
Expand All @@ -46,6 +59,7 @@ void hw_breakpoint_pmu_read(struct perf_event *bp);
void hw_breakpoint_pmu_unthrottle(struct perf_event *bp);

extern void arch_fill_perf_breakpoint(struct perf_event *bp);
extern int register_sh_ubc(struct sh_ubc *);

extern struct pmu perf_ops_bp;

Expand Down
4 changes: 2 additions & 2 deletions trunk/arch/sh/include/asm/processor_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <asm/page.h>
#include <asm/types.h>
#include <asm/ptrace.h>
#include <asm/ubc.h>
#include <asm/hw_breakpoint.h>

/*
* Default implementation of macro that returns current
Expand Down Expand Up @@ -102,7 +102,7 @@ struct thread_struct {
unsigned long pc;

/* Save middle states of ptrace breakpoints */
struct perf_event *ptrace_bps[NR_UBC_CHANNELS];
struct perf_event *ptrace_bps[HBP_NUM];

/* floating point info */
union sh_fpu_union fpu;
Expand Down
9 changes: 5 additions & 4 deletions trunk/arch/sh/kernel/cpu/sh4a/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7757) := pinmux-sh7757.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7785) := pinmux-sh7785.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o

obj-y += $(clock-y)
obj-$(CONFIG_SMP) += $(smp-y)
obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y)
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-y += $(clock-y)
obj-$(CONFIG_SMP) += $(smp-y)
obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y)
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += ubc.o
133 changes: 133 additions & 0 deletions trunk/arch/sh/kernel/cpu/sh4a/ubc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* arch/sh/kernel/cpu/sh4a/ubc.c
*
* On-chip UBC support for SH-4A CPUs.
*
* Copyright (C) 2009 - 2010 Paul Mundt
*
* 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.
*/
#include <linux/init.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <asm/hw_breakpoint.h>

#define UBC_CBR(idx) (0xff200000 + (0x20 * idx))
#define UBC_CRR(idx) (0xff200004 + (0x20 * idx))
#define UBC_CAR(idx) (0xff200008 + (0x20 * idx))
#define UBC_CAMR(idx) (0xff20000c + (0x20 * idx))

#define UBC_CCMFR 0xff200600
#define UBC_CBCR 0xff200620

/* CRR */
#define UBC_CRR_PCB (1 << 1)
#define UBC_CRR_BIE (1 << 0)

/* CBR */
#define UBC_CBR_CE (1 << 0)

static struct sh_ubc sh4a_ubc;

static void sh4a_ubc_enable(struct arch_hw_breakpoint *info, int idx)
{
__raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR(idx));
__raw_writel(info->address, UBC_CAR(idx));
}

static void sh4a_ubc_disable(struct arch_hw_breakpoint *info, int idx)
{
__raw_writel(0, UBC_CBR(idx));
__raw_writel(0, UBC_CAR(idx));
}

static void sh4a_ubc_enable_all(unsigned long mask)
{
int i;

for (i = 0; i < sh4a_ubc.num_events; i++)
if (mask & (1 << i))
__raw_writel(__raw_readl(UBC_CBR(i)) | UBC_CBR_CE,
UBC_CBR(i));
}

static void sh4a_ubc_disable_all(void)
{
int i;

for (i = 0; i < sh4a_ubc.num_events; i++)
__raw_writel(__raw_readl(UBC_CBR(i)) & ~UBC_CBR_CE,
UBC_CBR(i));
}

static unsigned long sh4a_ubc_active_mask(void)
{
unsigned long active = 0;
int i;

for (i = 0; i < sh4a_ubc.num_events; i++)
if (__raw_readl(UBC_CBR(i)) & UBC_CBR_CE)
active |= (1 << i);

return active;
}

static unsigned long sh4a_ubc_triggered_mask(void)
{
return __raw_readl(UBC_CCMFR);
}

static void sh4a_ubc_clear_triggered_mask(unsigned long mask)
{
__raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR);
}

static struct sh_ubc sh4a_ubc = {
.name = "SH-4A",
.num_events = 2,
.trap_nr = 0x1e0,
.enable = sh4a_ubc_enable,
.disable = sh4a_ubc_disable,
.enable_all = sh4a_ubc_enable_all,
.disable_all = sh4a_ubc_disable_all,
.active_mask = sh4a_ubc_active_mask,
.triggered_mask = sh4a_ubc_triggered_mask,
.clear_triggered_mask = sh4a_ubc_clear_triggered_mask,
};

static int __init sh4a_ubc_init(void)
{
struct clk *ubc_iclk = clk_get(NULL, "ubc0");
int i;

/*
* The UBC MSTP bit is optional, as not all platforms will have
* it. Just ignore it if we can't find it.
*/
if (IS_ERR(ubc_iclk))
ubc_iclk = NULL;

clk_enable(ubc_iclk);

__raw_writel(0, UBC_CBCR);

for (i = 0; i < sh4a_ubc.num_events; i++) {
__raw_writel(0, UBC_CAMR(i));
__raw_writel(0, UBC_CBR(i));

__raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR(i));

/* dummy read for write posting */
(void)__raw_readl(UBC_CRR(i));
}

clk_disable(ubc_iclk);

sh4a_ubc.clk = ubc_iclk;

return register_sh_ubc(&sh4a_ubc);
}
arch_initcall(sh4a_ubc_init);
Loading

0 comments on commit 0c9ea9c

Please sign in to comment.