diff options
author | Ronald G. Minnich <rminnich@gmail.com> | 2013-03-04 09:46:31 -0800 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2013-03-04 19:43:19 +0100 |
commit | 026bbda071161ad56822dceaabea03bceefac9ac (patch) | |
tree | 4d67044debe77486daa9d56348b3689f90341873 /src/cpu/samsung/exynos5250/power.c | |
parent | 1a43309bf7222fc25e8583d128c9685ec251dd76 (diff) | |
download | coreboot-026bbda071161ad56822dceaabea03bceefac9ac.tar.xz |
ARM: remove code that is IMHO a dangerous design
OK, this is tl;dr. But I need to write this in hopes we make
sure we don't put code like this into coreboot. Ever.
Our excuse in this case is that it was imported, not obviously wrong,
and easily changed. It made sense to get it in, make it work, then
do a cleanup pass, because changing everything up front is almost
impossible to debug.
The exynos code has bunch of base register values, e.g.
These are base addresses of things that look like a memory-mapped
struct. To get these to a pointer, they created the following macro,
which creates an inline function.
static inline unsigned int samsung_get_base_##device(void) \
{ \
return cpu_is_exynos5() ? EXYNOS5_##base : 0; \
}
And then invoke it 31 times in a .h file, e.g.:
SAMSUNG_BASE(clock, CLOCK_BASE)
to create 31 functions.
And then use it:
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
OK, what's wrong with this? It's easier to ask what's right with it. Answer: nothing.
I have a long list of what's wrong, and I may leave some things out,
but here goes:
1. the "function" can return a NULL if we're not on exynos5. Most uses of the code
don't check the return value.
2. And why would this function be running, if we're not on an exynos5? Why compile it in?
3. Note the cast everywhere a samsung_get_base_xxx is used.
The function returns an untyped variable, requiring the *user* to get two
things right: the cast, and the function invocation. One can replace that _clock(); with
_power(); in the code above, and they will be referencing the wrong registers, and
they'll never get an error!
We have a C compiler; use it to type data.
4. You're generating 31 functions using cpp each and every time the file is included.
The C compiler has to parse these each time. It's not at all like a simple cpp
macro which is only generated on use.
5. You can't tags or etags this code
6. In fact, any kind of analysis tool will be unable to do anything with this cpp magic.
That's only a partial list.
So what's the right way to do it? Just make typed constants, viz:
Or, since I expect people will want the lower case function syntax, I've left
it that way:
Now we've got something that is efficient, and we don't even need to protect with
any more.
Hence this change. We've got something that is type checked, does not require users to
cast on each use, will catch simple programming errors, can be analyzed with standard tools,
and builds faster.
So if we make a mistake:
struct exynos5_clock *clk =
samsung_get_base_adc();
We'll see it:
src/cpu/samsung/exynos5250/clock.c: In function 'get_pll_clk':
src/cpu/samsung/exynos5250/clock.c:183:3: error: initialization from incompatible pointer type [-Werror]
which we would not have seen before.
As a minor benefit, it shaves most of a second off the compilation.
Change-Id: Ie67bc4bc038a8dd1837b977d07332d7d7fd6be1f
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Reviewed-on: http://review.coreboot.org/2582
Tested-by: build bot (Jenkins)
Diffstat (limited to 'src/cpu/samsung/exynos5250/power.c')
-rw-r--r-- | src/cpu/samsung/exynos5250/power.c | 22 |
1 files changed, 11 insertions, 11 deletions
diff --git a/src/cpu/samsung/exynos5250/power.c b/src/cpu/samsung/exynos5250/power.c index 41e1e1b1f5..953bf5c518 100644 --- a/src/cpu/samsung/exynos5250/power.c +++ b/src/cpu/samsung/exynos5250/power.c @@ -38,7 +38,7 @@ static void ps_hold_setup(void) { struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); /* Set PS-Hold high */ setbits_le32(&power->ps_hold_ctrl, POWER_PS_HOLD_CONTROL_DATA_HIGH); @@ -47,7 +47,7 @@ static void ps_hold_setup(void) void power_reset(void) { struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); /* Clear inform1 so there's no change we think we've got a wake reset */ power->inform1 = 0; @@ -59,7 +59,7 @@ void power_reset(void) void power_shutdown(void) { struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); clrbits_le32(&power->ps_hold_ctrl, POWER_PS_HOLD_CONTROL_DATA_HIGH); @@ -69,7 +69,7 @@ void power_shutdown(void) void power_enable_dp_phy(void) { struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); setbits_le32(&power->dptx_phy_control, DPTX_PHY_ENABLE); } @@ -77,9 +77,9 @@ void power_enable_dp_phy(void) void power_enable_usb_phy(void) { struct exynos5_sysreg *sysreg = - (struct exynos5_sysreg *)samsung_get_base_sysreg(); + samsung_get_base_sysreg(); struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); unsigned int phy_cfg; /* Setting USB20PHY_CONFIG register to USB 2.0 HOST link */ @@ -98,7 +98,7 @@ void power_enable_usb_phy(void) void power_disable_usb_phy(void) { struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); /* Disabling USBHost_PHY */ clrbits_le32(&power->usb_host_phy_ctrl, POWER_USB_HOST_PHY_CTRL_EN); @@ -107,7 +107,7 @@ void power_disable_usb_phy(void) void power_enable_hw_thermal_trip(void) { struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); /* Enable HW thermal trip */ setbits_le32(&power->ps_hold_ctrl, POWER_ENABLE_HW_TRIP); @@ -116,7 +116,7 @@ void power_enable_hw_thermal_trip(void) uint32_t power_read_reset_status(void) { struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); return power->inform1; } @@ -124,7 +124,7 @@ uint32_t power_read_reset_status(void) void power_exit_wakeup(void) { struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); typedef void (*resume_func)(void); ((resume_func)power->inform0)(); @@ -193,7 +193,7 @@ int power_init(void) void power_enable_xclkout(void) { struct exynos5_power *power = - (struct exynos5_power *)samsung_get_base_power(); + samsung_get_base_power(); /* use xxti for xclk out */ clrsetbits_le32(&power->pmu_debug, PMU_DEBUG_CLKOUT_SEL_MASK, |