2007-05-01 05:08:47

by Paul Sokolovsky

[permalink] [raw]
Subject: [RFC, PATCH 2/4] SoC base drivers: ASIC3 SoC hardware definitions

Hello linux-kernel,

Intro: This is a header with hardware definitions for ASIC3 chip,
contributed by HP/Compaq. It is provided as-is, as a vendor-originated
header.
---------

ipaq-asic3.h: Hardware definitions for ASIC3 chip, found in ~12
handheld devices from HP/Compaq and HTC.

Signed-off-by: Paul Sokolovsky <[email protected]>


include/asm-arm/hardware/ipaq-asic3.h | 609 +++++++++++++++++++++++++++++++++
1 files changed, 609 insertions(+), 0 deletions(-)

diff --git a/include/asm-arm/hardware/ipaq-asic3.h b/include/asm-arm/hardware/ipaq-asic3.h
new file mode 100644
index 0000000..789bb16
--- /dev/null
+++ b/include/asm-arm/hardware/ipaq-asic3.h
@@ -0,0 +1,609 @@
+/*
+ *
+ * Definitions for the HTC ASIC3 chip found in several handheld devices
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Andrew Christian
+ *
+ */
+
+#ifndef IPAQ_ASIC3_H
+#define IPAQ_ASIC3_H
+
+/****************************************************/
+/* IPAQ, ASIC #3, replaces ASIC #1 */
+
+#define IPAQ_ASIC3(_b,s,x,y) \
+ (*((volatile s *) (_b + _IPAQ_ASIC3_ ## x ## _Base + (_IPAQ_ASIC3_ ## x ## _ ## y))))
+#define IPAQ_ASIC3_N(_b,s,x,y,z) \
+ (*((volatile s *) (_b + _IPAQ_ASIC3_ ## x ## _ ## y ## _Base + (_IPAQ_ASIC3_ ## x ## _ ## z))))
+
+#define IPAQ_ASIC3_GPIO(_b,s,x,y) \
+ (*((volatile s *) (_b + _IPAQ_ASIC3_GPIO_ ## x ## _Base + (_IPAQ_ASIC3_GPIO_ ## y))))
+
+#define IPAQ_ASIC3_OFFSET(x,y) (_IPAQ_ASIC3_ ## x ## _Base + _IPAQ_ASIC3_ ## x ## _ ## y)
+#define IPAQ_ASIC3_GPIO_OFFSET(x,y) (_IPAQ_ASIC3_GPIO_ ## x ## _Base + _IPAQ_ASIC3_GPIO_ ## y)
+
+
+/* All offsets below are specified with this address bus shift */
+#define ASIC3_DEFAULT_ADDR_SHIFT 2
+
+#define _IPAQ_ASIC3_GPIO_A_Base 0x0000
+#define _IPAQ_ASIC3_GPIO_B_Base 0x0100
+#define _IPAQ_ASIC3_GPIO_C_Base 0x0200
+#define _IPAQ_ASIC3_GPIO_D_Base 0x0300
+
+#define _IPAQ_ASIC3_GPIO_Mask 0x00 /* R/W 0:don't mask, 1:mask interrupt */
+#define _IPAQ_ASIC3_GPIO_Direction 0x04 /* R/W 0:input, 1:output */
+#define _IPAQ_ASIC3_GPIO_Out 0x08 /* R/W 0:output low, 1:output high */
+#define _IPAQ_ASIC3_GPIO_TriggerType 0x0c /* R/W 0:level, 1:edge */
+#define _IPAQ_ASIC3_GPIO_EdgeTrigger 0x10 /* R/W 0:falling, 1:rising */
+#define _IPAQ_ASIC3_GPIO_LevelTrigger 0x14 /* R/W 0:low, 1:high level detect */
+#define _IPAQ_ASIC3_GPIO_SleepMask 0x18 /* R/W 0:don't mask, 1:mask trigger in sleep mode */
+#define _IPAQ_ASIC3_GPIO_SleepOut 0x1c /* R/W level 0:low, 1:high in sleep mode */
+#define _IPAQ_ASIC3_GPIO_BattFaultOut 0x20 /* R/W level 0:low, 1:high in batt_fault */
+#define _IPAQ_ASIC3_GPIO_IntStatus 0x24 /* R/W 0:none, 1:detect */
+#define _IPAQ_ASIC3_GPIO_AltFunction 0x28 /* R/W 0:normal control 1:LED register control */
+#define _IPAQ_ASIC3_GPIO_SleepConf 0x2c /* R/W bit 1: autosleep 0: disable gposlpout in normal mode, enable gposlpout in sleep mode */
+#define _IPAQ_ASIC3_GPIO_Status 0x30 /* R Pin status */
+
+#define IPAQ_ASIC3_GPIO_A_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, A, Mask )
+#define IPAQ_ASIC3_GPIO_A_DIR(_b) IPAQ_ASIC3_GPIO( _b, u16, A, Direction )
+#define IPAQ_ASIC3_GPIO_A_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, A, Out )
+#define IPAQ_ASIC3_GPIO_A_LEVELTRI(_b) IPAQ_ASIC3_GPIO( _b, u16, A, TriggerType )
+#define IPAQ_ASIC3_GPIO_A_RISING(_b) IPAQ_ASIC3_GPIO( _b, u16, A, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_A_LEVEL(_b) IPAQ_ASIC3_GPIO( _b, u16, A, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_A_SLEEP_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, A, SleepMask )
+#define IPAQ_ASIC3_GPIO_A_SLEEP_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, A, SleepOut )
+#define IPAQ_ASIC3_GPIO_A_BATT_FAULT_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, A, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_A_INT_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, A, IntStatus )
+#define IPAQ_ASIC3_GPIO_A_ALT_FUNCTION(_b) IPAQ_ASIC3_GPIO( _b, u16, A, AltFunction )
+#define IPAQ_ASIC3_GPIO_A_SLEEP_CONF(_b) IPAQ_ASIC3_GPIO( _b, u16, A, SleepConf )
+#define IPAQ_ASIC3_GPIO_A_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, A, Status )
+
+#define IPAQ_ASIC3_GPIO_B_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, B, Mask )
+#define IPAQ_ASIC3_GPIO_B_DIR(_b) IPAQ_ASIC3_GPIO( _b, u16, B, Direction )
+#define IPAQ_ASIC3_GPIO_B_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, B, Out )
+#define IPAQ_ASIC3_GPIO_B_LEVELTRI(_b) IPAQ_ASIC3_GPIO( _b, u16, B, TriggerType )
+#define IPAQ_ASIC3_GPIO_B_RISING(_b) IPAQ_ASIC3_GPIO( _b, u16, B, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_B_LEVEL(_b) IPAQ_ASIC3_GPIO( _b, u16, B, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_B_SLEEP_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, B, SleepMask )
+#define IPAQ_ASIC3_GPIO_B_SLEEP_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, B, SleepOut )
+#define IPAQ_ASIC3_GPIO_B_BATT_FAULT_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, B, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_B_INT_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, B, IntStatus )
+#define IPAQ_ASIC3_GPIO_B_ALT_FUNCTION(_b) IPAQ_ASIC3_GPIO( _b, u16, B, AltFunction )
+#define IPAQ_ASIC3_GPIO_B_SLEEP_CONF(_b) IPAQ_ASIC3_GPIO( _b, u16, B, SleepConf )
+#define IPAQ_ASIC3_GPIO_B_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, B, Status )
+
+#define IPAQ_ASIC3_GPIO_C_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, C, Mask )
+#define IPAQ_ASIC3_GPIO_C_DIR(_b) IPAQ_ASIC3_GPIO( _b, u16, C, Direction )
+#define IPAQ_ASIC3_GPIO_C_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, C, Out )
+#define IPAQ_ASIC3_GPIO_C_LEVELTRI(_b) IPAQ_ASIC3_GPIO( _b, u16, C, TriggerType )
+#define IPAQ_ASIC3_GPIO_C_RISING(_b) IPAQ_ASIC3_GPIO( _b, u16, C, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_C_LEVEL(_b) IPAQ_ASIC3_GPIO( _b, u16, C, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_C_SLEEP_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, C, SleepMask )
+#define IPAQ_ASIC3_GPIO_C_SLEEP_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, C, SleepOut )
+#define IPAQ_ASIC3_GPIO_C_BATT_FAULT_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, C, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_C_INT_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, C, IntStatus )
+#define IPAQ_ASIC3_GPIO_C_ALT_FUNCTION(_b) IPAQ_ASIC3_GPIO( _b, u16, C, AltFunction )
+#define IPAQ_ASIC3_GPIO_C_SLEEP_CONF(_b) IPAQ_ASIC3_GPIO( _b, u16, C, SleepConf )
+#define IPAQ_ASIC3_GPIO_C_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, C, Status )
+
+#define IPAQ_ASIC3_GPIO_D_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, D, Mask )
+#define IPAQ_ASIC3_GPIO_D_DIR(_b) IPAQ_ASIC3_GPIO( _b, u16, D, Direction )
+#define IPAQ_ASIC3_GPIO_D_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, D, Out )
+#define IPAQ_ASIC3_GPIO_D_LEVELTRI(_b) IPAQ_ASIC3_GPIO( _b, u16, D, TriggerType )
+#define IPAQ_ASIC3_GPIO_D_RISING(_b) IPAQ_ASIC3_GPIO( _b, u16, D, EdgeTrigger )
+#define IPAQ_ASIC3_GPIO_D_LEVEL(_b) IPAQ_ASIC3_GPIO( _b, u16, D, LevelTrigger )
+#define IPAQ_ASIC3_GPIO_D_SLEEP_MASK(_b) IPAQ_ASIC3_GPIO( _b, u16, D, SleepMask )
+#define IPAQ_ASIC3_GPIO_D_SLEEP_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, D, SleepOut )
+#define IPAQ_ASIC3_GPIO_D_BATT_FAULT_OUT(_b) IPAQ_ASIC3_GPIO( _b, u16, D, BattFaultOut )
+#define IPAQ_ASIC3_GPIO_D_INT_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, D, IntStatus )
+#define IPAQ_ASIC3_GPIO_D_ALT_FUNCTION(_b) IPAQ_ASIC3_GPIO( _b, u16, D, AltFunction )
+#define IPAQ_ASIC3_GPIO_D_SLEEP_CONF(_b) IPAQ_ASIC3_GPIO( _b, u16, D, SleepConf )
+#define IPAQ_ASIC3_GPIO_D_STATUS(_b) IPAQ_ASIC3_GPIO( _b, u16, D, Status )
+
+#define _IPAQ_ASIC3_SPI_Base 0x0400
+#define _IPAQ_ASIC3_SPI_Control 0x0000
+#define _IPAQ_ASIC3_SPI_TxData 0x0004
+#define _IPAQ_ASIC3_SPI_RxData 0x0008
+#define _IPAQ_ASIC3_SPI_Int 0x000c
+#define _IPAQ_ASIC3_SPI_Status 0x0010
+
+#define IPAQ_ASIC3_SPI_Control(_b) IPAQ_ASIC3( _b, u16, SPI, Control )
+#define IPAQ_ASIC3_SPI_TxData(_b) IPAQ_ASIC3( _b, u16, SPI, TxData )
+#define IPAQ_ASIC3_SPI_RxData(_b) IPAQ_ASIC3( _b, u16, SPI, RxData )
+#define IPAQ_ASIC3_SPI_Int(_b) IPAQ_ASIC3( _b, u16, SPI, Int )
+#define IPAQ_ASIC3_SPI_Status(_b) IPAQ_ASIC3( _b, u16, SPI, Status )
+
+#define SPI_CONTROL_SPR(clk) ((clk) & 0x0f) /* Clock rate */
+
+#define _IPAQ_ASIC3_PWM_0_Base 0x0500
+#define _IPAQ_ASIC3_PWM_1_Base 0x0600
+#define _IPAQ_ASIC3_PWM_TimeBase 0x0000
+#define _IPAQ_ASIC3_PWM_PeriodTime 0x0004
+#define _IPAQ_ASIC3_PWM_DutyTime 0x0008
+
+#define IPAQ_ASIC3_PWM_TimeBase(_b, x) IPAQ_ASIC3_N( _b, u16, PWM, x, TimeBase )
+#define IPAQ_ASIC3_PWM_PeriodTime(_b, x) IPAQ_ASIC3_N( _b, u16, PWM, x, PeriodTime )
+#define IPAQ_ASIC3_PWM_DutyTime(_b, x) IPAQ_ASIC3_N( _b, u16, PWM, x, DutyTime )
+
+#define PWM_TIMEBASE_VALUE(x) ((x)&0xf) /* Low 4 bits sets time base */
+#define PWM_TIMEBASE_ENABLE (1 << 4) /* Enable clock */
+
+#define _IPAQ_ASIC3_LED_0_Base 0x0700
+#define _IPAQ_ASIC3_LED_1_Base 0x0800
+#define _IPAQ_ASIC3_LED_2_Base 0x0900
+#define _IPAQ_ASIC3_LED_TimeBase 0x0000 /* R/W 7 bits */
+#define _IPAQ_ASIC3_LED_PeriodTime 0x0004 /* R/W 12 bits */
+#define _IPAQ_ASIC3_LED_DutyTime 0x0008 /* R/W 12 bits */
+#define _IPAQ_ASIC3_LED_AutoStopCount 0x000c /* R/W 16 bits */
+
+#define IPAQ_ASIC3_LED_TimeBase(_b, x) IPAQ_ASIC3_N( _b, u8, LED, x, TimeBase )
+#define IPAQ_ASIC3_LED_PeriodTime(_b, x) IPAQ_ASIC3_N( _b, u16, LED, x, PeriodTime )
+#define IPAQ_ASIC3_LED_DutyTime(_b, x) IPAQ_ASIC3_N( _b, u16, LED, x, DutyTime )
+#define IPAQ_ASIC3_LED_AutoStopCount(_b, x) IPAQ_ASIC3_N( _b, u16, LED, x, AutoStopCount )
+
+/* LED TimeBase bits - match ASIC2 */
+#define LED_TBS 0x0f /* Low 4 bits sets time base, max = 13 */
+ /* Note: max = 5 on hx4700 */
+ /* 0: maximum time base */
+ /* 1: maximum time base / 2 */
+ /* n: maximum time base / 2^n */
+
+#define LED_EN (1 << 4) /* LED ON/OFF 0:off, 1:on */
+#define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop set 0:disable, 1:enable */
+#define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */
+
+#define _IPAQ_ASIC3_CLOCK_Base 0x0A00
+#define _IPAQ_ASIC3_CLOCK_CDEX 0x00
+#define _IPAQ_ASIC3_CLOCK_SEL 0x04
+
+#define IPAQ_ASIC3_CLOCK_CDEX(_b) IPAQ_ASIC3( _b, u16, CLOCK, CDEX )
+#define IPAQ_ASIC3_CLOCK_SEL(_b) IPAQ_ASIC3( _b, u16, CLOCK, SEL )
+
+#define CLOCK_CDEX_SOURCE (1 << 0) /* 2 bits */
+#define CLOCK_CDEX_SOURCE0 (1 << 0)
+#define CLOCK_CDEX_SOURCE1 (1 << 1)
+#define CLOCK_CDEX_SPI (1 << 2)
+#define CLOCK_CDEX_OWM (1 << 3)
+#define CLOCK_CDEX_PWM0 (1 << 4)
+#define CLOCK_CDEX_PWM1 (1 << 5)
+#define CLOCK_CDEX_LED0 (1 << 6)
+#define CLOCK_CDEX_LED1 (1 << 7)
+#define CLOCK_CDEX_LED2 (1 << 8)
+
+#define CLOCK_CDEX_SD_HOST (1 << 9) /* R/W: SD host clock source 24.576M/12.288M */
+#define CLOCK_CDEX_SD_BUS (1 << 10) /* R/W: SD bus clock source control 24.576M/12.288M */
+#define CLOCK_CDEX_SMBUS (1 << 11)
+#define CLOCK_CDEX_CONTROL_CX (1 << 12)
+
+#define CLOCK_CDEX_EX0 (1 << 13) /* R/W: 32.768 kHz crystal */
+#define CLOCK_CDEX_EX1 (1 << 14) /* R/W: 24.576 MHz crystal */
+
+#define CLOCK_SEL_SD_HCLK_SEL (1 << 0) /* R/W: SDIO host clock select - 1: 24.576 Mhz, 0: 12.288 MHz */
+#define CLOCK_SEL_SD_BCLK_SEL (1 << 1) /* R/W: SDIO bus clock select - 1: 24.576 MHz, 0: 12.288 MHz */
+#define CLOCK_SEL_CX (1 << 2) /* R/W: INT clock source control (32.768 kHz) */
+
+
+#define _IPAQ_ASIC3_INTR_Base 0x0B00
+
+#define _IPAQ_ASIC3_INTR_IntMask 0x00 /* Interrupt mask control */
+#define _IPAQ_ASIC3_INTR_PIntStat 0x04 /* Peripheral interrupt status */
+#define _IPAQ_ASIC3_INTR_IntCPS 0x08 /* Interrupt timer clock pre-scale */
+#define _IPAQ_ASIC3_INTR_IntTBS 0x0c /* Interrupt timer set */
+
+#define IPAQ_ASIC3_INTR_IntMask(_b) IPAQ_ASIC3( _b, u8, INTR, IntMask )
+#define IPAQ_ASIC3_INTR_PIntStat(_b) IPAQ_ASIC3( _b, u8, INTR, PIntStat )
+#define IPAQ_ASIC3_INTR_IntCPS(_b) IPAQ_ASIC3( _b, u8, INTR, IntCPS )
+#define IPAQ_ASIC3_INTR_IntTBS(_b) IPAQ_ASIC3( _b, u16, INTR, IntTBS )
+
+#define ASIC3_INTMASK_GINTMASK (1 << 0) /* Global interrupt mask 1:enable */
+#define ASIC3_INTMASK_GINTEL (1 << 1) /* 1: rising edge, 0: hi level */
+#define ASIC3_INTMASK_MASK0 (1 << 2)
+#define ASIC3_INTMASK_MASK1 (1 << 3)
+#define ASIC3_INTMASK_MASK2 (1 << 4)
+#define ASIC3_INTMASK_MASK3 (1 << 5)
+#define ASIC3_INTMASK_MASK4 (1 << 6)
+#define ASIC3_INTMASK_MASK5 (1 << 7)
+
+#define ASIC3_INTR_PERIPHERAL_A (1 << 0)
+#define ASIC3_INTR_PERIPHERAL_B (1 << 1)
+#define ASIC3_INTR_PERIPHERAL_C (1 << 2)
+#define ASIC3_INTR_PERIPHERAL_D (1 << 3)
+#define ASIC3_INTR_LED0 (1 << 4)
+#define ASIC3_INTR_LED1 (1 << 5)
+#define ASIC3_INTR_LED2 (1 << 6)
+#define ASIC3_INTR_SPI (1 << 7)
+#define ASIC3_INTR_SMBUS (1 << 8)
+#define ASIC3_INTR_OWM (1 << 9)
+
+#define ASIC3_INTR_CPS(x) ((x)&0x0f) /* 4 bits, max 14 */
+#define ASIC3_INTR_CPS_SET ( 1 << 4 ) /* Time base enable */
+
+
+/* Basic control of the SD ASIC */
+#define _IPAQ_ASIC3_SDHWCTRL_Base 0x0E00
+
+#define _IPAQ_ASIC3_SDHWCTRL_SDConf 0x00
+#define IPAQ_ASIC3_SDHWCTRL_SDConf(_b) IPAQ_ASIC3( _b, u8, SDHWCTRL, SDConf )
+
+#define ASIC3_SDHWCTRL_SUSPEND (1 << 0) /* 1=suspend all SD operations */
+#define ASIC3_SDHWCTRL_CLKSEL (1 << 1) /* 1=SDICK, 0=HCLK */
+#define ASIC3_SDHWCTRL_PCLR (1 << 2) /* All registers of SDIO cleared */
+#define ASIC3_SDHWCTRL_LEVCD (1 << 3) /* Level of SD card detection: 1:high, 0:low */
+#define ASIC3_SDHWCTRL_LEVWP (1 << 4) /* Level of SD card write protection: 1=low, 0=high */
+#define ASIC3_SDHWCTRL_SDLED (1 << 5) /* SD card LED signal 1=enable, 0=disable */
+#define ASIC3_SDHWCTRL_SDPWR (1 << 6) /* SD card power supply control 1=enable */
+
+
+/* This is a pointer to an array of 12 u32 values - but only the lower 2 bytes matter */
+/* Use it as "IPAQ_ASIC3_HWPROTECT_ARRAY[x]" */
+
+#define _IPAQ_ASIC3_HWPROTECT_Base 0x1000
+#define IPAQ_ASIC3_HWPROTECT_ARRAY ((volatile u32*)(_IPAQ_ASIC3_Base + _IPAQ_ASIC3_HWPROTECT_Base))
+#define HWPROTECT_ARRAY_LEN 12
+#define HWPROTECT_ARRAY_VALUES {0x4854,0x432d,0x5344,0x494f,0x2050,0x2f4e,0x3a33,0x3048,0x3830,0x3032,0x382d,0x3030}
+
+
+#define _IPAQ_ASIC3_EXTCF_Base 0x1100
+
+#define _IPAQ_ASIC3_EXTCF_Select 0x00
+#define _IPAQ_ASIC3_EXTCF_Reset 0x04
+
+#define IPAQ_ASIC3_EXTCF_Select(_b) IPAQ_ASIC3( _b, u16, EXTCF, Select )
+#define IPAQ_ASIC3_EXTCF_Reset(_b) IPAQ_ASIC3( _b, u16, EXTCF, Reset )
+
+#define ASIC3_EXTCF_SMOD0 (1 << 0) /* slot number of mode 0 */
+#define ASIC3_EXTCF_SMOD1 (1 << 1) /* slot number of mode 1 */
+#define ASIC3_EXTCF_SMOD2 (1 << 2) /* slot number of mode 2 */
+#define ASIC3_EXTCF_OWM_EN (1 << 4) /* enable onewire module */
+#define ASIC3_EXTCF_OWM_SMB (1 << 5) /* OWM bus selection */
+#define ASIC3_EXTCF_OWM_RESET (1 << 6) /* undocumented, used by OWM and CF */
+#define ASIC3_EXTCF_CF0_SLEEP_MODE (1 << 7) /* CF0 sleep state control */
+#define ASIC3_EXTCF_CF1_SLEEP_MODE (1 << 8) /* CF1 sleep state control */
+#define ASIC3_EXTCF_CF0_PWAIT_EN (1 << 10) /* CF0 PWAIT_n control */
+#define ASIC3_EXTCF_CF1_PWAIT_EN (1 << 11) /* CF1 PWAIT_n control */
+#define ASIC3_EXTCF_CF0_BUF_EN (1 << 12) /* CF0 buffer control */
+#define ASIC3_EXTCF_CF1_BUF_EN (1 << 13) /* CF1 buffer control */
+#define ASIC3_EXTCF_SD_MEM_ENABLE (1 << 14)
+#define ASIC3_EXTCF_CF_SLEEP (1 << 15) /* CF sleep mode control */
+
+/*****************************************************************************
+ * The Onewire interface registers
+ *
+ * OWM_CMD
+ * OWM_DAT
+ * OWM_INTR
+ * OWM_INTEN
+ * OWM_CLKDIV
+ *
+ *****************************************************************************/
+
+#define _IPAQ_ASIC3_OWM_Base 0xC00
+
+#define _IPAQ_ASIC3_OWM_CMD 0x00
+#define _IPAQ_ASIC3_OWM_DAT 0x04
+#define _IPAQ_ASIC3_OWM_INTR 0x08
+#define _IPAQ_ASIC3_OWM_INTEN 0x0C
+#define _IPAQ_ASIC3_OWM_CLKDIV 0x10
+
+#define ASIC3_OWM_CMD_ONEWR (1 << 0)
+#define ASIC3_OWM_CMD_SRA (1 << 1)
+#define ASIC3_OWM_CMD_DQO (1 << 2)
+#define ASIC3_OWM_CMD_DQI (1 << 3)
+
+#define ASIC3_OWM_INTR_PD (1 << 0)
+#define ASIC3_OWM_INTR_PDR (1 << 1)
+#define ASIC3_OWM_INTR_TBE (1 << 2)
+#define ASIC3_OWM_INTR_TEMP (1 << 3)
+#define ASIC3_OWM_INTR_RBF (1 << 4)
+
+#define ASIC3_OWM_INTEN_EPD (1 << 0)
+#define ASIC3_OWM_INTEN_IAS (1 << 1)
+#define ASIC3_OWM_INTEN_ETBE (1 << 2)
+#define ASIC3_OWM_INTEN_ETMT (1 << 3)
+#define ASIC3_OWM_INTEN_ERBF (1 << 4)
+
+#define ASIC3_OWM_CLKDIV_PRE (3 << 0) /* two bits wide at bit position 0 */
+#define ASIC3_OWM_CLKDIV_DIV (7 << 2) /* 3 bits wide at bit position 2 */
+
+
+/*****************************************************************************
+ * The SD configuration registers are at a completely different location
+ * in memory. They are divided into three sets of registers:
+ *
+ * SD_CONFIG Core configuration register
+ * SD_CTRL Control registers for SD operations
+ * SDIO_CTRL Control registers for SDIO operations
+ *
+ *****************************************************************************/
+
+#define IPAQ_ASIC3_SD_CONFIG(_b, s,x) \
+ (*((volatile s *) ((_b) + _IPAQ_ASIC3_SD_CONFIG_Base + (_IPAQ_ASIC3_SD_CONFIG_ ## x))))
+
+#define _IPAQ_ASIC3_SD_CONFIG_Base 0x0400 // Assumes 32 bit addressing
+
+#define _IPAQ_ASIC3_SD_CONFIG_Command 0x08 /* R/W: Command */
+#define _IPAQ_ASIC3_SD_CONFIG_Addr0 0x20 /* [9:31] SD Control Register Base Address */
+#define _IPAQ_ASIC3_SD_CONFIG_Addr1 0x24 /* [9:31] SD Control Register Base Address */
+#define _IPAQ_ASIC3_SD_CONFIG_IntPin 0x78 /* R/O: interrupt assigned to pin */
+#define _IPAQ_ASIC3_SD_CONFIG_ClkStop 0x80 /* Set to 0x1f to clock SD controller, 0 otherwise. */
+ /* at 0x82 - Gated Clock Control */
+#define _IPAQ_ASIC3_SD_CONFIG_ClockMode 0x84 /* Control clock of SD controller */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_PinStatus 0x88 /* R/0: read status of SD pins */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_Power1 0x90 /* Power1 - manual power control */
+ /* Power2 is at 0x92 - auto power up after card inserted */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_Power3 0x94 /* auto power down when card removed */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_CardDetect 0x98 /* */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_Slot 0xA0 /* R/O: define support slot number */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk1 0x1E0 /* Could be used for gated clock (don't use) */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk2 0x1E2 /* Could be used for gated clock (don't use) */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_GPIO_OutAndEnable 0x1E8 /* GPIO Output Reg. , at 0x1EA - GPIO Output Enable Reg. */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_GPIO_Status 0x1EC /* GPIO Status Reg. */
+#define _IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk3 0x1F0 /* Bit 1: double buffer/single buffer */
+
+#define IPAQ_ASIC3_SD_CONFIG_Command(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, Command )
+#define IPAQ_ASIC3_SD_CONFIG_Addr0(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, Addr0 )
+#define IPAQ_ASIC3_SD_CONFIG_Addr1(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, Addr1 )
+#define IPAQ_ASIC3_SD_CONFIG_IntPin(_b) IPAQ_ASIC3_SD_CONFIG(_b, u8, IntPin )
+#define IPAQ_ASIC3_SD_CONFIG_ClkStop(_b) IPAQ_ASIC3_SD_CONFIG(_b, u8, ClkStop )
+#define IPAQ_ASIC3_SD_CONFIG_ClockMode(_b) IPAQ_ASIC3_SD_CONFIG(_b, u8, ClockMode )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_PinStatus(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_PinStatus )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_Power1(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_Power1 )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_Power3(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_Power3 )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_CardDetect(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_CardDetect )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_Slot(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_Slot )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk1(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_ExtGateClk1 )
+#define IPAQ_ASIC3_SD_CONFIG_SDHC_ExtGateClk3(_b) IPAQ_ASIC3_SD_CONFIG(_b, u16, SDHC_ExtGateClk3 )
+
+#define SD_CONFIG_
+
+#define SD_CONFIG_COMMAND_MAE (1<<1) /* Memory access enable (set to 1 to access SD Controller) */
+
+#define SD_CONFIG_CLK_ENABLE_ALL 0x1f
+
+#define SD_CONFIG_POWER1_PC_33V 0x0200 /* Set for 3.3 volts */
+#define SD_CONFIG_POWER1_PC_OFF 0x0000 /* Turn off power */
+
+#define SD_CONFIG_CARDDETECTMODE_CLK ((x)&0x3) /* two bits - number of cycles for card detection */
+
+
+#define _IPAQ_ASIC3_SD_CTRL_Base 0x1000
+
+#define IPAQ_ASIC3_SD(_b, s,x) \
+ (*((volatile s *) ((_b) + _IPAQ_ASIC3_SD_CTRL_Base + (_IPAQ_ASIC3_SD_CTRL_ ## x))))
+
+#define _IPAQ_ASIC3_SD_CTRL_Cmd 0x00
+#define _IPAQ_ASIC3_SD_CTRL_Arg0 0x08
+#define _IPAQ_ASIC3_SD_CTRL_Arg1 0x0C
+#define _IPAQ_ASIC3_SD_CTRL_StopInternal 0x10
+#define _IPAQ_ASIC3_SD_CTRL_TransferSectorCount 0x14
+#define _IPAQ_ASIC3_SD_CTRL_Response0 0x18
+#define _IPAQ_ASIC3_SD_CTRL_Response1 0x1C
+#define _IPAQ_ASIC3_SD_CTRL_Response2 0x20
+#define _IPAQ_ASIC3_SD_CTRL_Response3 0x24
+#define _IPAQ_ASIC3_SD_CTRL_Response4 0x28
+#define _IPAQ_ASIC3_SD_CTRL_Response5 0x2C
+#define _IPAQ_ASIC3_SD_CTRL_Response6 0x30
+#define _IPAQ_ASIC3_SD_CTRL_Response7 0x34
+#define _IPAQ_ASIC3_SD_CTRL_CardStatus 0x38
+#define _IPAQ_ASIC3_SD_CTRL_BufferCtrl 0x3C
+#define _IPAQ_ASIC3_SD_CTRL_IntMaskCard 0x40
+#define _IPAQ_ASIC3_SD_CTRL_IntMaskBuffer 0x44
+#define _IPAQ_ASIC3_SD_CTRL_CardClockCtrl 0x48
+#define _IPAQ_ASIC3_SD_CTRL_MemCardXferDataLen 0x4C
+#define _IPAQ_ASIC3_SD_CTRL_MemCardOptionSetup 0x50
+#define _IPAQ_ASIC3_SD_CTRL_ErrorStatus0 0x58
+#define _IPAQ_ASIC3_SD_CTRL_ErrorStatus1 0x5C
+#define _IPAQ_ASIC3_SD_CTRL_DataPort 0x60
+#define _IPAQ_ASIC3_SD_CTRL_TransactionCtrl 0x68
+#define _IPAQ_ASIC3_SD_CTRL_SoftwareReset 0x1C0
+
+#define IPAQ_ASIC3_SD_CTRL_Cmd(_b) IPAQ_ASIC3_SD( _b, u16, Cmd ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Arg0(_b) IPAQ_ASIC3_SD( _b, u16, Arg0 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Arg1(_b) IPAQ_ASIC3_SD( _b, u16, Arg1 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_StopInternal(_b) IPAQ_ASIC3_SD( _b, u16, StopInternal ) /* */
+#define IPAQ_ASIC3_SD_CTRL_TransferSectorCount(_b) IPAQ_ASIC3_SD( _b, u16, TransferSectorCount ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response0(_b) IPAQ_ASIC3_SD( _b, u16, Response0 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response1(_b) IPAQ_ASIC3_SD( _b, u16, Response1 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response2(_b) IPAQ_ASIC3_SD( _b, u16, Response2 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response3(_b) IPAQ_ASIC3_SD( _b, u16, Response3 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response4(_b) IPAQ_ASIC3_SD( _b, u16, Response4 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response5(_b) IPAQ_ASIC3_SD( _b, u16, Response5 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response6(_b) IPAQ_ASIC3_SD( _b, u16, Response6 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_Response7(_b) IPAQ_ASIC3_SD( _b, u16, Response7 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_CardStatus(_b) IPAQ_ASIC3_SD( _b, u16, CardStatus ) /* */
+#define IPAQ_ASIC3_SD_CTRL_BufferCtrl(_b) IPAQ_ASIC3_SD( _b, u16, BufferCtrl ) /* and error status*/
+#define IPAQ_ASIC3_SD_CTRL_IntMaskCard(_b) IPAQ_ASIC3_SD( _b, u16, IntMaskCard ) /* */
+#define IPAQ_ASIC3_SD_CTRL_IntMaskBuffer(_b) IPAQ_ASIC3_SD( _b, u16, IntMaskBuffer ) /* */
+#define IPAQ_ASIC3_SD_CTRL_CardClockCtrl(_b) IPAQ_ASIC3_SD( _b, u16, CardClockCtrl ) /* */
+#define IPAQ_ASIC3_SD_CTRL_MemCardXferDataLen(_b) IPAQ_ASIC3_SD( _b, u16, MemCardXferDataLen ) /* */
+#define IPAQ_ASIC3_SD_CTRL_MemCardOptionSetup(_b) IPAQ_ASIC3_SD( _b, u16, MemCardOptionSetup ) /* */
+#define IPAQ_ASIC3_SD_CTRL_ErrorStatus0(_b) IPAQ_ASIC3_SD( _b, u16, ErrorStatus0 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_ErrorStatus1(_b) IPAQ_ASIC3_SD( _b, u16, ErrorStatus1 ) /* */
+#define IPAQ_ASIC3_SD_CTRL_DataPort(_b) IPAQ_ASIC3_SD( _b, u16, DataPort ) /* */
+#define IPAQ_ASIC3_SD_CTRL_TransactionCtrl(_b) IPAQ_ASIC3_SD( _b, u16, TransactionCtrl ) /* */
+#define IPAQ_ASIC3_SD_CTRL_SoftwareReset(_b) IPAQ_ASIC3_SD( _b, u16, SoftwareReset ) /* */
+
+#define SD_CTRL_SOFTWARE_RESET_CLEAR (1<<0)
+
+#define SD_CTRL_TRANSACTIONCONTROL_SET (1<<8) // 0x0100
+
+#define SD_CTRL_CARDCLOCKCONTROL_FOR_SD_CARD (1<<15)// 0x8000
+#define SD_CTRL_CARDCLOCKCONTROL_ENABLE_CLOCK (1<<8) // 0x0100
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_512 (1<<7) // 0x0080
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_256 (1<<6) // 0x0040
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_128 (1<<5) // 0x0020
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_64 (1<<4) // 0x0010
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_32 (1<<3) // 0x0008
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_16 (1<<2) // 0x0004
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_8 (1<<1) // 0x0002
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_4 (1<<0) // 0x0001
+#define SD_CTRL_CARDCLOCKCONTROL_CLK_DIV_2 (0<<0) // 0x0000
+
+#define MEM_CARD_OPTION_REQUIRED 0x000e
+#define MEM_CARD_OPTION_DATA_RESPONSE_TIMEOUT(x) (((x)&0x0f)<<4) /* Four bits */
+#define MEM_CARD_OPTION_C2_MODULE_NOT_PRESENT (1<<14) // 0x4000
+#define MEM_CARD_OPTION_DATA_XFR_WIDTH_1 (1<<15) // 0x8000
+#define MEM_CARD_OPTION_DATA_XFR_WIDTH_4 (0<<15) //~0x8000
+
+#define SD_CTRL_COMMAND_INDEX(x) ((x)&0x3f) /* 0=CMD0, 1=CMD1, ..., 63=CMD63 */
+#define SD_CTRL_COMMAND_TYPE_CMD (0 << 6)
+#define SD_CTRL_COMMAND_TYPE_ACMD (1 << 6)
+#define SD_CTRL_COMMAND_TYPE_AUTHENTICATION (2 << 6)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_NORMAL (0 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1 (4 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R1B (5 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R2 (6 << 8)
+#define SD_CTRL_COMMAND_RESPONSE_TYPE_EXT_R3 (7 << 8)
+#define SD_CTRL_COMMAND_DATA_PRESENT (1 << 11)
+#define SD_CTRL_COMMAND_TRANSFER_READ (1 << 12)
+#define SD_CTRL_COMMAND_TRANSFER_WRITE (0 << 12)
+#define SD_CTRL_COMMAND_MULTI_BLOCK (1 << 13)
+#define SD_CTRL_COMMAND_SECURITY_CMD (1 << 14)
+
+#define SD_CTRL_STOP_INTERNAL_ISSSUE_CMD12 (1 << 0)
+#define SD_CTRL_STOP_INTERNAL_AUTO_ISSUE_CMD12 (1 << 8)
+
+#define SD_CTRL_CARDSTATUS_RESPONSE_END (1 << 0)
+#define SD_CTRL_CARDSTATUS_RW_END (1 << 2)
+#define SD_CTRL_CARDSTATUS_CARD_REMOVED_0 (1 << 3)
+#define SD_CTRL_CARDSTATUS_CARD_INSERTED_0 (1 << 4)
+#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_0 (1 << 5)
+#define SD_CTRL_CARDSTATUS_WRITE_PROTECT (1 << 7)
+#define SD_CTRL_CARDSTATUS_CARD_REMOVED_3 (1 << 8)
+#define SD_CTRL_CARDSTATUS_CARD_INSERTED_3 (1 << 9)
+#define SD_CTRL_CARDSTATUS_SIGNAL_STATE_PRESENT_3 (1 << 10)
+
+#define SD_CTRL_BUFFERSTATUS_CMD_INDEX_ERROR (1 << 0) // 0x0001
+#define SD_CTRL_BUFFERSTATUS_CRC_ERROR (1 << 1) // 0x0002
+#define SD_CTRL_BUFFERSTATUS_STOP_BIT_END_ERROR (1 << 2) // 0x0004
+#define SD_CTRL_BUFFERSTATUS_DATA_TIMEOUT (1 << 3) // 0x0008
+#define SD_CTRL_BUFFERSTATUS_BUFFER_OVERFLOW (1 << 4) // 0x0010
+#define SD_CTRL_BUFFERSTATUS_BUFFER_UNDERFLOW (1 << 5) // 0x0020
+#define SD_CTRL_BUFFERSTATUS_CMD_TIMEOUT (1 << 6) // 0x0040
+#define SD_CTRL_BUFFERSTATUS_UNK7 (1 << 7) // 0x0080
+#define SD_CTRL_BUFFERSTATUS_BUFFER_READ_ENABLE (1 << 8) // 0x0100
+#define SD_CTRL_BUFFERSTATUS_BUFFER_WRITE_ENABLE (1 << 9) // 0x0200
+#define SD_CTRL_BUFFERSTATUS_ILLEGAL_FUNCTION (1 << 13)// 0x2000
+#define SD_CTRL_BUFFERSTATUS_CMD_BUSY (1 << 14)// 0x4000
+#define SD_CTRL_BUFFERSTATUS_ILLEGAL_ACCESS (1 << 15)// 0x8000
+
+#define SD_CTRL_INTMASKCARD_RESPONSE_END (1 << 0) // 0x0001
+#define SD_CTRL_INTMASKCARD_RW_END (1 << 2) // 0x0004
+#define SD_CTRL_INTMASKCARD_CARD_REMOVED_0 (1 << 3) // 0x0008
+#define SD_CTRL_INTMASKCARD_CARD_INSERTED_0 (1 << 4) // 0x0010
+#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_0 (1 << 5) // 0x0020
+#define SD_CTRL_INTMASKCARD_UNK6 (1 << 6) // 0x0040
+#define SD_CTRL_INTMASKCARD_WRITE_PROTECT (1 << 7) // 0x0080
+#define SD_CTRL_INTMASKCARD_CARD_REMOVED_3 (1 << 8) // 0x0100
+#define SD_CTRL_INTMASKCARD_CARD_INSERTED_3 (1 << 9) // 0x0200
+#define SD_CTRL_INTMASKCARD_SIGNAL_STATE_PRESENT_3 (1 << 10)// 0x0400
+
+#define SD_CTRL_INTMASKBUFFER_CMD_INDEX_ERROR (1 << 0) // 0x0001
+#define SD_CTRL_INTMASKBUFFER_CRC_ERROR (1 << 1) // 0x0002
+#define SD_CTRL_INTMASKBUFFER_STOP_BIT_END_ERROR (1 << 2) // 0x0004
+#define SD_CTRL_INTMASKBUFFER_DATA_TIMEOUT (1 << 3) // 0x0008
+#define SD_CTRL_INTMASKBUFFER_BUFFER_OVERFLOW (1 << 4) // 0x0010
+#define SD_CTRL_INTMASKBUFFER_BUFFER_UNDERFLOW (1 << 5) // 0x0020
+#define SD_CTRL_INTMASKBUFFER_CMD_TIMEOUT (1 << 6) // 0x0040
+#define SD_CTRL_INTMASKBUFFER_UNK7 (1 << 7) // 0x0080
+#define SD_CTRL_INTMASKBUFFER_BUFFER_READ_ENABLE (1 << 8) // 0x0100
+#define SD_CTRL_INTMASKBUFFER_BUFFER_WRITE_ENABLE (1 << 9) // 0x0200
+#define SD_CTRL_INTMASKBUFFER_ILLEGAL_FUNCTION (1 << 13)// 0x2000
+#define SD_CTRL_INTMASKBUFFER_CMD_BUSY (1 << 14)// 0x4000
+#define SD_CTRL_INTMASKBUFFER_ILLEGAL_ACCESS (1 << 15)// 0x8000
+
+#define SD_CTRL_DETAIL0_RESPONSE_CMD_ERROR (1 << 0) // 0x0001
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_NON_CMD12 (1 << 2) // 0x0004
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_RESPONSE_CMD12 (1 << 3) // 0x0008
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_READ_DATA (1 << 4) // 0x0010
+#define SD_CTRL_DETAIL0_END_BIT_ERROR_FOR_WRITE_CRC_STATUS (1 << 5) // 0x0020
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_NON_CMD12 (1 << 8) // 0x0100
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_RESPONSE_CMD12 (1 << 9) // 0x0200
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_READ_DATA (1 << 10)// 0x0400
+#define SD_CTRL_DETAIL0_CRC_ERROR_FOR_WRITE_CMD (1 << 11)// 0x0800
+
+#define SD_CTRL_DETAIL1_NO_CMD_RESPONSE (1 << 0) // 0x0001
+#define SD_CTRL_DETAIL1_TIMEOUT_READ_DATA (1 << 4) // 0x0010
+#define SD_CTRL_DETAIL1_TIMEOUT_CRS_STATUS (1 << 5) // 0x0020
+#define SD_CTRL_DETAIL1_TIMEOUT_CRC_BUSY (1 << 6) // 0x0040
+
+#define _IPAQ_ASIC3_SDIO_CTRL_Base 0x1200
+
+#define IPAQ_ASIC3_SDIO(_b, s,x) \
+ (*((volatile s *) ((_b) + _IPAQ_ASIC3_SDIO_CTRL_Base + (_IPAQ_ASIC3_SDIO_CTRL_ ## x))))
+
+#define _IPAQ_ASIC3_SDIO_CTRL_Cmd 0x00
+#define _IPAQ_ASIC3_SDIO_CTRL_CardPortSel 0x04
+#define _IPAQ_ASIC3_SDIO_CTRL_Arg0 0x08
+#define _IPAQ_ASIC3_SDIO_CTRL_Arg1 0x0C
+#define _IPAQ_ASIC3_SDIO_CTRL_TransferBlockCount 0x14
+#define _IPAQ_ASIC3_SDIO_CTRL_Response0 0x18
+#define _IPAQ_ASIC3_SDIO_CTRL_Response1 0x1C
+#define _IPAQ_ASIC3_SDIO_CTRL_Response2 0x20
+#define _IPAQ_ASIC3_SDIO_CTRL_Response3 0x24
+#define _IPAQ_ASIC3_SDIO_CTRL_Response4 0x28
+#define _IPAQ_ASIC3_SDIO_CTRL_Response5 0x2C
+#define _IPAQ_ASIC3_SDIO_CTRL_Response6 0x30
+#define _IPAQ_ASIC3_SDIO_CTRL_Response7 0x34
+#define _IPAQ_ASIC3_SDIO_CTRL_CardStatus 0x38
+#define _IPAQ_ASIC3_SDIO_CTRL_BufferCtrl 0x3C
+#define _IPAQ_ASIC3_SDIO_CTRL_IntMaskCard 0x40
+#define _IPAQ_ASIC3_SDIO_CTRL_IntMaskBuffer 0x44
+#define _IPAQ_ASIC3_SDIO_CTRL_CardXferDataLen 0x4C
+#define _IPAQ_ASIC3_SDIO_CTRL_CardOptionSetup 0x50
+#define _IPAQ_ASIC3_SDIO_CTRL_ErrorStatus0 0x54
+#define _IPAQ_ASIC3_SDIO_CTRL_ErrorStatus1 0x58
+#define _IPAQ_ASIC3_SDIO_CTRL_DataPort 0x60
+#define _IPAQ_ASIC3_SDIO_CTRL_TransactionCtrl 0x68
+#define _IPAQ_ASIC3_SDIO_CTRL_CardIntCtrl 0x6C
+#define _IPAQ_ASIC3_SDIO_CTRL_ClocknWaitCtrl 0x70
+#define _IPAQ_ASIC3_SDIO_CTRL_HostInformation 0x74
+#define _IPAQ_ASIC3_SDIO_CTRL_ErrorCtrl 0x78
+#define _IPAQ_ASIC3_SDIO_CTRL_LEDCtrl 0x7C
+#define _IPAQ_ASIC3_SDIO_CTRL_SoftwareReset 0x1C0
+
+#define IPAQ_ASIC3_SDIO_CTRL_Cmd(_b) IPAQ_ASIC3_SDIO( _b, u16, Cmd ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardPortSel(_b) IPAQ_ASIC3_SDIO( _b, u16, CardPortSel ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Arg0(_b) IPAQ_ASIC3_SDIO( _b, u16, Arg0 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Arg1(_b) IPAQ_ASIC3_SDIO( _b, u16, Arg1 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_TransferBlockCount(_b) IPAQ_ASIC3_SDIO( _b, u16, TransferBlockCount ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response0(_b) IPAQ_ASIC3_SDIO( _b, u16, Response0 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response1(_b) IPAQ_ASIC3_SDIO( _b, u16, Response1 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response2(_b) IPAQ_ASIC3_SDIO( _b, u16, Response2 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response3(_b) IPAQ_ASIC3_SDIO( _b, u16, Response3 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response4(_b) IPAQ_ASIC3_SDIO( _b, u16, Response4 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response5(_b) IPAQ_ASIC3_SDIO( _b, u16, Response5 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response6(_b) IPAQ_ASIC3_SDIO( _b, u16, Response6 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_Response7(_b) IPAQ_ASIC3_SDIO( _b, u16, Response7 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardStatus(_b) IPAQ_ASIC3_SDIO( _b, u16, CardStatus ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_BufferCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, BufferCtrl ) /* and error status*/
+#define IPAQ_ASIC3_SDIO_CTRL_IntMaskCard(_b) IPAQ_ASIC3_SDIO( _b, u16, IntMaskCard ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_IntMaskBuffer(_b) IPAQ_ASIC3_SDIO( _b, u16, IntMaskBuffer ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardXferDataLen(_b) IPAQ_ASIC3_SDIO( _b, u16, CardXferDataLen ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardOptionSetup(_b) IPAQ_ASIC3_SDIO( _b, u16, CardOptionSetup ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ErrorStatus0(_b) IPAQ_ASIC3_SDIO( _b, u16, ErrorStatus0 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ErrorStatus1(_b) IPAQ_ASIC3_SDIO( _b, u16, ErrorStatus1 ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_DataPort(_b) IPAQ_ASIC3_SDIO( _b, u16, DataPort ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_TransactionCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, TransactionCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_CardIntCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, CardIntCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ClocknWaitCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, ClocknWaitCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_HostInformation(_b) IPAQ_ASIC3_SDIO( _b, u16, HostInformation ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_ErrorCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, ErrorCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_LEDCtrl(_b) IPAQ_ASIC3_SDIO( _b, u16, LEDCtrl ) /* */
+#define IPAQ_ASIC3_SDIO_CTRL_SoftwareReset(_b) IPAQ_ASIC3_SDIO( _b, u16, SoftwareReset ) /* */
+
+#define IPAQ_ASIC3_MAP_SIZE 0x2000
+
+#endif


--
Best regards,
Paul mailto:[email protected]


2007-05-01 06:56:47

by Andrew Morton

[permalink] [raw]
Subject: Re: [RFC, PATCH 2/4] SoC base drivers: ASIC3 SoC hardware definitions

On Tue, 1 May 2007 08:08:39 +0300 Paul Sokolovsky <[email protected]> wrote:

> Hello linux-kernel,
>
> Intro: This is a header with hardware definitions for ASIC3 chip,
> contributed by HP/Compaq. It is provided as-is, as a vendor-originated
> header.
> ---------
>
> ipaq-asic3.h: Hardware definitions for ASIC3 chip, found in ~12
> handheld devices from HP/Compaq and HTC.
>
> Signed-off-by: Paul Sokolovsky <[email protected]>
>
>
> include/asm-arm/hardware/ipaq-asic3.h | 609 +++++++++++++++++++++++++++++++++
> 1 files changed, 609 insertions(+), 0 deletions(-)
>
> diff --git a/include/asm-arm/hardware/ipaq-asic3.h b/include/asm-arm/hardware/ipaq-asic3.h
> new file mode 100644
> index 0000000..789bb16
> --- /dev/null
> +++ b/include/asm-arm/hardware/ipaq-asic3.h
> @@ -0,0 +1,609 @@
> +/*
> + *
> + * Definitions for the HTC ASIC3 chip found in several handheld devices
> + *
> + * Copyright 2001 Compaq Computer Corporation.
> + *
> + * Use consistent with the GNU GPL is permitted,
> + * provided that this copyright notice is
> + * preserved in its entirety in all copies and derived works.
> + *
> + * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
> + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
> + * FITNESS FOR ANY PARTICULAR PURPOSE.
> + *
> + * Author: Andrew Christian
> + *
> + */
> +
> +#ifndef IPAQ_ASIC3_H
> +#define IPAQ_ASIC3_H
> +
> +/****************************************************/
> +/* IPAQ, ASIC #3, replaces ASIC #1 */
> +
> +#define IPAQ_ASIC3(_b,s,x,y) \
> + (*((volatile s *) (_b + _IPAQ_ASIC3_ ## x ## _Base + (_IPAQ_ASIC3_ ## x ## _ ## y))))
> +#define IPAQ_ASIC3_N(_b,s,x,y,z) \
> + (*((volatile s *) (_b + _IPAQ_ASIC3_ ## x ## _ ## y ## _Base + (_IPAQ_ASIC3_ ## x ## _ ## z))))
> +
> +#define IPAQ_ASIC3_GPIO(_b,s,x,y) \
> + (*((volatile s *) (_b + _IPAQ_ASIC3_GPIO_ ## x ## _Base + (_IPAQ_ASIC3_GPIO_ ## y))))
> +
> +#define IPAQ_ASIC3_OFFSET(x,y) (_IPAQ_ASIC3_ ## x ## _Base + _IPAQ_ASIC3_ ## x ## _ ## y)
> +#define IPAQ_ASIC3_GPIO_OFFSET(x,y) (_IPAQ_ASIC3_GPIO_ ## x ## _Base + _IPAQ_ASIC3_GPIO_ ## y)

Oh my eyes. What are these doing?

The volatiles are a worry - volatile is said to be basically-always-wrong
in-kernel, although we've never managed to document why, and i386
cheerfully uses it in readb() and friends.

Perhaps if you can describe presisely what's going on here, alternatives
might be suggested.


2007-05-01 10:23:59

by Alan

[permalink] [raw]
Subject: Re: [RFC, PATCH 2/4] SoC base drivers: ASIC3 SoC hardware definitions

> > + * Copyright 2001 Compaq Computer Corporation.
> > + *
> > + * Use consistent with the GNU GPL is permitted,
> > + * provided that this copyright notice is
> > + * preserved in its entirety in all copies and derived works.
> > + *
> > + * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
> > + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
> > + * FITNESS FOR ANY PARTICULAR PURPOSE.

This doesn't appear to be self consistent or GPL compatible. Any binary
will be a derivative work and will not contain the copyright notice.

Alan

2007-05-01 12:04:24

by Paul Sokolovsky

[permalink] [raw]
Subject: Re: [RFC, PATCH 2/4] SoC base drivers: ASIC3 SoC hardware definitions

Hello Alan,

Tuesday, May 1, 2007, 1:27:51 PM, you wrote:

>> > + * Copyright 2001 Compaq Computer Corporation.
>> > + *
>> > + * Use consistent with the GNU GPL is permitted,
>> > + * provided that this copyright notice is
>> > + * preserved in its entirety in all copies and derived works.
>> > + *
>> > + * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
>> > + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
>> > + * FITNESS FOR ANY PARTICULAR PURPOSE.

> This doesn't appear to be self consistent or GPL compatible. Any binary
> will be a derivative work and will not contain the copyright notice.

Well, this is one of those hard questions... Fortunately,
people who worked on this and were Compaq employees are reachable, so
I contacted Jamie Hicks, who is one of the authors of iPaq ports,
regarding solution for this. Jamie, would it be possible to leave
Compaq and other copyright notices, and Compaq disclaimer intact,
but replace following paragraph:

> + * Use consistent with the GNU GPL is permitted,
> + * provided that this copyright notice is
> + * preserved in its entirety in all copies and derived works.

With more common wording as appears in kernel sources:

> This program is free software; you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation; either version 2 of the License, or
> (at your option) any later version.

(or GPL2 wording, or verbose wording, whatever you see fit)

Thanks!

> Alan


--
Best regards,
Paul mailto:[email protected]

2007-05-01 12:41:42

by Jamey Hicks

[permalink] [raw]
Subject: Re: [RFC, PATCH 2/4] SoC base drivers: ASIC3 SoC hardware definitions

Paul Sokolovsky wrote:
> Hello Alan,
>
> Tuesday, May 1, 2007, 1:27:51 PM, you wrote:
>
>
>>>> + * Copyright 2001 Compaq Computer Corporation.
>>>> + *
>>>> + * Use consistent with the GNU GPL is permitted,
>>>> + * provided that this copyright notice is
>>>> + * preserved in its entirety in all copies and derived works.
>>>> + *
>>>> + * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
>>>> + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
>>>> + * FITNESS FOR ANY PARTICULAR PURPOSE.
>>>>
>
>
>> This doesn't appear to be self consistent or GPL compatible. Any binary
>> will be a derivative work and will not contain the copyright notice.
>>
>
> Well, this is one of those hard questions... Fortunately,
> people who worked on this and were Compaq employees are reachable, so
> I contacted Jamie Hicks, who is one of the authors of iPaq ports,
> regarding solution for this. Jamie, would it be possible to leave
> Compaq and other copyright notices, and Compaq disclaimer intact,
> but replace following paragraph:
>
>
>> + * Use consistent with the GNU GPL is permitted,
>> + * provided that this copyright notice is
>> + * preserved in its entirety in all copies and derived works.
>>
>
> With more common wording as appears in kernel sources:
>
>
>> This program is free software; you can redistribute it and/or modify
>> it under the terms of the GNU General Public License as published by
>> the Free Software Foundation; either version 2 of the License, or
>> (at your option) any later version.
>>
>
> (or GPL2 wording, or verbose wording, whatever you see fit)
>
> Thanks!
>
The intent of the vague wording was to have the copyright notice and
Compaq disclaimer of warranties preserved in the source code, not in
binaries, but it is definitely ambiguous. As I understand it, copyright
law says the copyright notices need to be preserved in source code, so
that part of the statement is redundant, and GPL has its own warrantee
disclaimer, so I think the standard wording is just fine. I approve
changing to the more standard GPL wording used in the kernel sources in
order to make this acceptable into the kernel.org tree.

Jamey Hicks

2007-05-08 19:11:25

by Randy Dunlap

[permalink] [raw]
Subject: [RFC/PATCH] doc: volatile considered evil

On Mon, 30 Apr 2007 23:56:42 -0700 Andrew Morton wrote:

> Oh my eyes. What are these doing?
>
> The volatiles are a worry - volatile is said to be basically-always-wrong
> in-kernel, although we've never managed to document why, and i386
> cheerfully uses it in readb() and friends.
>
> Perhaps if you can describe presisely what's going on here, alternatives
> might be suggested.

[well, can be turned into a patch]

Here are some 'volatile' comments from Linus, extracted from
several emails in at least 2 threads.

If this is close to useful, we can add it to Documentation/.

===============================================================

***** "volatile" considered useless and evil: Just Say NO! *****

Do not use the C-language "volatile" keyword
(extracted from lkml emails from Linus)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[Comment about a patch:]

> Also made all the relevant mce_log fields volatile for further safety.

I refuse to apply this part.

If the memory barriers are right, then the "volatile" doesn't matter.

And if the memory barriers aren't right, then "volatile" doesn't help.

Using "volatile" in data structures is basically _always_ a bug.

The only acceptable uses for "volatile" are:

- in _code_, i.e., for things like the definition of "readb()" etc, where we
use it to force a particular access.
- with inline asms
- on "jiffies", for stupid legacy reasons

Basically, a volatile on a data structure can NEVER be right. If it makes
a difference, it's a sign of improper locking.

And the reason I refuse to apply that part of the patch is that anybody
who even _thinks_ that they make a difference is horribly and utterly
confused, and doesn't understand locking.

So please _never_ use them like this.


> mce_log is fully lockless - it deals with machine checks which act like NMIs.
> That is it's problem.
>
> In theory the memory barriers should be sufficient, the volatiles are
> just an additional safety net to make it clear to humans/compiler these memory
> areas can change any time.

If the memory barriers aren't sufficient, the volatiles are useless. If
the memory barriers _are_ sufficient, the volatiles are useless.

See? They're useless.

The only thing they do is

- potentially make the compiler generate worse code for no reason (the
"no reason" being that if there aren't any barriers in between, the
compiler _should_ merge accesses)

- make some people _believe_ that that compiler does something "right".

The first point doesn't much matter. The second point matters a LOT.

Anybody who thinks "volatile" matters is WRONG. As such, a "volatile" is
anti-documentation - it makes people think that something is true that is
NOT true.

In other words, volatile on data structures is _evil_, because it instills
the wrong kind of beliefs in people. "volatility" is not a data structure
issue. It's a matter of the _code_ working on the data structure.


"volatile" really _is_ misdesigned. The semantics of it are so unclear as
to be totally useless. The only thing "volatile" can ever do is generate
worse code, WITH NO UPSIDES.

Historically (and from the standpoint of the C standard), the definition
of "volatile" is that any access is "visible" in the machine, and it
really kind of makes sense for hardware accesses, except these days
hardware accesses have other rules that are _not_ covered by "volatile",
so you can't actually use them for that.

And for accesses that have some software rules (i.e., not IO devices etc),
the rules for "volatile" are too vague to be useful.

So if you actually have rules about how to access a particular piece of
memory, just make those rules _explicit_. Use the real rules. Not
volatile, because volatile will always do the wrong thing.

Also, more importantly, "volatile" is on the wrong _part_ of the whole
system. In C, it's "data" that is volatile, but that is insane. Data
isn't volatile - _accesses_ are volatile. So it may make sense to say
"make this particular _access_ be careful", but not "make all accesses to
this data use some random strategy".

So the only thing "volatile" is potentially useful for is:

- actual accessor functions can use it in a _cast_ to make one particular
access follow the rules of "don't cache this one dereference". That is
useful as part of a _bigger_ set of rules about that access (i.e., it
might be the internal implementation of a "readb()", for example).

- for "random number generation" data locations, where you literally
don't _have_ any rules except "it's a random number". The only really
valid example of this is the "jiffy" timer tick.

Any other use of "volatile" is almost certainly a bug, or just useless.

Side note: it's also totally possible that a volatiles _hides_ a bug, i.e.,
removing the volatile ends up having bad effects, but that's because the
software itself isn't actually following the rules (or, more commonly, the
rules are broken, and somebody added "volatile" to hide the problem).

It's a bug if the volatile means that you don't follow the proper protocol
for accessing the data, and it's useless (and generally generates worse
code) if you already do.

So just say NO! to volatile except under the above circumstances.



[from another email thread:]

I suspect we should just face up to the fact that:

(a) "volatile" on kernel data is basically always a bug, and you should
use locking. "volatile" doesn't help anything at all with memory
ordering and friends, so it's insane to think it "solves" anything on
its own.
(b) on "iomem" pointers it does make sense, but those need special
accessor functions _anyway_, so things like test_bit() wouldn't work
on them.
(c) if you spin on a value [that's] changing, you should use "cpu_relax()" or
"barrier()" anyway, which will force gcc to re-load any values from
memory over the loop.

2007-05-08 19:19:26

by David Rientjes

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, 8 May 2007, Randy Dunlap wrote:

> [well, can be turned into a patch]
>
> Here are some 'volatile' comments from Linus, extracted from
> several emails in at least 2 threads.
>
> If this is close to useful, we can add it to Documentation/.
>
> ===============================================================
>
> ***** "volatile" considered useless and evil: Just Say NO! *****
>
> Do not use the C-language "volatile" keyword
> (extracted from lkml emails from Linus)
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>

Since 'volatile' has two different semantics depending on the context in
which it is used, this warning should be appended to include the fact that
it is legitimate to use for inline assembly.

2007-05-08 20:00:56

by Krzysztof Halasa

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

David Rientjes <[email protected]> writes:

> Since 'volatile' has two different semantics depending on the context in
> which it is used, this warning should be appended to include the fact that
> it is legitimate to use for inline assembly.

I think it hasn't two semantics, it's like arguing that char has two
semantics.

Volatile does one thing - prohibits C compiler from optimizing
accesses to the variable. Either with (volatile *) casts and with
volatile var;

Linus is right in that volatile != direct access to the hardware
and direct sync between all CPUs. Yes, most uses in high level code
are probably bugs. OTOH, there are other uses where optimizing must
be prohibited. It doesn't matter which form
is used, in fact
volatile type name;
name
is equivalent to:
type name;
*(volatile type *)&name;
At least as long as "volatile" keyword is concerned.
--
Krzysztof Halasa

2007-05-08 20:08:05

by Satyam Sharma

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On 5/8/07, Randy Dunlap <[email protected]> wrote:
> On Mon, 30 Apr 2007 23:56:42 -0700 Andrew Morton wrote:
>
> > Oh my eyes. What are these doing?
> >
> > The volatiles are a worry - volatile is said to be basically-always-wrong
> > in-kernel, although we've never managed to document why, and i386
> > cheerfully uses it in readb() and friends.
> >
> > Perhaps if you can describe presisely what's going on here, alternatives
> > might be suggested.
>
> [well, can be turned into a patch]
>
> Here are some 'volatile' comments from Linus, extracted from
> several emails in at least 2 threads.
>
> If this is close to useful, we can add it to Documentation/.

Yes, definitely. Say Documentation/volatile-usage.txt -- this raw
version could be touched a little bit, to have sections that clearly
explain (1) how volatile makes the compiler generate trashy code, (2)
why volatile doesn't even do what people _think_ it does, considering
code is executed out-of-order by _hardware_ these days and not due to
compilers like was the case 20 years back, (3) and so volatile ends up
_hiding_ bugs from people and thus should be consigned to the trash
can of history, (4) _except_ for _really special_ usage cases like
reading IO mapped as memory.

2007-05-08 20:21:34

by David Rientjes

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, 8 May 2007, Krzysztof Halasa wrote:

> > Since 'volatile' has two different semantics depending on the context in
> > which it is used, this warning should be appended to include the fact that
> > it is legitimate to use for inline assembly.
>
> I think it hasn't two semantics, it's like arguing that char has two
> semantics.
>
> Volatile does one thing - prohibits C compiler from optimizing
> accesses to the variable. Either with (volatile *) casts and with
> volatile var;
>

What the meaning of an "access" to a volatile memory-mapped I/O port or a
variable that can be asynchronously interrupted is implementation-defined.

You're only citing qualified versions of objects.

In an asm construct, if all your input operands are modified and specified
as output operands as well, volatile must be added so that the entire
construct is not optimized away. Additionally, it must be added if your
construct modifies memory that is neither listed in inputs nor outputs to
the construct so that it is known to have at least one side-effect. Then,
the compiler cannot delete your construct if it is reachable because it
may produce such side-effects.

Thus, the warning that was proposed for addition to CodingStyle should be
modified to explicitly state that the use of 'volatile' for asm constructs
is perfectly legitimate and its use as a type qualifier for objects in
code is inappropriate.

David

2007-05-08 21:05:56

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

Krzysztof Halasa wrote:
> David Rientjes <[email protected]> writes:
>
>
>> Since 'volatile' has two different semantics depending on the context in
>> which it is used, this warning should be appended to include the fact that
>> it is legitimate to use for inline assembly.
>>
>
> I think it hasn't two semantics, it's like arguing that char has two
> semantics.
>

No, David means that "asm volatile (...)" is meaningful and OK to use.

J

2007-05-08 21:10:25

by Krzysztof Halasa

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

Jeremy Fitzhardinge <[email protected]> writes:

> No, David means that "asm volatile (...)" is meaningful and OK to use.

Ok, I mistook that.
--
Krzysztof Halasa

2007-05-08 21:17:14

by Jeff Garzik

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

Jeremy Fitzhardinge wrote:
> No, David means that "asm volatile (...)" is meaningful and OK to use.

In a driver? Highly unlikey it is OK. In a filesystem? Even more
unlikely it is OK to use.

The set of circumstances where 'volatile' is acceptable is very limited.

You will see it used properly in the definitions of writel(), for
example. But most drivers using 'volatile' are likely bugs.

Jeff


2007-05-08 21:20:39

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

David Rientjes wrote:
> Since 'volatile' has two different semantics depending on the context in
> which it is used, this warning should be appended to include the fact that
> it is legitimate to use for inline assembly.
>


It's probably worth noting that "asm volatile (...)" doesn't mean what
many people think it means: specifically, it *does not* prevent the asm
from being reordered with respect to the surrounding code. It may not
even prevent it from being reordered with respect to other asm
volatiles. *All* it means is that the asm code will be emitted even if
the compiler doesn't think its results will be used. Note that an
"asm()" with no outputs is implicitly "asm volatile()" - on the grounds
that it would be otherwise useless as far as gcc can tell.

If you need to guarantee ordering of asm statements, you must do it
explicitly, with either a "memory" clobber, or some finer-grain
serialization variable (like the _proxy_pda stuff). It would be useful
if you could tell gcc "I'm passing this variable to the asm for
serialization purposes, but there's no need to generate any explicit
references to it", but as far as I know there's no support for that.

J

2007-05-08 21:23:48

by Randy Dunlap

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

Jeff Garzik wrote:
> Jeremy Fitzhardinge wrote:
>> No, David means that "asm volatile (...)" is meaningful and OK to use.

I thought it was OK in readl(), writel(), etc... (and in asm),
but that's it. (and jiffies)

> In a driver? Highly unlikey it is OK. In a filesystem? Even more
> unlikely it is OK to use.
>
> The set of circumstances where 'volatile' is acceptable is very limited.
>
> You will see it used properly in the definitions of writel(), for
> example. But most drivers using 'volatile' are likely bugs.


--
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

2007-05-08 21:25:49

by Randy Dunlap

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

Jeremy Fitzhardinge wrote:
> David Rientjes wrote:
>> Since 'volatile' has two different semantics depending on the context in
>> which it is used, this warning should be appended to include the fact that
>> it is legitimate to use for inline assembly.
>>
>
>
> It's probably worth noting that "asm volatile (...)" doesn't mean what
> many people think it means: specifically, it *does not* prevent the asm
> from being reordered with respect to the surrounding code. It may not
> even prevent it from being reordered with respect to other asm
> volatiles. *All* it means is that the asm code will be emitted even if
> the compiler doesn't think its results will be used. Note that an
> "asm()" with no outputs is implicitly "asm volatile()" - on the grounds
> that it would be otherwise useless as far as gcc can tell.
>
> If you need to guarantee ordering of asm statements, you must do it
> explicitly, with either a "memory" clobber, or some finer-grain
> serialization variable (like the _proxy_pda stuff). It would be useful
> if you could tell gcc "I'm passing this variable to the asm for
> serialization purposes, but there's no need to generate any explicit
> references to it", but as far as I know there's no support for that.
>
> J

The doc. should just be talking about "volatile" in C mostly.
Any asm volatile comments are "extra".

--
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

2007-05-08 21:26:00

by Jeff Garzik

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

Randy Dunlap wrote:
> Jeff Garzik wrote:
>> Jeremy Fitzhardinge wrote:
>>> No, David means that "asm volatile (...)" is meaningful and OK to use.
>
> I thought it was OK in readl(), writel(), etc... (and in asm),
> but that's it. (and jiffies)
>
>> In a driver? Highly unlikey it is OK. In a filesystem? Even more
>> unlikely it is OK to use.
>>
>> The set of circumstances where 'volatile' is acceptable is very limited.
>>
>> You will see it used properly in the definitions of writel(), for
>> example. But most drivers using 'volatile' are likely bugs.


Not sure how to interpret your top-posted response :)

It is normal in the definition of writel(), in arch code, but
inappropriate in drivers when they _use_ writel().

If I may generalize, arch code generally knows what it's doing, when it
uses volatile. OTOH, driver authors that use volatile generally do
/not/ know what they are doing.

Jeff


2007-05-08 21:29:19

by David Rientjes

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, 8 May 2007, Jeremy Fitzhardinge wrote:

> It's probably worth noting that "asm volatile (...)" doesn't mean what
> many people think it means: specifically, it *does not* prevent the asm
> from being reordered with respect to the surrounding code. It may not
> even prevent it from being reordered with respect to other asm
> volatiles. *All* it means is that the asm code will be emitted even if
> the compiler doesn't think its results will be used. Note that an
> "asm()" with no outputs is implicitly "asm volatile()" - on the grounds
> that it would be otherwise useless as far as gcc can tell.
>
> If you need to guarantee ordering of asm statements, you must do it
> explicitly, with either a "memory" clobber, or some finer-grain
> serialization variable (like the _proxy_pda stuff). It would be useful
> if you could tell gcc "I'm passing this variable to the asm for
> serialization purposes, but there's no need to generate any explicit
> references to it", but as far as I know there's no support for that.
>

Ok, so let's take your second paragraph and my email of an hour ago:

In an asm construct, if all your input operands are modified and
specified as output operands as well, volatile must be added so
that the entire construct is not optimized away. Additionally,
it must be added if your construct modifies memory that is neither
listed in inputs nor outputs to the construct so that it is known
to have at least one side-effect. Then, the compiler cannot
delete your construct if it is reachable because it may produce
such side-effects.

and add it to any proposed change to CodingStyle that suggests against the
'volatile' keyword since there exists a distinct difference in behavior
between using the keyword as a type qualifier for an object and as a
qualifier for an asm construct.

David

2007-05-08 21:37:09

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

David Rientjes wrote:
> Ok, so let's take your second paragraph and my email of an hour ago:
>
> In an asm construct, if all your input operands are modified and
> specified as output operands as well, volatile must be added so
> that the entire construct is not optimized away. Additionally,
> it must be added if your construct modifies memory that is neither
> listed in inputs nor outputs to the construct so that it is known
> to have at least one side-effect.

Hm. Is "asm volatile" necessary if you have a "memory" clobber? Would
probably be the safest thing, I guess.

> and add it to any proposed change to CodingStyle that suggests against the
> 'volatile' keyword since there exists a distinct difference in behavior
> between using the keyword as a type qualifier for an object and as a
> qualifier for an asm construct.
>

Yeah, they're completely different. They're not even analogous, really,
which was my point. People confer more meaning to "asm volatile" than
it actually has, because of the analogy with volatile variables/types.
They would have been better off with something like "asm static", which
isn't much more meaningful, but at least it doesn't mislead the reader
into thinking it has anything to do with the other volatile.

But yes, seems like a worthwhile thing to point out. Or just point to
the gcc manual, which is pretty clear about all this stuff.

J

2007-05-08 22:00:41

by David Rientjes

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, 8 May 2007, Jeremy Fitzhardinge wrote:

> > In an asm construct, if all your input operands are modified and
> > specified as output operands as well, volatile must be added so
> > that the entire construct is not optimized away. Additionally,
> > it must be added if your construct modifies memory that is neither
> > listed in inputs nor outputs to the construct so that it is known
> > to have at least one side-effect.
>
> Hm. Is "asm volatile" necessary if you have a "memory" clobber? Would
> probably be the safest thing, I guess.
>

No, because the first requirement for 'volatile' in my paragraph above is
restricted to clobbering specific hard registers and an operand cannot
describe a hard register for a member when that register appears in the
clobber list. If an input operand is modified (i.e. not "accessed",
rather "modified" inclusive of the case where the previous value is the
same as the original value) then it must also be specified as an output
operand.

Now if all such output operands are to specify that the input operands
were "modified", 'volatile' is required to ensure the side-effects are
preserved or, otherwise, gcc is free optimize the entire asm construct
away since it appears to be unused.

> Yeah, they're completely different. They're not even analogous, really,
> which was my point. People confer more meaning to "asm volatile" than
> it actually has, because of the analogy with volatile variables/types.
> They would have been better off with something like "asm static", which
> isn't much more meaningful, but at least it doesn't mislead the reader
> into thinking it has anything to do with the other volatile.
>

You're point about reordering "asm volatile" constructs differs depending
on -mvolatile-asm-stop or -mno-volatile-asm-stop, however.

David

2007-05-08 22:04:53

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

David Rientjes wrote:
> Now if all such output operands are to specify that the input operands
> were "modified", 'volatile' is required to ensure the side-effects are
> preserved or, otherwise, gcc is free optimize the entire asm construct
> away since it appears to be unused.
>

Yup.

>> Yeah, they're completely different. They're not even analogous, really,
>> which was my point. People confer more meaning to "asm volatile" than
>> it actually has, because of the analogy with volatile variables/types.
>> They would have been better off with something like "asm static", which
>> isn't much more meaningful, but at least it doesn't mislead the reader
>> into thinking it has anything to do with the other volatile.
>>
>>
>
> You're point about reordering "asm volatile" constructs differs depending
> on -mvolatile-asm-stop or -mno-volatile-asm-stop, however.
>

Erm, that seems to be ia64 specific, and I have no idea what adding a
"stop bit" implies. Can you set even or odd parity too?

J

2007-05-08 22:20:05

by David Rientjes

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, 8 May 2007, Jeremy Fitzhardinge wrote:

> > You're point about reordering "asm volatile" constructs differs depending
> > on -mvolatile-asm-stop or -mno-volatile-asm-stop, however.
> >
>
> Erm, that seems to be ia64 specific, and I have no idea what adding a
> "stop bit" implies. Can you set even or odd parity too?
>

It is analogous with a sequence point for ia64. But, as you mentioned, it
is ia64 specific so your comment about "asm volatile" constructs not being
reordered is always appropriate outside of ia64 specific code but may not
apply to ia64 if we ever compiled with -mvolatile-asm-stop. If we do not
compile with that option, the behavior is unspecified. I don't think
we'll be adding -mvolatile-asm-stop support any time soon so your warning
certainly is appropriate for all code at this time.

David

2007-05-08 22:29:35

by Jeremy Fitzhardinge

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

David Rientjes wrote:
> It is analogous with a sequence point for ia64. But, as you mentioned, it
> is ia64 specific so your comment about "asm volatile" constructs not being
> reordered is always appropriate outside of ia64 specific code but may not
> apply to ia64 if we ever compiled with -mvolatile-asm-stop. If we do not
> compile with that option, the behavior is unspecified. I don't think
> we'll be adding -mvolatile-asm-stop support any time soon so your warning
> certainly is appropriate for all code at this time.
>

Sounds like it's referring to micro-architectural reordering, which is
distinct from compiler reordering. In other words, even if you
specified "-mvolatile-asm-stop" I would assume that the compiler could
still reorder the asm statements. Am I right, or should I read more
into the manual description than it actually says?

J

2007-05-08 22:36:46

by David Rientjes

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, 8 May 2007, Jeremy Fitzhardinge wrote:

> Sounds like it's referring to micro-architectural reordering, which is
> distinct from compiler reordering. In other words, even if you
> specified "-mvolatile-asm-stop" I would assume that the compiler could
> still reorder the asm statements. Am I right, or should I read more
> into the manual description than it actually says?
>

The ia64 architecture does not include any interlocks for asm constructs
and allow them to be executed in parallel without stop bits (although it
should emit a diagnostic message from gcc, although that is not a
constraint that was introduced in C99). Adding -mvolatile-asm-stops will
add these stop bits for any asm volatile construct that does not already
have them so that gcc is aware that it is unsafe to execute such
constructs in parallel.

[ This is a tangent because we currently don't have -mvolatile-asm-stop
support and it's ia64-specific. If they ever request such support,
then this will simply alter your warning about reordering asm
volatile constructs to exclude the ia64 case. ]

David

2007-05-08 23:05:46

by Randy Dunlap

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, 8 May 2007 14:27:33 -0700 (PDT) David Rientjes wrote:

> On Tue, 8 May 2007, Jeremy Fitzhardinge wrote:
>
> > It's probably worth noting that "asm volatile (...)" doesn't mean what
> > many people think it means: specifically, it *does not* prevent the asm
> > from being reordered with respect to the surrounding code. It may not
> > even prevent it from being reordered with respect to other asm
> > volatiles. *All* it means is that the asm code will be emitted even if
> > the compiler doesn't think its results will be used. Note that an
> > "asm()" with no outputs is implicitly "asm volatile()" - on the grounds
> > that it would be otherwise useless as far as gcc can tell.
> >
> > If you need to guarantee ordering of asm statements, you must do it
> > explicitly, with either a "memory" clobber, or some finer-grain
> > serialization variable (like the _proxy_pda stuff). It would be useful
> > if you could tell gcc "I'm passing this variable to the asm for
> > serialization purposes, but there's no need to generate any explicit
> > references to it", but as far as I know there's no support for that.
> >

Well, the document is really about "volatile" in C, not in gcc asm
extensions.
But if you want to add paragraphs(s) to the file, that's OK too.

> Ok, so let's take your second paragraph and my email of an hour ago:
>
> In an asm construct, if all your input operands are modified and
> specified as output operands as well, volatile must be added so
> that the entire construct is not optimized away. Additionally,
> it must be added if your construct modifies memory that is neither
> listed in inputs nor outputs to the construct so that it is known
> to have at least one side-effect. Then, the compiler cannot
> delete your construct if it is reachable because it may produce
> such side-effects.
>
> and add it to any proposed change to CodingStyle that suggests against the
> 'volatile' keyword since there exists a distinct difference in behavior
> between using the keyword as a type qualifier for an object and as a
> qualifier for an asm construct.


---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

2007-05-08 23:09:34

by Randy Dunlap

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, 8 May 2007 13:20:31 -0700 (PDT) David Rientjes wrote:

> On Tue, 8 May 2007, Krzysztof Halasa wrote:
>
> > > Since 'volatile' has two different semantics depending on the context in
> > > which it is used, this warning should be appended to include the fact that
> > > it is legitimate to use for inline assembly.
> >
> > I think it hasn't two semantics, it's like arguing that char has two
> > semantics.
> >
> > Volatile does one thing - prohibits C compiler from optimizing
> > accesses to the variable. Either with (volatile *) casts and with
> > volatile var;
> >
>
> What the meaning of an "access" to a volatile memory-mapped I/O port or a
> variable that can be asynchronously interrupted is implementation-defined.
>
> You're only citing qualified versions of objects.
>
> In an asm construct, if all your input operands are modified and specified
> as output operands as well, volatile must be added so that the entire
> construct is not optimized away. Additionally, it must be added if your
> construct modifies memory that is neither listed in inputs nor outputs to
> the construct so that it is known to have at least one side-effect. Then,
> the compiler cannot delete your construct if it is reachable because it
> may produce such side-effects.
>
> Thus, the warning that was proposed for addition to CodingStyle should be
> modified to explicitly state that the use of 'volatile' for asm constructs
> is perfectly legitimate and its use as a type qualifier for objects in
> code is inappropriate.

It's already there, isn't it? <quote from original:>

The only acceptable uses for "volatile" are:

- in _code_, i.e., for things like the definition of "readb()" etc, where we
use it to force a particular access.
- with inline asms
- on "jiffies", for stupid legacy reasons

</quote>

or are you saying that you want to subject/header/title modified also?


---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

2007-05-08 23:33:10

by Randy Dunlap

[permalink] [raw]
Subject: [PATCH] doc: volatile considered evil

On Tue, 8 May 2007 13:07:51 -0700 Satyam Sharma wrote:

> Yes, definitely. Say Documentation/volatile-usage.txt -- this raw
> version could be touched a little bit, to have sections that clearly
> explain (1) how volatile makes the compiler generate trashy code, (2)
> why volatile doesn't even do what people _think_ it does, considering
> code is executed out-of-order by _hardware_ these days and not due to
> compilers like was the case 20 years back, (3) and so volatile ends up
> _hiding_ bugs from people and thus should be consigned to the trash
> can of history, (4) _except_ for _really special_ usage cases like
> reading IO mapped as memory.

Hi Satyam,

If you would like to organize it like that, I'd be happy to
turn it over to you.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

From: Randy Dunlap <[email protected]>

Add information on the problems with the C-language "volatile" keyword
and why it should not be used (most of the time).

Signed-off-by: Randy Dunlap <[email protected]>
---
Documentation/volatile-usage.txt | 129 +++++++++++++++++++++++++++++++++++++++
1 file changed, 129 insertions(+)

--- /dev/null
+++ linux-2.6.21-git10/Documentation/volatile-usage.txt
@@ -0,0 +1,129 @@
+***** "volatile" considered useless and evil: Just Say NO! *****
+
+Do not use the C-language "volatile" keyword
+(extracted from lkml emails from Linus)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[Comment about a patch:]
+
+> Also made all the relevant mce_log fields volatile for further safety.
+
+I refuse to apply this part.
+
+If the memory barriers are right, then the "volatile" doesn't matter.
+
+And if the memory barriers aren't right, then "volatile" doesn't help.
+
+Using "volatile" in data structures is basically _always_ a bug.
+
+The only acceptable uses for "volatile" are:
+
+ - in _code_, i.e., for things like the definition of "readb()" etc, where we
+ use it to force a particular access.
+ - with inline asms
+ - on "jiffies", for stupid legacy reasons
+
+Basically, a volatile on a data structure can NEVER be right. If it makes
+a difference, it's a sign of improper locking.
+
+And the reason I refuse to apply that part of the patch is that anybody
+who even _thinks_ that they make a difference is horribly and utterly
+confused, and doesn't understand locking.
+
+So please _never_ use them like this.
+
+
+> mce_log is fully lockless - it deals with machine checks which act like NMIs.
+> That is it's problem.
+>
+> In theory the memory barriers should be sufficient, the volatiles are
+> just an additional safety net to make it clear to humans/compiler these memory
+> areas can change any time.
+
+If the memory barriers aren't sufficient, the volatiles are useless. If
+the memory barriers _are_ sufficient, the volatiles are useless.
+
+See? They're useless.
+
+The only thing they do is
+
+ - potentially make the compiler generate worse code for no reason (the
+ "no reason" being that if there aren't any barriers in between, the
+ compiler _should_ merge accesses)
+
+ - make some people _believe_ that that compiler does something "right".
+
+The first point doesn't much matter. The second point matters a LOT.
+
+Anybody who thinks "volatile" matters is WRONG. As such, a "volatile" is
+anti-documentation - it makes people think that something is true that is
+NOT true.
+
+In other words, volatile on data structures is _evil_, because it instills
+the wrong kind of beliefs in people. "volatility" is not a data structure
+issue. It's a matter of the _code_ working on the data structure.
+
+
+"volatile" really _is_ misdesigned. The semantics of it are so unclear as
+to be totally useless. The only thing "volatile" can ever do is generate
+worse code, WITH NO UPSIDES.
+
+Historically (and from the standpoint of the C standard), the definition
+of "volatile" is that any access is "visible" in the machine, and it
+really kind of makes sense for hardware accesses, except these days
+hardware accesses have other rules that are _not_ covered by "volatile",
+so you can't actually use them for that.
+
+And for accesses that have some software rules (i.e., not IO devices etc),
+the rules for "volatile" are too vague to be useful.
+
+So if you actually have rules about how to access a particular piece of
+memory, just make those rules _explicit_. Use the real rules. Not
+volatile, because volatile will always do the wrong thing.
+
+Also, more importantly, "volatile" is on the wrong _part_ of the whole
+system. In C, it's "data" that is volatile, but that is insane. Data
+isn't volatile - _accesses_ are volatile. So it may make sense to say
+"make this particular _access_ be careful", but not "make all accesses to
+this data use some random strategy".
+
+So the only thing "volatile" is potentially useful for is:
+
+ - actual accessor functions can use it in a _cast_ to make one particular
+ access follow the rules of "don't cache this one dereference". That is
+ useful as part of a _bigger_ set of rules about that access (i.e., it
+ might be the internal implementation of a "readb()", for example).
+
+ - for "random number generation" data locations, where you literally
+ don't _have_ any rules except "it's a random number". The only really
+ valid example of this is the "jiffy" timer tick.
+
+Any other use of "volatile" is almost certainly a bug, or just useless.
+
+Side note: it's also totally possible that a volatiles _hides_ a bug, i.e.,
+removing the volatile ends up having bad effects, but that's because the
+software itself isn't actually following the rules (or, more commonly, the
+rules are broken, and somebody added "volatile" to hide the problem).
+
+It's a bug if the volatile means that you don't follow the proper protocol
+for accessing the data, and it's useless (and generally generates worse
+code) if you already do.
+
+So just say NO! to volatile except under the above circumstances.
+
+
+
+[from another email thread:]
+
+I suspect we should just face up to the fact that:
+
+ (a) "volatile" on kernel data is basically always a bug, and you should
+ use locking. "volatile" doesn't help anything at all with memory
+ ordering and friends, so it's insane to think it "solves" anything on
+ its own.
+ (b) on "iomem" pointers it does make sense, but those need special
+ accessor functions _anyway_, so things like test_bit() wouldn't work
+ on them.
+ (c) if you spin on a value [that's] changing, you should use "cpu_relax()" or
+ "barrier()" anyway, which will force gcc to re-load any values from
+ memory over the loop.

2007-05-08 23:54:36

by David Rientjes

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, 8 May 2007, Randy Dunlap wrote:

> It's already there, isn't it? <quote from original:>
>
> The only acceptable uses for "volatile" are:
>
> - in _code_, i.e., for things like the definition of "readb()" etc, where we
> use it to force a particular access.
> - with inline asms
> - on "jiffies", for stupid legacy reasons
>
> </quote>
>
> or are you saying that you want to subject/header/title modified also?
>

I wasn't aware that you were considering the inclusion of Linus' entire
email in the document. There exists a point where CodingStyle becomes so
large that people choose not to read it in its entirety, so I was
expecting only an addition that would explicit document the acceptable and
unacceptable uses of 'volatile' in kernel code with perhaps a link to his
email.

2007-05-08 23:56:17

by Randy Dunlap

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

David Rientjes wrote:
> On Tue, 8 May 2007, Randy Dunlap wrote:
>
>> It's already there, isn't it? <quote from original:>
>>
>> The only acceptable uses for "volatile" are:
>>
>> - in _code_, i.e., for things like the definition of "readb()" etc, where we
>> use it to force a particular access.
>> - with inline asms
>> - on "jiffies", for stupid legacy reasons
>>
>> </quote>
>>
>> or are you saying that you want to subject/header/title modified also?
>>
>
> I wasn't aware that you were considering the inclusion of Linus' entire
> email in the document. There exists a point where CodingStyle becomes so
> large that people choose not to read it in its entirety, so I was
> expecting only an addition that would explicit document the acceptable and
> unacceptable uses of 'volatile' in kernel code with perhaps a link to his
> email.

but I wouldn't put it into CodingStyle.

--
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

2007-05-09 00:06:50

by David Rientjes

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Tue, 8 May 2007, Randy Dunlap wrote:

> From: Randy Dunlap <[email protected]>
>
> Add information on the problems with the C-language "volatile" keyword
> and why it should not be used (most of the time).
>
> Signed-off-by: Randy Dunlap <[email protected]>
> ---
> Documentation/volatile-usage.txt | 129 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 129 insertions(+)
>
> --- /dev/null
> +++ linux-2.6.21-git10/Documentation/volatile-usage.txt
> @@ -0,0 +1,129 @@
> +***** "volatile" considered useless and evil: Just Say NO! *****
> +
> +Do not use the C-language "volatile" keyword
> +(extracted from lkml emails from Linus)
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +

Again, please change this sweeping introduction to explicitly state that
Linus' emails were a criticism of using 'volatile' for objects (he refers
to them as "data structures") and can be appropriate for asm constructs.

2007-05-09 02:03:53

by Randy Dunlap

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Tue, 8 May 2007 17:06:23 -0700 (PDT) David Rientjes wrote:

> On Tue, 8 May 2007, Randy Dunlap wrote:
>
> > From: Randy Dunlap <[email protected]>
> >
> > Add information on the problems with the C-language "volatile" keyword
> > and why it should not be used (most of the time).
> >
> > Signed-off-by: Randy Dunlap <[email protected]>
> > ---
> > Documentation/volatile-usage.txt | 129 +++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 129 insertions(+)
> >
> > --- /dev/null
> > +++ linux-2.6.21-git10/Documentation/volatile-usage.txt
> > @@ -0,0 +1,129 @@
> > +***** "volatile" considered useless and evil: Just Say NO! *****
> > +
> > +Do not use the C-language "volatile" keyword
> > +(extracted from lkml emails from Linus)
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
>
> Again, please change this sweeping introduction to explicitly state that
> Linus' emails were a criticism of using 'volatile' for objects (he refers
> to them as "data structures") and can be appropriate for asm constructs.

You haven't replied to my other emails...

"volatile" used on a gcc asm extension is different, granted.
It's not even a C-language "volatile" keyword AFAICT, so it doesn't
apply in this context.


Anyway, how is this slightly modified title?

+***** "volatile" considered useless and evil: Just Say NO! *****
+
+Do not use the C-language "volatile" keyword on kernel data
+(extracted from lkml emails from Linus)


---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

2007-05-09 02:19:26

by Jonathan Corbet

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

Randy Dunlap <[email protected]> wrote:

> Here are some 'volatile' comments from Linus, extracted from
> several emails in at least 2 threads.
>
> If this is close to useful, we can add it to Documentation/.

I just took a shot at turning this into something more like a normal
document:

http://lwn.net/Articles/233479/

Comments welcome. If people think it suits the need I'll happily make a
version which moves from the LWN style to Documentation/ and send it in.

Thanks,

jon

Jonathan Corbet / LWN.net / [email protected]

2007-05-09 02:39:24

by David Rientjes

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Tue, 8 May 2007, Randy Dunlap wrote:

> "volatile" used on a gcc asm extension is different, granted.
> It's not even a C-language "volatile" keyword AFAICT, so it doesn't
> apply in this context.
>

Using 'volatile' for an asm construct certainly is a keyword; in fact, C99
defines 'volatile' as a token which is reserved for use as a keyword.

> Anyway, how is this slightly modified title?
>
> +***** "volatile" considered useless and evil: Just Say NO! *****
> +
> +Do not use the C-language "volatile" keyword on kernel data
> +(extracted from lkml emails from Linus)
>

It's still ambiguous. A much more explicit title that nobody could argue
with would be "do not use the 'volatile' keyword as a type qualifier for
an object."

David

2007-05-09 03:14:14

by Randy Dunlap

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Tue, 8 May 2007 19:38:56 -0700 (PDT) David Rientjes wrote:

> On Tue, 8 May 2007, Randy Dunlap wrote:
>
> > "volatile" used on a gcc asm extension is different, granted.
> > It's not even a C-language "volatile" keyword AFAICT, so it doesn't
> > apply in this context.
> >
>
> Using 'volatile' for an asm construct certainly is a keyword; in fact, C99
> defines 'volatile' as a token which is reserved for use as a keyword.

touche'

> > Anyway, how is this slightly modified title?
> >
> > +***** "volatile" considered useless and evil: Just Say NO! *****
> > +
> > +Do not use the C-language "volatile" keyword on kernel data
> > +(extracted from lkml emails from Linus)
> >
>
> It's still ambiguous. A much more explicit title that nobody could argue
> with would be "do not use the 'volatile' keyword as a type qualifier for
> an object."

OK, I can accept that.

---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

2007-05-09 08:51:30

by Stefan Richter

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

Randy Dunlap wrote:
> Add information on the problems with the C-language "volatile" keyword
> and why it should not be used (most of the time).

I like Jonathan's article http://lwn.net/Articles/233479/ a lot.
It puts as much emphasis on the DOs as on the DON'Ts, which I find helpful.
--
Stefan Richter
-=====-=-=== -=-= -=--=
http://arcgraph.de/sr/

2007-05-09 09:18:58

by Alan

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

> It's still ambiguous. A much more explicit title that nobody could argue
> with would be "do not use the 'volatile' keyword as a type qualifier for
> an object."

Except when you do. The kernel uses the C volatile in various places
itself for specific good reasons (and some for historical bad ones)

Perhaps a closer summary would be

Do Not Use Volatile
-------------------

1. volatile is not a locking mechanism

Volatile does not define sufficiently sane or strong semantics for
locking. The kernel has proper locking mechanisms which also act as
compiler fetch/store barriers and where neccessary hardware barriers for
SMP systems. The kernel knows about all the corner cases, you probably
don't.

2. volatile is not needed for mmio space

I/O memory access are done via readb/writeb and friends. They deal with
volatility themselves so you don't have to. They may nor may not use
volatile internally to their implementation, but that is none of your
business.

3. volatile is not atomic

Using volatile does not guarantee atomic behaviour. This often requires
special instructions or code sequences too. We have atomic_t and the
atomic_* operators for this.

4. volatile is not a store or read barrier

Using volatile is not always sufficient to order accesses on SMP or to
ensure things execute in the order expected. Instead the kernel provides
a set of barrier operations which have clearly defined semantics on all
systems. Make use of rmb, wmb, barrier, smp_wmb etc instead

When Might You Need volatile ?
------------------------------

When you are implementing the locking primitives on a new platform. When
you are implementing the I/O and atomic prmitives on a new platform. Also
in inline gcc assembler where "volatile" is used for subtly different
purposes.

Possibly very special cases we haven't thought about yet. However if you
find one remember the need for portability and ask whether it should be
using volatile or there is a gap in the existing hardware abstraction.

2007-05-09 09:27:17

by Nick Piggin

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

Alan Cox wrote:
>>It's still ambiguous. A much more explicit title that nobody could argue
>>with would be "do not use the 'volatile' keyword as a type qualifier for
>>an object."
>
>
> Except when you do. The kernel uses the C volatile in various places
> itself for specific good reasons (and some for historical bad ones)
>
> Perhaps a closer summary would be
>
> Do Not Use Volatile
> -------------------
>
> 1. volatile is not a locking mechanism
>
> Volatile does not define sufficiently sane or strong semantics for
> locking. The kernel has proper locking mechanisms which also act as
> compiler fetch/store barriers and where neccessary hardware barriers for
> SMP systems. The kernel knows about all the corner cases, you probably
> don't.
>
> 2. volatile is not needed for mmio space
>
> I/O memory access are done via readb/writeb and friends. They deal with
> volatility themselves so you don't have to. They may nor may not use
> volatile internally to their implementation, but that is none of your
> business.
>
> 3. volatile is not atomic
>
> Using volatile does not guarantee atomic behaviour. This often requires
> special instructions or code sequences too. We have atomic_t and the
> atomic_* operators for this.
>
> 4. volatile is not a store or read barrier
>
> Using volatile is not always sufficient to order accesses on SMP or to
> ensure things execute in the order expected. Instead the kernel provides
> a set of barrier operations which have clearly defined semantics on all
> systems. Make use of rmb, wmb, barrier, smp_wmb etc instead
>
> When Might You Need volatile ?
> ------------------------------
>
> When you are implementing the locking primitives on a new platform. When
> you are implementing the I/O and atomic prmitives on a new platform. Also
> in inline gcc assembler where "volatile" is used for subtly different
> purposes.

Is there a good reason for using volatile in atomic/locking primitives?
AFAIKS there is not.

--
SUSE Labs, Novell Inc.

2007-05-09 09:43:17

by Johannes Stezenbach

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On Tue, May 08, 2007, Jonathan Corbet wrote:
>
> I just took a shot at turning this into something more like a normal
> document:
>
> http://lwn.net/Articles/233479/

I think the "jiffies variable is special" part misses the
"for stupid legacy reasons" explanation.

According to the other volatile rules one should use
something like that:

extern unsigned long __jiffies;
static inline unsigned long read_ulong(unsigned long *addr)
{
return *(volatile unsigned long *)addr;
}
static inline unsigned long get_jiffies(void)
{
return read_ulong(&__jiffies);
}

But of course changing all references to jiffies in the kernel would
be insane, thus jiffies is special "for stupid legacy reasons".

Right?


Johannes

2007-05-09 10:25:56

by David Rientjes

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Wed, 9 May 2007, Alan Cox wrote:

> When Might You Need volatile ?
> ------------------------------
>
> When you are implementing the locking primitives on a new platform. When
> you are implementing the I/O and atomic prmitives on a new platform. Also
> in inline gcc assembler where "volatile" is used for subtly different
> purposes.
>

What is determined to be an "access" (read or modify) to an object such
as a locking primitive that is type-qualified with the keyword 'volatile'
is implementation defined.

You cannot guarantee that the value in such an object would agree
with the evaluation thus far as specified by the semantics of the code
even at sequence points because such an object can be modified without
knowledge to the implementation. The only thing you _can_ guarantee at
these sequence points is that their previous accesses are complete and
later accesses, as specified by the semantics of the code, have not yet
occurred. This does not exclude the possibility that they were modified
without knowledge to the implementation. In this case, the actual and
abstract semantics of the text may not agree.

Thus, any reliance on type-qualifying an object that represents an atomic
or locking primitive on the keyword 'volatile' is misplaced.

David

2007-05-09 13:28:24

by Alan

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

> > When you are implementing the locking primitives on a new platform. When
> > you are implementing the I/O and atomic prmitives on a new platform. Also
> > in inline gcc assembler where "volatile" is used for subtly different
> > purposes.
>
> Is there a good reason for using volatile in atomic/locking primitives?
> AFAIKS there is not.

Depends on the platform. If you are writing a new architecture then who
knows what you will need to get the barriers right - you may want to use
volatile, you may want to use asm.

2007-05-09 13:33:11

by Alan

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

> Thus, any reliance on type-qualifying an object that represents an atomic
> or locking primitive on the keyword 'volatile' is misplaced.

arch/foo is generally implementation specific code.

2007-05-09 15:50:06

by Randy Dunlap

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Wed, 09 May 2007 10:50:21 +0200 Stefan Richter wrote:

> Randy Dunlap wrote:
> > Add information on the problems with the C-language "volatile" keyword
> > and why it should not be used (most of the time).
>
> I like Jonathan's article http://lwn.net/Articles/233479/ a lot.
> It puts as much emphasis on the DOs as on the DON'Ts, which I find helpful.

Yep. I expect to drop my patch in favor of Jon's writeup.

---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

2007-05-09 18:46:21

by David Rientjes

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Wed, 9 May 2007, Alan Cox wrote:

> > Thus, any reliance on type-qualifying an object that represents an atomic
> > or locking primitive on the keyword 'volatile' is misplaced.
>
> arch/foo is generally implementation specific code.
>

That's true, but what qualifies as an "access" to an object that is
type qualified with the 'volatile' keyword is _implementation_ defined,
meaning the behavior is defined by the compiler and not this new
architecture you're proposing 'volatile' is appropriate for. That's pure
C99.

2007-05-09 19:04:25

by Satyam Sharma

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On 5/9/07, Randy Dunlap <[email protected]> wrote:
> On Wed, 09 May 2007 10:50:21 +0200 Stefan Richter wrote:
>
> > Randy Dunlap wrote:
> > > Add information on the problems with the C-language "volatile" keyword
> > > and why it should not be used (most of the time).
> >
> > I like Jonathan's article http://lwn.net/Articles/233479/ a lot.
> > It puts as much emphasis on the DOs as on the DON'Ts, which I find helpful.
>
> Yep. I expect to drop my patch in favor of Jon's writeup.

Yeah, that article was both comprehensive and to-the-point indeed. I
was trying my hand at re-organizing your original mail, but Jon's
version is nicer.

2007-05-09 19:34:50

by Satyam Sharma

[permalink] [raw]
Subject: Re: [RFC/PATCH] doc: volatile considered evil

On 5/9/07, Johannes Stezenbach <[email protected]> wrote:
> On Tue, May 08, 2007, Jonathan Corbet wrote:
> >
> > I just took a shot at turning this into something more like a normal
> > document:
> >
> > http://lwn.net/Articles/233479/
>
> I think the "jiffies variable is special" part misses the
> "for stupid legacy reasons" explanation.
>
> According to the other volatile rules one should use
> something like that:
>
> extern unsigned long __jiffies;
> static inline unsigned long read_ulong(unsigned long *addr)
> {
> return *(volatile unsigned long *)addr;
> }
> static inline unsigned long get_jiffies(void)
> {
> return read_ulong(&__jiffies);
> }
>
> But of course changing all references to jiffies in the kernel would
> be insane, thus jiffies is special "for stupid legacy reasons".
>
> Right?

Right. jiffies comes with no locking protection by default (and adding
one today in a patch that is not invasive / disruptive could be
difficult). If it had a spinlock or something for itself then the
above discussion would have been void, everybody would've just grabbed
the lock before accessing jiffies, and the spinlock implementation
would have done the Right Thing by itself (using barriers, obviously,
and so "volatile" would've been unnecessary even then).

Anyway, as things stand, jiffies comes without locks for itself. But
using a volatile "access cast" to read jiffies whenever you might need
it is _still_ not what I would personally prefer. IMO, it's *much*
better to use something like barrier() if / where you're sitting in a
tight loop comparing jiffies to whatever (a timeout expiry for
example).

So, if you _really_ need / want to do something of this sort, I'd much
rather see:

while (time_before(jiffies, expiry))
barrier();

in code instead of:

while (time_before((*(volatile unsigned long *)&jiffies), expiry))
;

But of course,

while (time_before(jiffies, expiry))
cpu_relax();

would be better still.

A last word from Linus himself here would be obviously best, but I'm
not so sure it makes sense to allow the "volatile" type qualifier
_even_ for the jiffies case.

2007-05-09 20:19:34

by Alan

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Wed, 9 May 2007 11:41:27 -0700 (PDT)
David Rientjes <[email protected]> wrote:

> On Wed, 9 May 2007, Alan Cox wrote:
>
> > > Thus, any reliance on type-qualifying an object that represents an atomic
> > > or locking primitive on the keyword 'volatile' is misplaced.
> >
> > arch/foo is generally implementation specific code.
> >
>
> That's true, but what qualifies as an "access" to an object that is
> type qualified with the 'volatile' keyword is _implementation_ defined,
> meaning the behavior is defined by the compiler and not this new
> architecture you're proposing 'volatile' is appropriate for. That's pure
> C99.

arch/foo almost always supports a single compiler too - gcc. We simply
don't support anything else. We use gcc inlines and features extensively.

And who cares about such fine detail of C99, did they fix the struct copy
bug in ANSI C even ? [1]

Alan
[1] ANSI C says access to the padding fields of a struct is undefined.
ANSI C also says that struct assignment is a memcpy. Therefore struct
assignment in ANSI C is a violation of ANSI C...

At this point its a lot simpler not to care about other compilers pet
insanities or areas of the spec like volatile that are vaguer and less
credible than the output of the US congress.

2007-05-09 20:26:10

by David Rientjes

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Wed, 9 May 2007, Alan Cox wrote:

> arch/foo almost always supports a single compiler too - gcc. We simply
> don't support anything else. We use gcc inlines and features extensively.
>

Ok, so your "acceptable use clause" of your addition should include that
fact. That the volatile type qualifier is legitimate when developing a
new architecture and the only implementation you support for compilation
of such text has a one-to-one correspondence between actual and abstract
machine semantics.

> [1] ANSI C says access to the padding fields of a struct is undefined.
> ANSI C also says that struct assignment is a memcpy. Therefore struct
> assignment in ANSI C is a violation of ANSI C...
>

Padding bytes are unspecified, not undefined. I doubt ANSI C says
padding bytes are undefined because then any implementation that pads
members of a struct object would not be strictly conforming.

David

2007-05-09 22:49:33

by Rob Landley

[permalink] [raw]
Subject: Re: [PATCH] doc: volatile considered evil

On Wednesday 09 May 2007 4:23 pm, Alan Cox wrote:
> arch/foo almost always supports a single compiler too - gcc. We simply
> don't support anything else. We use gcc inlines and features extensively.
>
> And who cares about such fine detail of C99, did they fix the struct copy
> bug in ANSI C even ? [1]

Um, I've picked up the tinycc baton (in my copious free time) and am slowly
trying to get it to build a bootable linux kernel. There's a ways to go, and
I really have no idea what I'm doing, but I have help and even made a release
recently (which is already significantly out of date, largely thanks to David
Wheeler):

http://landley.net/code/tinycc/

Admittedly, a lot of this involves implementing gcc extensions, but gratuitous
use of them when there's a perfectly good c99 way of doing it isn't
necessarily a plus. Fabrice got it as far as tccboot before QEMU ate his
life, we've improved a bit since then, and there's presumably a finite amount
of work left to be done...

Rob