diff options
Diffstat (limited to 'arch/sh/kernel/cpu/hwblk.c')
| -rw-r--r-- | arch/sh/kernel/cpu/hwblk.c | 69 |
1 files changed, 47 insertions, 22 deletions
diff --git a/arch/sh/kernel/cpu/hwblk.c b/arch/sh/kernel/cpu/hwblk.c index 7c3a73deff24..c0ad7d46e784 100644 --- a/arch/sh/kernel/cpu/hwblk.c +++ b/arch/sh/kernel/cpu/hwblk.c | |||
| @@ -9,38 +9,64 @@ | |||
| 9 | 9 | ||
| 10 | static DEFINE_SPINLOCK(hwblk_lock); | 10 | static DEFINE_SPINLOCK(hwblk_lock); |
| 11 | 11 | ||
| 12 | static void hwblk_area_inc(struct hwblk_info *info, int area) | 12 | static void hwblk_area_mod_cnt(struct hwblk_info *info, |
| 13 | int area, int counter, int value, int goal) | ||
| 13 | { | 14 | { |
| 14 | struct hwblk_area *hap = info->areas + area; | 15 | struct hwblk_area *hap = info->areas + area; |
| 15 | 16 | ||
| 16 | hap->cnt++; | 17 | hap->cnt[counter] += value; |
| 17 | if (hap->cnt == 1) | 18 | |
| 18 | if (hap->flags & HWBLK_AREA_FLAG_PARENT) | 19 | if (hap->cnt[counter] != goal) |
| 19 | hwblk_area_inc(info, hap->parent); | 20 | return; |
| 21 | |||
| 22 | if (hap->flags & HWBLK_AREA_FLAG_PARENT) | ||
| 23 | hwblk_area_mod_cnt(info, hap->parent, counter, value, goal); | ||
| 20 | } | 24 | } |
| 21 | 25 | ||
| 22 | static void hwblk_area_dec(struct hwblk_info *info, int area) | 26 | |
| 27 | static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk, | ||
| 28 | int counter, int value, int goal) | ||
| 23 | { | 29 | { |
| 24 | struct hwblk_area *hap = info->areas + area; | 30 | struct hwblk *hp = info->hwblks + hwblk; |
| 31 | |||
| 32 | hp->cnt[counter] += value; | ||
| 33 | if (hp->cnt[counter] == goal) | ||
| 34 | hwblk_area_mod_cnt(info, hp->area, counter, value, goal); | ||
| 25 | 35 | ||
| 26 | if (hap->cnt == 1) | 36 | return hp->cnt[counter]; |
| 27 | if (hap->flags & HWBLK_AREA_FLAG_PARENT) | ||
| 28 | hwblk_area_dec(info, hap->parent); | ||
| 29 | hap->cnt--; | ||
| 30 | } | 37 | } |
| 31 | 38 | ||
| 32 | static void hwblk_enable(struct hwblk_info *info, int hwblk) | 39 | static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk, |
| 40 | int counter, int value, int goal) | ||
| 41 | { | ||
| 42 | unsigned long flags; | ||
| 43 | |||
| 44 | spin_lock_irqsave(&hwblk_lock, flags); | ||
| 45 | __hwblk_mod_cnt(info, hwblk, counter, value, goal); | ||
| 46 | spin_unlock_irqrestore(&hwblk_lock, flags); | ||
| 47 | } | ||
| 48 | |||
| 49 | void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter) | ||
| 50 | { | ||
| 51 | hwblk_mod_cnt(info, hwblk, counter, 1, 1); | ||
| 52 | } | ||
| 53 | |||
| 54 | void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter) | ||
| 55 | { | ||
| 56 | hwblk_mod_cnt(info, hwblk, counter, -1, 0); | ||
| 57 | } | ||
| 58 | |||
| 59 | void hwblk_enable(struct hwblk_info *info, int hwblk) | ||
| 33 | { | 60 | { |
| 34 | struct hwblk *hp = info->hwblks + hwblk; | 61 | struct hwblk *hp = info->hwblks + hwblk; |
| 35 | unsigned long tmp; | 62 | unsigned long tmp; |
| 36 | unsigned long flags; | 63 | unsigned long flags; |
| 64 | int ret; | ||
| 37 | 65 | ||
| 38 | spin_lock_irqsave(&hwblk_lock, flags); | 66 | spin_lock_irqsave(&hwblk_lock, flags); |
| 39 | 67 | ||
| 40 | hp->cnt++; | 68 | ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1); |
| 41 | if (hp->cnt == 1) { | 69 | if (ret == 1) { |
| 42 | hwblk_area_inc(info, hp->area); | ||
| 43 | |||
| 44 | tmp = __raw_readl(hp->mstp); | 70 | tmp = __raw_readl(hp->mstp); |
| 45 | tmp &= ~(1 << hp->bit); | 71 | tmp &= ~(1 << hp->bit); |
| 46 | __raw_writel(tmp, hp->mstp); | 72 | __raw_writel(tmp, hp->mstp); |
| @@ -49,27 +75,26 @@ static void hwblk_enable(struct hwblk_info *info, int hwblk) | |||
| 49 | spin_unlock_irqrestore(&hwblk_lock, flags); | 75 | spin_unlock_irqrestore(&hwblk_lock, flags); |
| 50 | } | 76 | } |
| 51 | 77 | ||
| 52 | static void hwblk_disable(struct hwblk_info *info, int hwblk) | 78 | void hwblk_disable(struct hwblk_info *info, int hwblk) |
| 53 | { | 79 | { |
| 54 | struct hwblk *hp = info->hwblks + hwblk; | 80 | struct hwblk *hp = info->hwblks + hwblk; |
| 55 | unsigned long tmp; | 81 | unsigned long tmp; |
| 56 | unsigned long flags; | 82 | unsigned long flags; |
| 83 | int ret; | ||
| 57 | 84 | ||
| 58 | spin_lock_irqsave(&hwblk_lock, flags); | 85 | spin_lock_irqsave(&hwblk_lock, flags); |
| 59 | 86 | ||
| 60 | if (hp->cnt == 1) { | 87 | ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0); |
| 61 | hwblk_area_dec(info, hp->area); | 88 | if (ret == 0) { |
| 62 | |||
| 63 | tmp = __raw_readl(hp->mstp); | 89 | tmp = __raw_readl(hp->mstp); |
| 64 | tmp |= 1 << hp->bit; | 90 | tmp |= 1 << hp->bit; |
| 65 | __raw_writel(tmp, hp->mstp); | 91 | __raw_writel(tmp, hp->mstp); |
| 66 | } | 92 | } |
| 67 | hp->cnt--; | ||
| 68 | 93 | ||
| 69 | spin_unlock_irqrestore(&hwblk_lock, flags); | 94 | spin_unlock_irqrestore(&hwblk_lock, flags); |
| 70 | } | 95 | } |
| 71 | 96 | ||
| 72 | static struct hwblk_info *hwblk_info; | 97 | struct hwblk_info *hwblk_info; |
| 73 | 98 | ||
| 74 | int __init hwblk_register(struct hwblk_info *info) | 99 | int __init hwblk_register(struct hwblk_info *info) |
| 75 | { | 100 | { |
