linux/arch/avr32/kernel/ocd.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007 Atmel Corporation
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8#include <linux/init.h>
   9#include <linux/sched.h>
  10#include <linux/spinlock.h>
  11
  12#include <asm/ocd.h>
  13
  14static long ocd_count;
  15static spinlock_t ocd_lock;
  16
  17/**
  18 * ocd_enable - enable on-chip debugging
  19 * @child: task to be debugged
  20 *
  21 * If @child is non-NULL, ocd_enable() first checks if debugging has
  22 * already been enabled for @child, and if it has, does nothing.
  23 *
  24 * If @child is NULL (e.g. when debugging the kernel), or debugging
  25 * has not already been enabled for it, ocd_enable() increments the
  26 * reference count and enables the debugging hardware.
  27 */
  28void ocd_enable(struct task_struct *child)
  29{
  30        u32 dc;
  31
  32        if (child)
  33                pr_debug("ocd_enable: child=%s [%u]\n",
  34                                child->comm, child->pid);
  35        else
  36                pr_debug("ocd_enable (no child)\n");
  37
  38        if (!child || !test_and_set_tsk_thread_flag(child, TIF_DEBUG)) {
  39                spin_lock(&ocd_lock);
  40                ocd_count++;
  41                dc = ocd_read(DC);
  42                dc |= (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT);
  43                ocd_write(DC, dc);
  44                spin_unlock(&ocd_lock);
  45        }
  46}
  47
  48/**
  49 * ocd_disable - disable on-chip debugging
  50 * @child: task that was being debugged, but isn't anymore
  51 *
  52 * If @child is non-NULL, ocd_disable() checks if debugging is enabled
  53 * for @child, and if it isn't, does nothing.
  54 *
  55 * If @child is NULL (e.g. when debugging the kernel), or debugging is
  56 * enabled, ocd_disable() decrements the reference count, and if it
  57 * reaches zero, disables the debugging hardware.
  58 */
  59void ocd_disable(struct task_struct *child)
  60{
  61        u32 dc;
  62
  63        if (!child)
  64                pr_debug("ocd_disable (no child)\n");
  65        else if (test_tsk_thread_flag(child, TIF_DEBUG))
  66                pr_debug("ocd_disable: child=%s [%u]\n",
  67                                child->comm, child->pid);
  68
  69        if (!child || test_and_clear_tsk_thread_flag(child, TIF_DEBUG)) {
  70                spin_lock(&ocd_lock);
  71                ocd_count--;
  72
  73                WARN_ON(ocd_count < 0);
  74
  75                if (ocd_count <= 0) {
  76                        dc = ocd_read(DC);
  77                        dc &= ~((1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
  78                        ocd_write(DC, dc);
  79                }
  80                spin_unlock(&ocd_lock);
  81        }
  82}
  83
  84#ifdef CONFIG_DEBUG_FS
  85#include <linux/debugfs.h>
  86#include <linux/module.h>
  87
  88static struct dentry *ocd_debugfs_root;
  89static struct dentry *ocd_debugfs_DC;
  90static struct dentry *ocd_debugfs_DS;
  91static struct dentry *ocd_debugfs_count;
  92
  93static int ocd_DC_get(void *data, u64 *val)
  94{
  95        *val = ocd_read(DC);
  96        return 0;
  97}
  98static int ocd_DC_set(void *data, u64 val)
  99{
 100        ocd_write(DC, val);
 101        return 0;
 102}
 103DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n");
 104
 105static int ocd_DS_get(void *data, u64 *val)
 106{
 107        *val = ocd_read(DS);
 108        return 0;
 109}
 110DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n");
 111
 112static int ocd_count_get(void *data, u64 *val)
 113{
 114        *val = ocd_count;
 115        return 0;
 116}
 117DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n");
 118
 119static void ocd_debugfs_init(void)
 120{
 121        struct dentry *root;
 122
 123        root = debugfs_create_dir("ocd", NULL);
 124        if (IS_ERR(root) || !root)
 125                goto err_root;
 126        ocd_debugfs_root = root;
 127
 128        ocd_debugfs_DC = debugfs_create_file("DC", S_IRUSR | S_IWUSR,
 129                                root, NULL, &fops_DC);
 130        if (!ocd_debugfs_DC)
 131                goto err_DC;
 132
 133        ocd_debugfs_DS = debugfs_create_file("DS", S_IRUSR, root,
 134                                NULL, &fops_DS);
 135        if (!ocd_debugfs_DS)
 136                goto err_DS;
 137
 138        ocd_debugfs_count = debugfs_create_file("count", S_IRUSR, root,
 139                                NULL, &fops_count);
 140        if (!ocd_debugfs_count)
 141                goto err_count;
 142
 143        return;
 144
 145err_count:
 146        debugfs_remove(ocd_debugfs_DS);
 147err_DS:
 148        debugfs_remove(ocd_debugfs_DC);
 149err_DC:
 150        debugfs_remove(ocd_debugfs_root);
 151err_root:
 152        printk(KERN_WARNING "OCD: Failed to create debugfs entries\n");
 153}
 154#else
 155static inline void ocd_debugfs_init(void)
 156{
 157
 158}
 159#endif
 160
 161static int __init ocd_init(void)
 162{
 163        spin_lock_init(&ocd_lock);
 164        ocd_debugfs_init();
 165        return 0;
 166}
 167arch_initcall(ocd_init);
 168