* [PATCH] ARM: dts: mxs: Fix the RTC compatible prop on M28EVK
From: Marek Vasut @ 2014-07-22 2:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140221033102.GS3010@S2101-09.ap.freescale.net>
On Friday, February 21, 2014 at 04:31:06 AM, Shawn Guo wrote:
> On Fri, Feb 21, 2014 at 04:14:00AM +0100, Marek Vasut wrote:
> > On Friday, February 21, 2014 at 03:09:16 AM, Shawn Guo wrote:
> > > On Thu, Feb 20, 2014 at 01:31:37PM +0100, Marek Vasut wrote:
> > > > On Friday, January 24, 2014 at 12:23:36 AM, Marek Vasut wrote:
> > > > > The compatible property should be m41t62, not mt41t62, so fix this.
> > > > >
> > > > > Signed-off-by: Marek Vasut <marex@denx.de>
> > > > > Cc: Shawn Guo <shawn.guo@linaro.org>
> > > >
> > > > Bump ?
> > >
> > > Applied. Sorry for the delay.
> >
> > Sure, no problem. Thanks. Shall I submit this for -stable too ?
>
> Oh, at this time which already passes -rc3, I didn't categorize it as a
> critical fix (build error, kernel dumps, system hang) that we should
> send right away for 3.14 and -stable. If you do, you can try to resend
> it to arm-soc folks with my ACK.
Is there anything special to get this into 3.14-stable now or shall I just
follow the general stable submission guidelines ?
Best regards,
Marek Vasut
^ permalink raw reply
* [PATCH 2/2] iio: adc: exynos_adc: Add support for S3C24xx ADC
From: Chanwoo Choi @ 2014-07-22 2:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405995074-3271-1-git-send-email-cw00.choi@samsung.com>
This patch add support for s3c2410/s3c2416/s3c2440/s3c2443 ADC. The s3c24xx
is alomost same as ADCv1. But, There are a little difference as following:
- ADCMUX register address to select channel
- ADCDAT mask (10bit or 12bit ADC resolution according to SoC version)
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
.../devicetree/bindings/arm/samsung/exynos-adc.txt | 10 ++-
drivers/iio/adc/exynos_adc.c | 89 +++++++++++++++++++++-
2 files changed, 96 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
index b6e3989..fe34c76 100644
--- a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
@@ -11,11 +11,19 @@ New driver handles the following
Required properties:
- compatible: Must be "samsung,exynos-adc-v1"
- for exynos4412/5250 controllers.
+ for exynos4412/5250 and s5pv210 controllers.
Must be "samsung,exynos-adc-v2" for
future controllers.
Must be "samsung,exynos3250-adc" for
controllers compatible with ADC of Exynos3250.
+ Must be "samsung,s3c2410-adc" for
+ the ADC in s3c2410 and compatibles
+ Must be "samsung,s3c2416-adc" for
+ the ADC in s3c2416 and compatibles
+ Must be "samsung,s3c2440-adc" for
+ the ADC in s3c2440 and compatibles
+ Must be "samsung,s3c2443-adc" for
+ the ADC in s3c2443 and compatibles
Must be "samsung,s3c6410-adc" for
the ADC in s3c6410 and compatibles
- reg: Contains ADC register address range (base address and
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 05bdd2f12..7d28032 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -51,6 +51,9 @@
#define ADC_V1_MUX(x) ((x) + 0x1c)
#define ADC_V1_CLRINTPNDNUP(x) ((x) + 0x20)
+/* S3C2410 ADC registers definitions */
+#define ADC_S3C2410_MUX(x) ((x) + 0x18)
+
/* Future ADC_V2 registers definitions */
#define ADC_V2_CON1(x) ((x) + 0x00)
#define ADC_V2_CON2(x) ((x) + 0x04)
@@ -67,6 +70,8 @@
/* Bit definitions for S3C2410 ADC */
#define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) <<3)
+#define ADC_S3C2410_DATX_MASK 0x3FF
+#define ADC_S3C2416_CON_RES_SEL (1 << 3)
/* Bit definitions for ADC_V2 */
#define ADC_V2_CON1_SOFT_RESET (1u << 2)
@@ -84,6 +89,7 @@
/* Bit definitions common for ADC_V1 and ADC_V2 */
#define ADC_CON_EN_START (1u << 0)
+#define ADC_CON_EN_START_MASK (0x3 << 0)
#define ADC_DATX_MASK 0xFFF
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
@@ -101,12 +107,14 @@ struct exynos_adc {
struct completion completion;
u32 value;
+ u32 value2;
unsigned int version;
};
struct exynos_adc_data {
int num_channels;
bool needs_sclk;
+ u32 mask;
void (*init_hw)(struct exynos_adc *info);
void (*exit_hw)(struct exynos_adc *info);
@@ -217,6 +225,17 @@ static void exynos_adc_v1_start_conv(struct exynos_adc *info,
static const struct exynos_adc_data const exynos_adc_v1_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
+ .mask = ADC_DATX_MASK, /* 12bit ADC resolution */
+
+ .init_hw = exynos_adc_v1_init_hw,
+ .exit_hw = exynos_adc_v1_exit_hw,
+ .clear_irq = exynos_adc_v1_clear_irq,
+ .start_conv = exynos_adc_v1_start_conv,
+};
+
+static struct exynos_adc_data const exynos_adc_s3c24xx_data = {
+ .num_channels = MAX_ADC_V1_CHANNELS,
+ .mask = ADC_S3C2410_DATX_MASK, /* 10bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
@@ -224,6 +243,55 @@ static const struct exynos_adc_data const exynos_adc_v1_data = {
.start_conv = exynos_adc_v1_start_conv,
};
+static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info,
+ unsigned long addr)
+{
+ u32 con1;
+
+ /* Enable 12bit ADC resolution */
+ con1 = readl(ADC_V1_CON(info->regs));
+ con1 |= ADC_S3C2416_CON_RES_SEL;
+ writel(con1, ADC_V1_CON(info->regs));
+
+ /* Select channel for S3C2416 */
+ writel(addr, ADC_S3C2410_MUX(info->regs));
+
+ con1 = readl(ADC_V1_CON(info->regs));
+ writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
+}
+
+static struct exynos_adc_data const exynos_adc_s3c2416_data = {
+ .num_channels = MAX_ADC_V1_CHANNELS,
+ .mask = ADC_DATX_MASK, /* 12bit ADC resolution */
+
+ .init_hw = exynos_adc_v1_init_hw,
+ .exit_hw = exynos_adc_v1_exit_hw,
+ .clear_irq = exynos_adc_v1_clear_irq,
+ .start_conv = exynos_adc_s3c2416_start_conv,
+};
+
+static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info,
+ unsigned long addr)
+{
+ u32 con1;
+
+ /* Select channel for S3C2433 */
+ writel(addr, ADC_S3C2410_MUX(info->regs));
+
+ con1 = readl(ADC_V1_CON(info->regs));
+ writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
+}
+
+static struct exynos_adc_data const exynos_adc_s3c2443_data = {
+ .num_channels = MAX_ADC_V1_CHANNELS,
+ .mask = ADC_S3C2410_DATX_MASK, /* 10bit ADC resolution */
+
+ .init_hw = exynos_adc_v1_init_hw,
+ .exit_hw = exynos_adc_v1_exit_hw,
+ .clear_irq = exynos_adc_v1_clear_irq,
+ .start_conv = exynos_adc_s3c2443_start_conv,
+};
+
static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
unsigned long addr)
{
@@ -237,6 +305,7 @@ static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
static struct exynos_adc_data const exynos_adc_s3c64xx_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
+ .mask = ADC_DATX_MASK, /* 12bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
@@ -293,6 +362,7 @@ static void exynos_adc_v2_start_conv(struct exynos_adc *info,
static const struct exynos_adc_data const exynos_adc_v2_data = {
.num_channels = MAX_ADC_V2_CHANNELS,
+ .mask = ADC_DATX_MASK, /* 12bit ADC resolution */
.init_hw = exynos_adc_v2_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
@@ -302,6 +372,7 @@ static const struct exynos_adc_data const exynos_adc_v2_data = {
static const struct exynos_adc_data const exynos3250_adc_data = {
.num_channels = MAX_EXYNOS3250_ADC_CHANNELS,
+ .mask = ADC_DATX_MASK, /* 12bit ADC resolution */
.needs_sclk = true,
.init_hw = exynos_adc_v2_init_hw,
@@ -312,6 +383,18 @@ static const struct exynos_adc_data const exynos3250_adc_data = {
static const struct of_device_id exynos_adc_match[] = {
{
+ .compatible = "samsung,s3c2410-adc",
+ .data = &exynos_adc_s3c24xx_data,
+ }, {
+ .compatible = "samsung,s3c2416-adc",
+ .data = &exynos_adc_s3c2416_data,
+ }, {
+ .compatible = "samsung,s3c2440-adc",
+ .data = &exynos_adc_s3c24xx_data,
+ }, {
+ .compatible = "samsung,s3c2443-adc",
+ .data = &exynos_adc_s3c2443_data,
+ }, {
.compatible = "samsung,s3c6410-adc",
.data = &exynos_adc_s3c64xx_data,
}, {
@@ -365,7 +448,7 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
ret = -ETIMEDOUT;
} else {
*val = info->value;
- *val2 = 0;
+ *val2 = info->value2;
ret = IIO_VAL_INT;
}
@@ -377,9 +460,11 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
{
struct exynos_adc *info = (struct exynos_adc *)dev_id;
+ u32 mask = info->data->mask;
/* Read value */
- info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK;
+ info->value = readl(ADC_V1_DATX(info->regs)) & mask;
+ info->value2 = readl(ADC_V1_DATY(info->regs)) & mask;
/* clear irq */
if (info->data->clear_irq)
--
1.8.0
^ permalink raw reply related
* [PATCH 1/2] iio: adc: exynos_adc: add support for s3c64xx adc
From: Chanwoo Choi @ 2014-07-22 2:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405995074-3271-1-git-send-email-cw00.choi@samsung.com>
From: Arnd Bergmann <arnd@arndb.de>
The ADC in s3c64xx is almost the same as exynosv1, but
has a different 'select' method. Adding this here will be
helpful to move over the existing s3c64xx platform from the
legacy plat-samsung/adc driver to the new exynos-adc.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
---
.../devicetree/bindings/arm/samsung/exynos-adc.txt | 2 ++
drivers/iio/adc/exynos_adc.c | 32 +++++++++++++++++++++-
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
index 6d34891..b6e3989 100644
--- a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
@@ -16,6 +16,8 @@ Required properties:
future controllers.
Must be "samsung,exynos3250-adc" for
controllers compatible with ADC of Exynos3250.
+ Must be "samsung,s3c6410-adc" for
+ the ADC in s3c6410 and compatibles
- reg: Contains ADC register address range (base address and
length) and the address of the phy enable register.
- interrupts: Contains the interrupt information for the timer. The
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 87e0895..05bdd2f12 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -40,12 +40,16 @@
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
-/* EXYNOS4412/5250 ADC_V1 registers definitions */
+/* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */
#define ADC_V1_CON(x) ((x) + 0x00)
+#define ADC_V1_TSC(x) ((x) + 0x04)
#define ADC_V1_DLY(x) ((x) + 0x08)
#define ADC_V1_DATX(x) ((x) + 0x0C)
+#define ADC_V1_DATY(x) ((x) + 0x10)
+#define ADC_V1_UPDN(x) ((x) + 0x14)
#define ADC_V1_INTCLR(x) ((x) + 0x18)
#define ADC_V1_MUX(x) ((x) + 0x1c)
+#define ADC_V1_CLRINTPNDNUP(x) ((x) + 0x20)
/* Future ADC_V2 registers definitions */
#define ADC_V2_CON1(x) ((x) + 0x00)
@@ -61,6 +65,9 @@
#define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6)
#define ADC_V1_CON_STANDBY (1u << 2)
+/* Bit definitions for S3C2410 ADC */
+#define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) <<3)
+
/* Bit definitions for ADC_V2 */
#define ADC_V2_CON1_SOFT_RESET (1u << 2)
@@ -217,6 +224,26 @@ static const struct exynos_adc_data const exynos_adc_v1_data = {
.start_conv = exynos_adc_v1_start_conv,
};
+static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
+ unsigned long addr)
+{
+ u32 con1;
+
+ con1 = readl(ADC_V1_CON(info->regs));
+ con1 &= ~ADC_S3C2410_CON_SELMUX(7);
+ con1 |= ADC_S3C2410_CON_SELMUX(addr);
+ writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
+}
+
+static struct exynos_adc_data const exynos_adc_s3c64xx_data = {
+ .num_channels = MAX_ADC_V1_CHANNELS,
+
+ .init_hw = exynos_adc_v1_init_hw,
+ .exit_hw = exynos_adc_v1_exit_hw,
+ .clear_irq = exynos_adc_v1_clear_irq,
+ .start_conv = exynos_adc_s3c64xx_start_conv,
+};
+
static void exynos_adc_v2_init_hw(struct exynos_adc *info)
{
u32 con1, con2;
@@ -285,6 +312,9 @@ static const struct exynos_adc_data const exynos3250_adc_data = {
static const struct of_device_id exynos_adc_match[] = {
{
+ .compatible = "samsung,s3c6410-adc",
+ .data = &exynos_adc_s3c64xx_data,
+ }, {
.compatible = "samsung,exynos-adc-v1",
.data = &exynos_adc_v1_data,
}, {
--
1.8.0
^ permalink raw reply related
* [PATCH 0/2] iio: adc: exynos_adc: Add support for s3c64xx/s3c24xx ADC
From: Chanwoo Choi @ 2014-07-22 2:11 UTC (permalink / raw)
To: linux-arm-kernel
This patch add support for s3c64xx/s3c24xx ADC. s3c64xx/s3c24xx is alomost same
as ADCv1. But, s3c64xx/s3c24xx has a little difference from ADCv1 as following:
- ADCMUX register address to select channel
- ADCDAT mask (10bit or 12bit ADC resolution according to SoC version)
This patchset is implemented based on exynos3250 ADC patchset[1].
[1] http://www.spinics.net/lists/kernel/msg1791299.html
Arnd Bergmann (1):
iio: adc: exynos_adc: add support for s3c64xx adc
Chanwoo Choi (1):
iio: adc: exynos_adc: Add support for S3C24xx ADC
.../devicetree/bindings/arm/samsung/exynos-adc.txt | 12 +-
drivers/iio/adc/exynos_adc.c | 121 ++++++++++++++++++++-
2 files changed, 129 insertions(+), 4 deletions(-)
--
1.8.0
^ permalink raw reply
* [PATCH] ARM: dts: imx: Add alias for ethernet controller
From: Marek Vasut @ 2014-07-22 2:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140324014936.GA4006@dragon>
On Monday, March 24, 2014 at 02:49:38 AM, Shawn Guo wrote:
> On Tue, Mar 18, 2014 at 01:37:09AM +0100, Marek Vasut wrote:
> > On Friday, February 28, 2014 at 12:58:41 PM, Marek Vasut wrote:
> > > Add alias for FEC ethernet on i.MX to allow bootloaders (like U-Boot)
> > > patch-in the MAC address for FEC using this alias.
> > >
> > > Signed-off-by: Marek Vasut <marex@denx.de>
> > > Cc: Shawn Guo <shawn.guo@linaro.org>
> >
> > Bump ?
>
> Sorry. I had actually applied the patch but forgot replying.
Hello Shawn,
I'd like to apply this patch for 3.14-stable , are you OK with this please ?
Shall I submit it ?
Best regards,
Marek Vasut
^ permalink raw reply
* [PATCH 2/3] ARM: smp_scu: enable SCU standby support
From: Shawn Guo @ 2014-07-22 2:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140721102638.GE32578@arm.com>
On Mon, Jul 21, 2014 at 11:26:38AM +0100, Catalin Marinas wrote:
> The usual question - could the firmware enable this bit before Linux
> starts?
It could, I guess. Actually, on i.MX we're setting this bit in platform
code right now. But I think setting this bit makes sense for most of
the platforms, so it can reasonably be done in SCU core function. Isn't
it the point of having core/common function after all?
> We already do a read/modify/write sequence here and are only
> supposed to write the enable bit as the rest are implementation defined.
Isn't standby bit implemented by all A9 SCU except a couple of very
early revisions (per Will)?
Shawn
^ permalink raw reply
* [PATCHv8 4/4] ARM: dts: Fix wrong compatible string for Exynos3250 ADC
From: Chanwoo Choi @ 2014-07-22 2:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405994696-3117-1-git-send-email-cw00.choi@samsung.com>
This patchset fix wrong compatible string for Exynos3250 ADC. Exynos3250 SoC
need to control only special clock for ADC. Exynos SoC except for Exynos3250
has not included special clock for ADC. The exynos ADC driver can control
special clock if compatible string is 'exynos3250-adc-v2'.
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/boot/dts/exynos3250.dtsi | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 15c9c87..767189a 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -407,10 +407,11 @@
};
adc: adc at 126C0000 {
- compatible = "samsung,exynos-adc-v3";
+ compatible = "samsung,exynos3250-adc",
+ "samsung,exynos-adc-v2";
reg = <0x126C0000 0x100>, <0x10020718 0x4>;
interrupts = <0 137 0>;
- clock-names = "adc", "sclk_tsadc";
+ clock-names = "adc", "sclk";
clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
#io-channel-cells = <1>;
io-channel-ranges;
--
1.8.0
^ permalink raw reply related
* [PATCHv8 3/4] iio: devicetree: Add DT binding documentation for Exynos3250 ADC
From: Chanwoo Choi @ 2014-07-22 2:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405994696-3117-1-git-send-email-cw00.choi@samsung.com>
This patch add DT binding documentation for Exynos3250 ADC IP. Exynos3250 has
special clock ('sclk_adc') for ADC which provide clock to internal ADC.
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
.../devicetree/bindings/arm/samsung/exynos-adc.txt | 25 ++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
index 832fe8c..adc61b0 100644
--- a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
@@ -14,14 +14,21 @@ Required properties:
for exynos4412/5250 controllers.
Must be "samsung,exynos-adc-v2" for
future controllers.
+ Must be "samsung,exynos3250-adc" for
+ controllers compatible with ADC of Exynos3250.
- reg: Contains ADC register address range (base address and
length) and the address of the phy enable register.
- interrupts: Contains the interrupt information for the timer. The
format is being dependent on which interrupt controller
the Samsung device uses.
- #io-channel-cells = <1>; As ADC has multiple outputs
-- clocks From common clock binding: handle to adc clock.
-- clock-names From common clock binding: Shall be "adc".
+- clocks From common clock bindings: handles to clocks specified
+ in "clock-names" property, in the same order.
+- clock-names From common clock bindings: list of clock input names
+ used by ADC block:
+ - "adc" : ADC bus clock
+ - "sclk" : ADC special clock (only for Exynos3250 and
+ compatible ADC block)
- vdd-supply VDD input supply.
Note: child nodes can be added for auto probing from device tree.
@@ -41,6 +48,20 @@ adc: adc at 12D10000 {
vdd-supply = <&buck5_reg>;
};
+Example: adding device info in dtsi file for Exynos3250 with additional sclk
+
+adc: adc at 126C0000 {
+ compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2;
+ reg = <0x126C0000 0x100>, <0x10020718 0x4>;
+ interrupts = <0 137 0>;
+ #io-channel-cells = <1>;
+ io-channel-ranges;
+
+ clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
+ clock-names = "adc", "sclk";
+
+ vdd-supply = <&buck5_reg>;
+};
Example: Adding child nodes in dts file
--
1.8.0
^ permalink raw reply related
* [PATCHv8 2/4] iio: adc: exynos_adc: Control special clock of ADC to support Exynos3250 ADC
From: Chanwoo Choi @ 2014-07-22 2:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405994696-3117-1-git-send-email-cw00.choi@samsung.com>
This patch control special clock for ADC in Exynos series's FSYS block.
If special clock of ADC is registerd on clock list of common clk framework,
Exynos ADC drvier have to control this clock.
Exynos3250/Exynos4/Exynos5 has 'adc' clock as following:
- 'adc' clock: bus clock for ADC
Exynos3250 has additional 'sclk_adc' clock as following:
- 'sclk_adc' clock: special clock for ADC which provide clock to internal ADC
Exynos 4210/4212/4412 and Exynos5250/5420 has not included 'sclk_adc' clock
in FSYS_BLK. But, Exynos3250 based on Cortex-A7 has only included 'sclk_adc'
clock in FSYS_BLK.
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/iio/adc/exynos_adc.c | 111 +++++++++++++++++++++++++++++++++++++++----
1 file changed, 103 insertions(+), 8 deletions(-)
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index dde4ca8..87e0895 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
@@ -70,8 +71,9 @@
#define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0)
#define ADC_V2_CON2_ACH_MASK 0xF
-#define MAX_ADC_V2_CHANNELS 10
-#define MAX_ADC_V1_CHANNELS 8
+#define MAX_ADC_V2_CHANNELS 10
+#define MAX_ADC_V1_CHANNELS 8
+#define MAX_EXYNOS3250_ADC_CHANNELS 2
/* Bit definitions common for ADC_V1 and ADC_V2 */
#define ADC_CON_EN_START (1u << 0)
@@ -81,9 +83,11 @@
struct exynos_adc {
struct exynos_adc_data *data;
+ struct device *dev;
void __iomem *regs;
void __iomem *enable_reg;
struct clk *clk;
+ struct clk *sclk;
unsigned int irq;
struct regulator *vdd;
@@ -95,6 +99,7 @@ struct exynos_adc {
struct exynos_adc_data {
int num_channels;
+ bool needs_sclk;
void (*init_hw)(struct exynos_adc *info);
void (*exit_hw)(struct exynos_adc *info);
@@ -102,6 +107,66 @@ struct exynos_adc_data {
void (*start_conv)(struct exynos_adc *info, unsigned long addr);
};
+static void exynos_adc_unprepare_clk(struct exynos_adc *info)
+{
+ if (info->data->needs_sclk)
+ clk_unprepare(info->sclk);
+ clk_unprepare(info->clk);
+}
+
+static int exynos_adc_prepare_clk(struct exynos_adc *info)
+{
+ int ret;
+
+ ret = clk_prepare(info->clk);
+ if (ret) {
+ dev_err(info->dev, "failed preparing adc clock: %d\n", ret);
+ return ret;
+ }
+
+ if (info->data->needs_sclk) {
+ ret = clk_prepare(info->sclk);
+ if (ret) {
+ clk_unprepare(info->clk);
+ dev_err(info->dev,
+ "failed preparing sclk_adc clock: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void exynos_adc_disable_clk(struct exynos_adc *info)
+{
+ if (info->data->needs_sclk)
+ clk_disable(info->sclk);
+ clk_disable(info->clk);
+}
+
+static int exynos_adc_enable_clk(struct exynos_adc *info)
+{
+ int ret;
+
+ ret = clk_enable(info->clk);
+ if (ret) {
+ dev_err(info->dev, "failed enabling adc clock: %d\n", ret);
+ return ret;
+ }
+
+ if (info->data->needs_sclk) {
+ ret = clk_enable(info->sclk);
+ if (ret) {
+ clk_disable(info->clk);
+ dev_err(info->dev,
+ "failed enabling sclk_adc clock: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static void exynos_adc_v1_init_hw(struct exynos_adc *info)
{
u32 con1;
@@ -208,6 +273,16 @@ static const struct exynos_adc_data const exynos_adc_v2_data = {
.start_conv = exynos_adc_v2_start_conv,
};
+static const struct exynos_adc_data const exynos3250_adc_data = {
+ .num_channels = MAX_EXYNOS3250_ADC_CHANNELS,
+ .needs_sclk = true,
+
+ .init_hw = exynos_adc_v2_init_hw,
+ .exit_hw = exynos_adc_v2_exit_hw,
+ .clear_irq = exynos_adc_v2_clear_irq,
+ .start_conv = exynos_adc_v2_start_conv,
+};
+
static const struct of_device_id exynos_adc_match[] = {
{
.compatible = "samsung,exynos-adc-v1",
@@ -215,6 +290,9 @@ static const struct of_device_id exynos_adc_match[] = {
}, {
.compatible = "samsung,exynos-adc-v2",
.data = &exynos_adc_v2_data,
+ }, {
+ .compatible = "samsung,exynos3250-adc",
+ .data = &exynos3250_adc_data,
},
{},
};
@@ -376,6 +454,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
}
info->irq = irq;
+ info->dev = &pdev->dev;
init_completion(&info->completion);
@@ -386,6 +465,16 @@ static int exynos_adc_probe(struct platform_device *pdev)
return PTR_ERR(info->clk);
}
+ if (info->data->needs_sclk) {
+ info->sclk = devm_clk_get(&pdev->dev, "sclk");
+ if (IS_ERR(info->sclk)) {
+ dev_err(&pdev->dev,
+ "failed getting sclk clock, err = %ld\n",
+ PTR_ERR(info->sclk));
+ return PTR_ERR(info->sclk);
+ }
+ }
+
info->vdd = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(info->vdd)) {
dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
@@ -397,10 +486,14 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = clk_prepare_enable(info->clk);
+ ret = exynos_adc_prepare_clk(info);
if (ret)
goto err_disable_reg;
+ ret = exynos_adc_enable_clk(info);
+ if (ret)
+ goto err_unprepare_clk;
+
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = dev_name(&pdev->dev);
@@ -443,7 +536,9 @@ err_irq:
err_disable_clk:
if (info->data->exit_hw)
info->data->exit_hw(info);
- clk_disable_unprepare(info->clk);
+ exynos_adc_disable_clk(info);
+err_unprepare_clk:
+ exynos_adc_unprepare_clk(info);
err_disable_reg:
regulator_disable(info->vdd);
return ret;
@@ -460,7 +555,8 @@ static int exynos_adc_remove(struct platform_device *pdev)
free_irq(info->irq, info);
if (info->data->exit_hw)
info->data->exit_hw(info);
- clk_disable_unprepare(info->clk);
+ exynos_adc_disable_clk(info);
+ exynos_adc_unprepare_clk(info);
regulator_disable(info->vdd);
return 0;
@@ -474,8 +570,7 @@ static int exynos_adc_suspend(struct device *dev)
if (info->data->exit_hw)
info->data->exit_hw(info);
-
- clk_disable_unprepare(info->clk);
+ exynos_adc_disable_clk(info);
regulator_disable(info->vdd);
return 0;
@@ -491,7 +586,7 @@ static int exynos_adc_resume(struct device *dev)
if (ret)
return ret;
- ret = clk_prepare_enable(info->clk);
+ ret = exynos_adc_enable_clk(info);
if (ret)
return ret;
--
1.8.0
^ permalink raw reply related
* [PATCHv8 1/4] iio: adc: exynos_adc: Add exynos_adc_data structure to improve readability
From: Chanwoo Choi @ 2014-07-22 2:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405994696-3117-1-git-send-email-cw00.choi@samsung.com>
This patchset add 'exynos_adc_data' structure which includes some functions
to control ADC operation and specific data according to ADC version (v1 or v2).
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/iio/adc/exynos_adc.c | 226 ++++++++++++++++++++++++++++---------------
1 file changed, 147 insertions(+), 79 deletions(-)
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 010578f..dde4ca8 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -39,11 +39,6 @@
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
-enum adc_version {
- ADC_V1,
- ADC_V2
-};
-
/* EXYNOS4412/5250 ADC_V1 registers definitions */
#define ADC_V1_CON(x) ((x) + 0x00)
#define ADC_V1_DLY(x) ((x) + 0x08)
@@ -85,6 +80,7 @@ enum adc_version {
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
struct exynos_adc {
+ struct exynos_adc_data *data;
void __iomem *regs;
void __iomem *enable_reg;
struct clk *clk;
@@ -97,43 +93,139 @@ struct exynos_adc {
unsigned int version;
};
-static const struct of_device_id exynos_adc_match[] = {
- { .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 },
- { .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 },
- {},
+struct exynos_adc_data {
+ int num_channels;
+
+ void (*init_hw)(struct exynos_adc *info);
+ void (*exit_hw)(struct exynos_adc *info);
+ void (*clear_irq)(struct exynos_adc *info);
+ void (*start_conv)(struct exynos_adc *info, unsigned long addr);
};
-MODULE_DEVICE_TABLE(of, exynos_adc_match);
-static inline unsigned int exynos_adc_get_version(struct platform_device *pdev)
+static void exynos_adc_v1_init_hw(struct exynos_adc *info)
{
- const struct of_device_id *match;
+ u32 con1;
- match = of_match_node(exynos_adc_match, pdev->dev.of_node);
- return (unsigned int)match->data;
+ writel(1, info->enable_reg);
+
+ /* set default prescaler values and Enable prescaler */
+ con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
+
+ /* Enable 12-bit ADC resolution */
+ con1 |= ADC_V1_CON_RES;
+ writel(con1, ADC_V1_CON(info->regs));
+}
+
+static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
+{
+ u32 con;
+
+ writel(0, info->enable_reg);
+
+ con = readl(ADC_V1_CON(info->regs));
+ con |= ADC_V1_CON_STANDBY;
+ writel(con, ADC_V1_CON(info->regs));
+}
+
+static void exynos_adc_v1_clear_irq(struct exynos_adc *info)
+{
+ writel(1, ADC_V1_INTCLR(info->regs));
}
-static void exynos_adc_hw_init(struct exynos_adc *info)
+static void exynos_adc_v1_start_conv(struct exynos_adc *info,
+ unsigned long addr)
+{
+ u32 con1;
+
+ writel(addr, ADC_V1_MUX(info->regs));
+
+ con1 = readl(ADC_V1_CON(info->regs));
+ writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
+}
+
+static const struct exynos_adc_data const exynos_adc_v1_data = {
+ .num_channels = MAX_ADC_V1_CHANNELS,
+
+ .init_hw = exynos_adc_v1_init_hw,
+ .exit_hw = exynos_adc_v1_exit_hw,
+ .clear_irq = exynos_adc_v1_clear_irq,
+ .start_conv = exynos_adc_v1_start_conv,
+};
+
+static void exynos_adc_v2_init_hw(struct exynos_adc *info)
{
u32 con1, con2;
- if (info->version == ADC_V2) {
- con1 = ADC_V2_CON1_SOFT_RESET;
- writel(con1, ADC_V2_CON1(info->regs));
+ writel(1, info->enable_reg);
- con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
- ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
- writel(con2, ADC_V2_CON2(info->regs));
+ con1 = ADC_V2_CON1_SOFT_RESET;
+ writel(con1, ADC_V2_CON1(info->regs));
- /* Enable interrupts */
- writel(1, ADC_V2_INT_EN(info->regs));
- } else {
- /* set default prescaler values and Enable prescaler */
- con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
+ con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
+ ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
+ writel(con2, ADC_V2_CON2(info->regs));
- /* Enable 12-bit ADC resolution */
- con1 |= ADC_V1_CON_RES;
- writel(con1, ADC_V1_CON(info->regs));
- }
+ /* Enable interrupts */
+ writel(1, ADC_V2_INT_EN(info->regs));
+}
+
+static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
+{
+ u32 con;
+
+ writel(0, info->enable_reg);
+
+ con = readl(ADC_V2_CON1(info->regs));
+ con &= ~ADC_CON_EN_START;
+ writel(con, ADC_V2_CON1(info->regs));
+}
+
+static void exynos_adc_v2_clear_irq(struct exynos_adc *info)
+{
+ writel(1, ADC_V2_INT_ST(info->regs));
+}
+
+static void exynos_adc_v2_start_conv(struct exynos_adc *info,
+ unsigned long addr)
+{
+ u32 con1, con2;
+
+ con2 = readl(ADC_V2_CON2(info->regs));
+ con2 &= ~ADC_V2_CON2_ACH_MASK;
+ con2 |= ADC_V2_CON2_ACH_SEL(addr);
+ writel(con2, ADC_V2_CON2(info->regs));
+
+ con1 = readl(ADC_V2_CON1(info->regs));
+ writel(con1 | ADC_CON_EN_START, ADC_V2_CON1(info->regs));
+}
+
+static const struct exynos_adc_data const exynos_adc_v2_data = {
+ .num_channels = MAX_ADC_V2_CHANNELS,
+
+ .init_hw = exynos_adc_v2_init_hw,
+ .exit_hw = exynos_adc_v2_exit_hw,
+ .clear_irq = exynos_adc_v2_clear_irq,
+ .start_conv = exynos_adc_v2_start_conv,
+};
+
+static const struct of_device_id exynos_adc_match[] = {
+ {
+ .compatible = "samsung,exynos-adc-v1",
+ .data = &exynos_adc_v1_data,
+ }, {
+ .compatible = "samsung,exynos-adc-v2",
+ .data = &exynos_adc_v2_data,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_adc_match);
+
+static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+
+ match = of_match_node(exynos_adc_match, pdev->dev.of_node);
+ return (struct exynos_adc_data *)match->data;
}
static int exynos_read_raw(struct iio_dev *indio_dev,
@@ -144,7 +236,6 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
{
struct exynos_adc *info = iio_priv(indio_dev);
unsigned long timeout;
- u32 con1, con2;
int ret;
if (mask != IIO_CHAN_INFO_RAW)
@@ -154,28 +245,15 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
reinit_completion(&info->completion);
/* Select the channel to be used and Trigger conversion */
- if (info->version == ADC_V2) {
- con2 = readl(ADC_V2_CON2(info->regs));
- con2 &= ~ADC_V2_CON2_ACH_MASK;
- con2 |= ADC_V2_CON2_ACH_SEL(chan->address);
- writel(con2, ADC_V2_CON2(info->regs));
-
- con1 = readl(ADC_V2_CON1(info->regs));
- writel(con1 | ADC_CON_EN_START,
- ADC_V2_CON1(info->regs));
- } else {
- writel(chan->address, ADC_V1_MUX(info->regs));
-
- con1 = readl(ADC_V1_CON(info->regs));
- writel(con1 | ADC_CON_EN_START,
- ADC_V1_CON(info->regs));
- }
+ if (info->data->start_conv)
+ info->data->start_conv(info, chan->address);
timeout = wait_for_completion_timeout
(&info->completion, EXYNOS_ADC_TIMEOUT);
if (timeout == 0) {
dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
- exynos_adc_hw_init(info);
+ if (info->data->init_hw)
+ info->data->init_hw(info);
ret = -ETIMEDOUT;
} else {
*val = info->value;
@@ -193,13 +271,11 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
struct exynos_adc *info = (struct exynos_adc *)dev_id;
/* Read value */
- info->value = readl(ADC_V1_DATX(info->regs)) &
- ADC_DATX_MASK;
+ info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK;
+
/* clear irq */
- if (info->version == ADC_V2)
- writel(1, ADC_V2_INT_ST(info->regs));
- else
- writel(1, ADC_V1_INTCLR(info->regs));
+ if (info->data->clear_irq)
+ info->data->clear_irq(info);
complete(&info->completion);
@@ -277,6 +353,12 @@ static int exynos_adc_probe(struct platform_device *pdev)
info = iio_priv(indio_dev);
+ info->data = exynos_adc_get_data(pdev);
+ if (!info->data) {
+ dev_err(&pdev->dev, "failed getting exynos_adc_data\n");
+ return -EINVAL;
+ }
+
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->regs))
@@ -319,10 +401,6 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (ret)
goto err_disable_reg;
- writel(1, info->enable_reg);
-
- info->version = exynos_adc_get_version(pdev);
-
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = dev_name(&pdev->dev);
@@ -331,11 +409,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
indio_dev->info = &exynos_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = exynos_adc_iio_channels;
-
- if (info->version == ADC_V1)
- indio_dev->num_channels = MAX_ADC_V1_CHANNELS;
- else
- indio_dev->num_channels = MAX_ADC_V2_CHANNELS;
+ indio_dev->num_channels = info->data->num_channels;
ret = request_irq(info->irq, exynos_adc_isr,
0, dev_name(&pdev->dev), info);
@@ -349,7 +423,8 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (ret)
goto err_irq;
- exynos_adc_hw_init(info);
+ if (info->data->init_hw)
+ info->data->init_hw(info);
ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
if (ret < 0) {
@@ -366,7 +441,8 @@ err_of_populate:
err_irq:
free_irq(info->irq, info);
err_disable_clk:
- writel(0, info->enable_reg);
+ if (info->data->exit_hw)
+ info->data->exit_hw(info);
clk_disable_unprepare(info->clk);
err_disable_reg:
regulator_disable(info->vdd);
@@ -382,7 +458,8 @@ static int exynos_adc_remove(struct platform_device *pdev)
exynos_adc_remove_devices);
iio_device_unregister(indio_dev);
free_irq(info->irq, info);
- writel(0, info->enable_reg);
+ if (info->data->exit_hw)
+ info->data->exit_hw(info);
clk_disable_unprepare(info->clk);
regulator_disable(info->vdd);
@@ -394,19 +471,10 @@ static int exynos_adc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct exynos_adc *info = iio_priv(indio_dev);
- u32 con;
- if (info->version == ADC_V2) {
- con = readl(ADC_V2_CON1(info->regs));
- con &= ~ADC_CON_EN_START;
- writel(con, ADC_V2_CON1(info->regs));
- } else {
- con = readl(ADC_V1_CON(info->regs));
- con |= ADC_V1_CON_STANDBY;
- writel(con, ADC_V1_CON(info->regs));
- }
+ if (info->data->exit_hw)
+ info->data->exit_hw(info);
- writel(0, info->enable_reg);
clk_disable_unprepare(info->clk);
regulator_disable(info->vdd);
@@ -427,8 +495,8 @@ static int exynos_adc_resume(struct device *dev)
if (ret)
return ret;
- writel(1, info->enable_reg);
- exynos_adc_hw_init(info);
+ if (info->data->init_hw)
+ info->data->init_hw(info);
return 0;
}
--
1.8.0
^ permalink raw reply related
* [PATCHv8 0/4] iio: adc: exynos_adc: Support Exynos3250 ADC and code clean
From: Chanwoo Choi @ 2014-07-22 2:04 UTC (permalink / raw)
To: linux-arm-kernel
This patchset support Exynos3250 ADC (Analog Digital Converter) because
Exynos3250 has additional special clock for ADC IP.
Changes from v7:
- Add acked message by Arnd Bergmann
- Use two compatible string for Exynos3250 ADC as following:
: compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2;
Changes from v6:
- Use "exynos3250-adc" compatible string instead of "exynos3250-adc-v2"
- Use "sclk" clock name instead of "sclk_adc"
- Remove un-necessary macro for exyno-adc-data-v2 structure.
- Remove '(void *)' cast and mark the exynos-adc-data structure as 'const'
- Change the number of ADC channels (Exynos3250 has only two channels for ADC)
Changes from v5:
- Add acked message by Kukjin Kim
- Add reviewed messgae by Tomasz Figa
- Fix typo (for for -> for)
Changes from v4:
- Use 'exynos_adc_data' structure instead of 'exynos_adc_ops' structure
and remove enum variable of ADC version
- Fix wrong name of special clock (sclk_tsadc -> sclk_adc)
- Add reviewed message by Naveen Krishna Chatradhi
- Add functions for ADC clock control
Changes from v3:
- Add new 'exynos_adc_ops' structure to improve readability according to
Tomasz Figa comment[1]
[1] https://lkml.org/lkml/2014/4/16/238
- Add new 'exynos3250-adc-v2' compatible string to support Exynos3250 ADC
- Fix wrong compaitlbe string of ADC in Exynos3250 dtsi file
Changes from v2:
- Check return value of clock function to deal with error exception
- Fix minor coding style to improve readability
Changes from v1:
- Add new "samsung,exynos-adc-v3" compatible to support Exynos3250 ADC
- Add a patch about DT binding documentation
Chanwoo Choi (4):
iio: adc: exynos_adc: Add exynos_adc_data structure to improve
readability
iio: adc: exynos_adc: Control special clock of ADC to support
Exynos3250 ADC
iio: devicetree: Add DT binding documentation for Exynos3250 ADC
ARM: dts: Fix wrong compatible string for Exynos3250 ADC
.../devicetree/bindings/arm/samsung/exynos-adc.txt | 25 +-
arch/arm/boot/dts/exynos3250.dtsi | 5 +-
drivers/iio/adc/exynos_adc.c | 335 +++++++++++++++------
3 files changed, 275 insertions(+), 90 deletions(-)
--
1.8.0
^ permalink raw reply
* [PATCH 2/3] ARM: smp_scu: enable SCU standby support
From: Shawn Guo @ 2014-07-22 1:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140721094452.GD16122@arm.com>
On Mon, Jul 21, 2014 at 10:44:52AM +0100, Will Deacon wrote:
> > > > @@ -54,7 +55,7 @@ void scu_enable(void __iomem *scu_base)
> > > > if (scu_ctrl & SCU_ENABLE)
> > > > return;
> > > >
> > > > - scu_ctrl |= SCU_ENABLE;
> > > > + scu_ctrl |= SCU_ENABLE | SCU_STANDBY_ENABLE;
> > >
> > > I don't think this bit exists on all revisions of the A9.
> >
> > Thanks for the info, Will. Is there any side-effect to write the
> > standby bit on those revisions which do not define the bit?
>
> I'm not actually sure what happens at the hardware level, but the TRM is
> pretty clear in its definition of `RESERVED':
>
> `All reserved bits not used by the implementation must be written as 0 and
> read as 0.'
Okay. Can you please tell which revisions of A9 do not implement this
standby bit, so that I can check and skip them? The oldest revision I
can find on http://infocenter.arm.com/ is r2p0, which already implements
the bit.
Shawn
^ permalink raw reply
* [PATCH v3 8/8] x86_64, entry: Use split-phase syscall_trace_enter for 64-bit syscalls
From: Andy Lutomirski @ 2014-07-22 1:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2baeb5fad958c292705885941d61ab31771a75bb.1405992946.git.luto@amacapital.net>
On KVM on my box, this reduces the overhead from an always-accept
seccomp filter from ~130ns to ~17ns. Most of that comes from
avoiding IRET on every syscall when seccomp is enabled.
In extremely approximate hacked-up benchmarking, just bypassing IRET
saves about 80ns, so there's another 43ns of savings here from
simplifying the seccomp path.
The diffstat is also rather nice :)
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
arch/x86/kernel/entry_64.S | 38 +++++++++++++++-----------------------
1 file changed, 15 insertions(+), 23 deletions(-)
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 1eb3094..13e0c1d 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -479,22 +479,6 @@ sysret_signal:
#ifdef CONFIG_AUDITSYSCALL
/*
- * Fast path for syscall audit without full syscall trace.
- * We just call __audit_syscall_entry() directly, and then
- * jump back to the normal fast path.
- */
-auditsys:
- movq %r10,%r9 /* 6th arg: 4th syscall arg */
- movq %rdx,%r8 /* 5th arg: 3rd syscall arg */
- movq %rsi,%rcx /* 4th arg: 2nd syscall arg */
- movq %rdi,%rdx /* 3rd arg: 1st syscall arg */
- movq %rax,%rsi /* 2nd arg: syscall number */
- movl $AUDIT_ARCH_X86_64,%edi /* 1st arg: audit arch */
- call __audit_syscall_entry
- LOAD_ARGS 0 /* reload call-clobbered registers */
- jmp system_call_fastpath
-
- /*
* Return fast path for syscall audit. Call __audit_syscall_exit()
* directly and then jump back to the fast path with TIF_SYSCALL_AUDIT
* masked off.
@@ -511,17 +495,25 @@ sysret_audit:
/* Do syscall tracing */
tracesys:
-#ifdef CONFIG_AUDITSYSCALL
- testl $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT),TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
- jz auditsys
-#endif
+ leaq -REST_SKIP(%rsp), %rdi
+ movq $AUDIT_ARCH_X86_64, %rsi
+ call syscall_trace_enter_phase1
+ test %rax, %rax
+ jnz tracesys_phase2 /* if needed, run the slow path */
+ LOAD_ARGS 0 /* else restore clobbered regs */
+ jmp system_call_fastpath /* and return to the fast path */
+
+tracesys_phase2:
SAVE_REST
FIXUP_TOP_OF_STACK %rdi
- movq %rsp,%rdi
- call syscall_trace_enter
+ movq %rsp, %rdi
+ movq $AUDIT_ARCH_X86_64, %rsi
+ movq %rax,%rdx
+ call syscall_trace_enter_phase2
+
/*
* Reload arg registers from stack in case ptrace changed them.
- * We don't reload %rax because syscall_trace_enter() returned
+ * We don't reload %rax because syscall_trace_entry_phase2() returned
* the value it wants us to use in the table lookup.
*/
LOAD_ARGS ARGOFFSET, 1
--
1.9.3
^ permalink raw reply related
* [PATCH v3 7/8] x86_64, entry: Treat regs->ax the same in fastpath and slowpath syscalls
From: Andy Lutomirski @ 2014-07-22 1:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2baeb5fad958c292705885941d61ab31771a75bb.1405992946.git.luto@amacapital.net>
For slowpath syscalls, we initialize regs->ax to -ENOSYS and stick
the syscall number into regs->orig_ax prior to any possible tracing
and syscall execution. This is user-visible ABI used by ptrace
syscall emulation and seccomp.
For fastpath syscalls, there's no good reason not to do the same
thing. It's even slightly simpler than what we're currently doing.
It probably has no measureable performance impact. It should have
no user-visible effect.
The purpose of this patch is to prepare for two-phase syscall
tracing, in which the first phase might modify the saved RAX without
leaving the fast path. This change is just subtle enough that I'm
keeping it separate.
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
arch/x86/include/asm/calling.h | 6 +++++-
arch/x86/kernel/entry_64.S | 13 ++++---------
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/arch/x86/include/asm/calling.h b/arch/x86/include/asm/calling.h
index cb4c73b..76659b6 100644
--- a/arch/x86/include/asm/calling.h
+++ b/arch/x86/include/asm/calling.h
@@ -85,7 +85,7 @@ For 32-bit we have the following conventions - kernel is built with
#define ARGOFFSET R11
#define SWFRAME ORIG_RAX
- .macro SAVE_ARGS addskip=0, save_rcx=1, save_r891011=1
+ .macro SAVE_ARGS addskip=0, save_rcx=1, save_r891011=1, rax_enosys=0
subq $9*8+\addskip, %rsp
CFI_ADJUST_CFA_OFFSET 9*8+\addskip
movq_cfi rdi, 8*8
@@ -96,7 +96,11 @@ For 32-bit we have the following conventions - kernel is built with
movq_cfi rcx, 5*8
.endif
+ .if \rax_enosys
+ movq $-ENOSYS, 4*8(%rsp)
+ .else
movq_cfi rax, 4*8
+ .endif
.if \save_r891011
movq_cfi r8, 3*8
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index b25ca96..1eb3094 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -405,8 +405,8 @@ GLOBAL(system_call_after_swapgs)
* and short:
*/
ENABLE_INTERRUPTS(CLBR_NONE)
- SAVE_ARGS 8,0
- movq %rax,ORIG_RAX-ARGOFFSET(%rsp)
+ SAVE_ARGS 8, 0, rax_enosys=1
+ movq_cfi rax,(ORIG_RAX-ARGOFFSET)
movq %rcx,RIP-ARGOFFSET(%rsp)
CFI_REL_OFFSET rip,RIP-ARGOFFSET
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
@@ -418,7 +418,7 @@ system_call_fastpath:
andl $__SYSCALL_MASK,%eax
cmpl $__NR_syscall_max,%eax
#endif
- ja badsys
+ ja ret_from_sys_call /* and return regs->ax */
movq %r10,%rcx
call *sys_call_table(,%rax,8) # XXX: rip relative
movq %rax,RAX-ARGOFFSET(%rsp)
@@ -477,10 +477,6 @@ sysret_signal:
FIXUP_TOP_OF_STACK %r11, -ARGOFFSET
jmp int_check_syscall_exit_work
-badsys:
- movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
- jmp ret_from_sys_call
-
#ifdef CONFIG_AUDITSYSCALL
/*
* Fast path for syscall audit without full syscall trace.
@@ -520,7 +516,6 @@ tracesys:
jz auditsys
#endif
SAVE_REST
- movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
FIXUP_TOP_OF_STACK %rdi
movq %rsp,%rdi
call syscall_trace_enter
@@ -537,7 +532,7 @@ tracesys:
andl $__SYSCALL_MASK,%eax
cmpl $__NR_syscall_max,%eax
#endif
- ja int_ret_from_sys_call /* RAX(%rsp) set to -ENOSYS above */
+ ja int_ret_from_sys_call /* RAX(%rsp) is already set */
movq %r10,%rcx /* fixup for C */
call *sys_call_table(,%rax,8)
movq %rax,RAX-ARGOFFSET(%rsp)
--
1.9.3
^ permalink raw reply related
* [PATCH v3 6/8] x86: Split syscall_trace_enter into two phases
From: Andy Lutomirski @ 2014-07-22 1:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2baeb5fad958c292705885941d61ab31771a75bb.1405992946.git.luto@amacapital.net>
This splits syscall_trace_enter into syscall_trace_enter_phase1 and
syscall_trace_enter_phase2. Only phase 2 has full pt_regs, and only
phase 2 is permitted to modify any of pt_regs except for orig_ax.
The intent is that phase 1 can be called from the syscall fast path.
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
arch/x86/include/asm/ptrace.h | 5 ++
arch/x86/kernel/ptrace.c | 145 ++++++++++++++++++++++++++++++++++++------
2 files changed, 131 insertions(+), 19 deletions(-)
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 6205f0c..86fc2bb 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -75,6 +75,11 @@ convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
int error_code, int si_code);
+
+extern unsigned long syscall_trace_enter_phase1(struct pt_regs *, u32 arch);
+extern long syscall_trace_enter_phase2(struct pt_regs *, u32 arch,
+ unsigned long phase1_result);
+
extern long syscall_trace_enter(struct pt_regs *);
extern void syscall_trace_leave(struct pt_regs *);
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 39296d2..9ec6972 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1441,13 +1441,117 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
force_sig_info(SIGTRAP, &info, tsk);
}
+static void do_audit_syscall_entry(struct pt_regs *regs, u32 arch)
+{
+#ifdef CONFIG_X86_64
+ if (arch == AUDIT_ARCH_X86_64) {
+ audit_syscall_entry(arch, regs->orig_ax, regs->di,
+ regs->si, regs->dx, regs->r10);
+ } else
+#endif
+ {
+ audit_syscall_entry(arch, regs->orig_ax, regs->bx,
+ regs->cx, regs->dx, regs->si);
+ }
+}
+
/*
- * We must return the syscall number to actually look up in the table.
- * This can be -1L to skip running any syscall at all.
+ * We can return 0 to resume the syscall or anything else to go to phase
+ * 2. If we resume the syscall, we need to put something appropriate in
+ * regs->orig_ax.
+ *
+ * NB: We don't have full pt_regs here, but regs->orig_ax and regs->ax
+ * are fully functional.
+ *
+ * For phase 2's benefit, our return value is:
+ * 0: resume the syscall
+ * 1: go to phase 2; no seccomp phase 2 needed
+ * 2: go to phase 2; pass return value to seccomp
*/
-long syscall_trace_enter(struct pt_regs *regs)
+unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch)
+{
+ unsigned long ret = 0;
+ u32 work;
+
+ BUG_ON(regs != task_pt_regs(current));
+
+ work = ACCESS_ONCE(current_thread_info()->flags) &
+ _TIF_WORK_SYSCALL_ENTRY;
+
+#ifdef CONFIG_SECCOMP
+ /*
+ * Do seccomp first -- it should minimize exposure of other
+ * code, and keeping seccomp fast is probably more valuable
+ * than the rest of this.
+ */
+ if (work & _TIF_SECCOMP) {
+ struct seccomp_data sd;
+
+ sd.arch = arch;
+ sd.nr = regs->orig_ax;
+ sd.instruction_pointer = regs->ip;
+#ifdef CONFIG_X86_64
+ if (arch == AUDIT_ARCH_X86_64) {
+ sd.args[0] = regs->di;
+ sd.args[1] = regs->si;
+ sd.args[2] = regs->dx;
+ sd.args[3] = regs->r10;
+ sd.args[4] = regs->r8;
+ sd.args[5] = regs->r9;
+ } else
+#endif
+ {
+ sd.args[0] = regs->bx;
+ sd.args[1] = regs->cx;
+ sd.args[2] = regs->dx;
+ sd.args[3] = regs->si;
+ sd.args[4] = regs->di;
+ sd.args[5] = regs->bp;
+ }
+
+ BUILD_BUG_ON(SECCOMP_PHASE1_OK != 0);
+ BUILD_BUG_ON(SECCOMP_PHASE1_SKIP != 1);
+
+ ret = seccomp_phase1(&sd);
+ if (ret == SECCOMP_PHASE1_SKIP) {
+ regs->orig_ax = -1;
+ ret = 0;
+ } else if (ret != SECCOMP_PHASE1_OK) {
+ return ret; /* Go directly to phase 2 */
+ }
+
+ work &= ~_TIF_SECCOMP;
+ }
+#endif
+
+ /* Do our best to finish without phase 2. */
+ if (work == 0)
+ return ret; /* seccomp only (ret == 0 here) */
+
+#ifdef CONFIG_AUDITSYSCALL
+ if (work == _TIF_SYSCALL_AUDIT) {
+ /*
+ * If there is no more work to be done except auditing,
+ * then audit in phase 1. Phase 2 always audits, so, if
+ * we audit here, then we can't go on to phase 2.
+ */
+ do_audit_syscall_entry(regs, arch);
+ return 0;
+ }
+#endif
+
+ return 1; /* Something is enabled that we can't handle in phase 1 */
+}
+
+/* Returns the syscall nr to run (which should match regs->orig_ax). */
+long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch,
+ unsigned long phase1_result)
{
long ret = 0;
+ u32 work = ACCESS_ONCE(current_thread_info()->flags) &
+ _TIF_WORK_SYSCALL_ENTRY;
+
+ BUG_ON(regs != task_pt_regs(current));
user_exit();
@@ -1458,17 +1562,20 @@ long syscall_trace_enter(struct pt_regs *regs)
* do_debug() and we need to set it again to restore the user
* state. If we entered on the slow path, TF was already set.
*/
- if (test_thread_flag(TIF_SINGLESTEP))
+ if (work & _TIF_SINGLESTEP)
regs->flags |= X86_EFLAGS_TF;
- /* do the secure computing check first */
- if (secure_computing()) {
+ /*
+ * Call seccomp_phase2 before running the other hooks so that
+ * they can see any changes made by a seccomp tracer.
+ */
+ if (phase1_result > 1 && seccomp_phase2(phase1_result)) {
/* seccomp failures shouldn't expose any additional code. */
ret = -1L;
goto out;
}
- if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
+ if (unlikely(work & _TIF_SYSCALL_EMU))
ret = -1L;
if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) &&
@@ -1478,23 +1585,23 @@ long syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->orig_ax);
- if (is_ia32_task())
- audit_syscall_entry(AUDIT_ARCH_I386,
- regs->orig_ax,
- regs->bx, regs->cx,
- regs->dx, regs->si);
-#ifdef CONFIG_X86_64
- else
- audit_syscall_entry(AUDIT_ARCH_X86_64,
- regs->orig_ax,
- regs->di, regs->si,
- regs->dx, regs->r10);
-#endif
+ do_audit_syscall_entry(regs, arch);
out:
return ret ?: regs->orig_ax;
}
+long syscall_trace_enter(struct pt_regs *regs)
+{
+ u32 arch = is_ia32_task() ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
+ unsigned long phase1_result = syscall_trace_enter_phase1(regs, arch);
+
+ if (phase1_result == 0)
+ return regs->orig_ax;
+ else
+ return syscall_trace_enter_phase2(regs, arch, phase1_result);
+}
+
void syscall_trace_leave(struct pt_regs *regs)
{
bool step;
--
1.9.3
^ permalink raw reply related
* [PATCH v3 5/8] x86,x32,audit: Fix x32's AUDIT_ARCH wrt audit
From: Andy Lutomirski @ 2014-07-22 1:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1405992946.git.luto@amacapital.net>
is_compat_task() is the wrong check for audit arch; the check should
be is_ia32_task(): x32 syscalls should be AUDIT_ARCH_X86_64, not
AUDIT_ARCH_I386.
CONFIG_AUDITSYSCALL is currently incompatible with x32, so this has
no visible effect.
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
arch/x86/kernel/ptrace.c | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 93c182a..39296d2 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1441,15 +1441,6 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
force_sig_info(SIGTRAP, &info, tsk);
}
-
-#ifdef CONFIG_X86_32
-# define IS_IA32 1
-#elif defined CONFIG_IA32_EMULATION
-# define IS_IA32 is_compat_task()
-#else
-# define IS_IA32 0
-#endif
-
/*
* We must return the syscall number to actually look up in the table.
* This can be -1L to skip running any syscall at all.
@@ -1487,7 +1478,7 @@ long syscall_trace_enter(struct pt_regs *regs)
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->orig_ax);
- if (IS_IA32)
+ if (is_ia32_task())
audit_syscall_entry(AUDIT_ARCH_I386,
regs->orig_ax,
regs->bx, regs->cx,
--
1.9.3
^ permalink raw reply related
* [PATCH 4/6] chipidea: usbmisc_imx: Add USB support for VF610 SoCs
From: Peter Chen @ 2014-07-22 1:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <e776c8a6ea0d919edb5e3ce1bf0697b23f09f028.1405702442.git.stefan@agner.ch>
On Fri, Jul 18, 2014 at 07:01:40PM +0200, Stefan Agner wrote:
> This adds Vybrid VF610 SoC support. The IP is very similar to i.MX6,
> however the non-core registers are spread in two different register
> areas. Hence we support multiple registers which are addressed by
> the index of usbmisc.
>
> Signed-off-by: Stefan Agner <stefan@agner.ch>
> ---
> I tried first to create two usbmisc nodes and hoped it would instanciate
> the driver twice, however, the driver currently only supports one instance.
> In an short attempt to add support for that, I realized that since the
> data structure holding the information for each instance is within the
> driver ci_hdrc_imx. For Vybrid two instances would make much more sense,
> however, a i.MX6Q shares all the non-core registers in one register area,
> hence only one driver can map this area. I ended up with this multiple
> registers solution, altough for the Vybrid multiple instances would
> probably make more sense. Any thoughts on this?
>
I prefer rename current usbmisc_imx as usbmisc_mix_v1 and create the
new usbmisc_imx_v2 for multiple instances case.
Peter
> drivers/usb/chipidea/usbmisc_imx.c | 76 +++++++++++++++++++++++++++-----------
> 1 file changed, 54 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
> index 85293b8..61c2350 100644
> --- a/drivers/usb/chipidea/usbmisc_imx.c
> +++ b/drivers/usb/chipidea/usbmisc_imx.c
> @@ -57,6 +57,10 @@
>
> #define MX6_BM_OVER_CUR_DIS BIT(7)
>
> +#define VF610_OVER_CUR_DIS BIT(7)
> +
> +#define MAX_BASE_ADDR 2
> +
> struct usbmisc_ops {
> /* It's called once when probe a usb device */
> int (*init)(struct imx_usbmisc_data *data);
> @@ -65,7 +69,7 @@ struct usbmisc_ops {
> };
>
> struct imx_usbmisc {
> - void __iomem *base;
> + void __iomem *base[MAX_BASE_ADDR];
> spinlock_t lock;
> struct clk *clk;
> const struct usbmisc_ops *ops;
> @@ -84,20 +88,20 @@ static int usbmisc_imx25_init(struct imx_usbmisc_data *data)
> spin_lock_irqsave(&usbmisc->lock, flags);
> switch (data->index) {
> case 0:
> - val = readl(usbmisc->base);
> + val = readl(usbmisc->base[0]);
> val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT);
> val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT;
> val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT);
> - writel(val, usbmisc->base);
> + writel(val, usbmisc->base[0]);
> break;
> case 1:
> - val = readl(usbmisc->base);
> + val = readl(usbmisc->base[0]);
> val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT | MX25_H1_IPPUE_UP_BIT);
> val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT;
> val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT |
> MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT);
>
> - writel(val, usbmisc->base);
> + writel(val, usbmisc->base[0]);
>
> break;
> }
> @@ -115,7 +119,7 @@ static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
> if (data->index > 2)
> return -EINVAL;
>
> - reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
> + reg = usbmisc->base[0] + MX25_USB_PHY_CTRL_OFFSET;
>
> if (data->evdo) {
> spin_lock_irqsave(&usbmisc->lock, flags);
> @@ -149,10 +153,10 @@ static int usbmisc_imx27_init(struct imx_usbmisc_data *data)
>
> spin_lock_irqsave(&usbmisc->lock, flags);
> if (data->disable_oc)
> - val = readl(usbmisc->base) | val;
> + val = readl(usbmisc->base[0]) | val;
> else
> - val = readl(usbmisc->base) & ~val;
> - writel(val, usbmisc->base);
> + val = readl(usbmisc->base[0]) & ~val;
> + writel(val, usbmisc->base[0]);
> spin_unlock_irqrestore(&usbmisc->lock, flags);
>
> return 0;
> @@ -168,29 +172,29 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
> return -EINVAL;
>
> /* Select a 24 MHz reference clock for the PHY */
> - reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET;
> + reg = usbmisc->base[0] + MX53_USB_OTG_PHY_CTRL_1_OFFSET;
> val = readl(reg);
> val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK;
> val |= MX53_USB_PLL_DIV_24_MHZ;
> - writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
> + writel(val, usbmisc->base[0] + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
>
> if (data->disable_oc) {
> spin_lock_irqsave(&usbmisc->lock, flags);
> switch (data->index) {
> case 0:
> - reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
> + reg = usbmisc->base[0] + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
> val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
> break;
> case 1:
> - reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
> + reg = usbmisc->base[0] + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
> val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
> break;
> case 2:
> - reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
> + reg = usbmisc->base[0] + MX53_USB_UH2_CTRL_OFFSET;
> val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
> break;
> case 3:
> - reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
> + reg = usbmisc->base[0] + MX53_USB_UH3_CTRL_OFFSET;
> val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
> break;
> }
> @@ -212,15 +216,31 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
>
> if (data->disable_oc) {
> spin_lock_irqsave(&usbmisc->lock, flags);
> - reg = readl(usbmisc->base + data->index * 4);
> + reg = readl(usbmisc->base[0] + data->index * 4);
> writel(reg | MX6_BM_OVER_CUR_DIS,
> - usbmisc->base + data->index * 4);
> + usbmisc->base[0] + data->index * 4);
> spin_unlock_irqrestore(&usbmisc->lock, flags);
> }
>
> return 0;
> }
>
> +static int usbmisc_vf610_init(struct imx_usbmisc_data *data)
> +{
> + u32 reg;
> +
> + if (data->index >= 2)
> + return -EINVAL;
> +
> + if (data->disable_oc) {
> + reg = readl(usbmisc->base[data->index]);
> + writel(reg | VF610_OVER_CUR_DIS,
> + usbmisc->base[data->index]);
> + }
> +
> + return 0;
> +}
> +
> static const struct usbmisc_ops imx25_usbmisc_ops = {
> .init = usbmisc_imx25_init,
> .post = usbmisc_imx25_post,
> @@ -238,6 +258,10 @@ static const struct usbmisc_ops imx6q_usbmisc_ops = {
> .init = usbmisc_imx6q_init,
> };
>
> +static const struct usbmisc_ops vf610_usbmisc_ops = {
> + .init = usbmisc_vf610_init,
> +};
> +
> int imx_usbmisc_init(struct imx_usbmisc_data *data)
> {
> if (!usbmisc)
> @@ -283,6 +307,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
> .compatible = "fsl,imx6q-usbmisc",
> .data = &imx6q_usbmisc_ops,
> },
> + {
> + .compatible = "fsl,vf610-usbmisc",
> + .data = &vf610_usbmisc_ops,
> + },
> { /* sentinel */ }
> };
> MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
> @@ -291,7 +319,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
> {
> struct resource *res;
> struct imx_usbmisc *data;
> - int ret;
> + int ret, i;
> struct of_device_id *tmp_dev;
>
> if (usbmisc)
> @@ -303,10 +331,14 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
>
> spin_lock_init(&data->lock);
>
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - data->base = devm_ioremap_resource(&pdev->dev, res);
> - if (IS_ERR(data->base))
> - return PTR_ERR(data->base);
> + for (i = 0; i < MAX_BASE_ADDR; i++) {
> + res = platform_get_resource(pdev, IORESOURCE_MEM, i);
> + data->base[i] = devm_ioremap_resource(&pdev->dev, res);
> +
> + /* First base address is mandatory */
> + if (IS_ERR(data->base) && !i)
> + return PTR_ERR(data->base);
> + }
>
> data->clk = devm_clk_get(&pdev->dev, NULL);
> if (IS_ERR(data->clk)) {
> --
> 2.0.1
>
--
Best Regards,
Peter Chen
^ permalink raw reply
* [PATCH v3 4/8] seccomp: Document two-phase seccomp and arch-provided seccomp_data
From: Andy Lutomirski @ 2014-07-22 1:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1405992946.git.luto@amacapital.net>
The description of how archs should implement seccomp filters was
still strictly correct, but it failed to describe the newly
available optimizations.
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
arch/Kconfig | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/Kconfig b/arch/Kconfig
index 0eae9df..05d7a8a 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -323,6 +323,17 @@ config HAVE_ARCH_SECCOMP_FILTER
results in the system call being skipped immediately.
- seccomp syscall wired up
+ For best performance, an arch should use seccomp_phase1 and
+ seccomp_phase2 directly. It should call seccomp_phase1 for all
+ syscalls if TIF_SECCOMP is set, but seccomp_phase1 does not
+ need to be called from a ptrace-safe context. It must then
+ call seccomp_phase2 if seccomp_phase1 returns anything other
+ than SECCOMP_PHASE1_OK or SECCOMP_PHASE1_SKIP.
+
+ As an additional optimization, an arch may provide seccomp_data
+ directly to seccomp_phase1; this avoids multiple calls
+ to the syscall_xyz helpers for every syscall.
+
config SECCOMP_FILTER
def_bool y
depends on HAVE_ARCH_SECCOMP_FILTER && SECCOMP && NET
--
1.9.3
^ permalink raw reply related
* [PATCH v3 3/8] seccomp: Allow arch code to provide seccomp_data
From: Andy Lutomirski @ 2014-07-22 1:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1405992946.git.luto@amacapital.net>
populate_seccomp_data is expensive: it works by inspecting
task_pt_regs and various other bits to piece together all the
information, and it's does so in multiple partially redundant steps.
Arch-specific code in the syscall entry path can do much better.
Admittedly this adds a bit of additional room for error, but the
speedup should be worth it.
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
include/linux/seccomp.h | 2 +-
kernel/seccomp.c | 32 +++++++++++++++++++-------------
2 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index 3885108..a19ddac 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -39,7 +39,7 @@ static inline int secure_computing(void)
#define SECCOMP_PHASE1_OK 0
#define SECCOMP_PHASE1_SKIP 1
-extern u32 seccomp_phase1(void);
+extern u32 seccomp_phase1(struct seccomp_data *sd);
int seccomp_phase2(u32 phase1_result);
#else
extern void secure_computing_strict(int this_syscall);
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 0088d29..80115b0 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -173,10 +173,10 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
*
* Returns valid seccomp BPF response codes.
*/
-static u32 seccomp_run_filters(void)
+static u32 seccomp_run_filters(struct seccomp_data *sd)
{
struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter);
- struct seccomp_data sd;
+ struct seccomp_data sd_local;
u32 ret = SECCOMP_RET_ALLOW;
/* Ensure unexpected behavior doesn't result in failing open. */
@@ -186,14 +186,17 @@ static u32 seccomp_run_filters(void)
/* Make sure cross-thread synced filter points somewhere sane. */
smp_read_barrier_depends();
- populate_seccomp_data(&sd);
+ if (!sd) {
+ populate_seccomp_data(&sd_local);
+ sd = &sd_local;
+ }
/*
* All filters in the list are evaluated and the lowest BPF return
* value always takes priority (ignoring the DATA).
*/
for (; f; f = f->prev) {
- u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd);
+ u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)sd);
if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
ret = cur_ret;
@@ -599,7 +602,7 @@ void secure_computing_strict(int this_syscall)
#else
int __secure_computing(void)
{
- u32 phase1_result = seccomp_phase1();
+ u32 phase1_result = seccomp_phase1(NULL);
if (likely(phase1_result == SECCOMP_PHASE1_OK))
return 0;
@@ -610,7 +613,7 @@ int __secure_computing(void)
}
#ifdef CONFIG_SECCOMP_FILTER
-static u32 __seccomp_phase1_filter(int this_syscall, struct pt_regs *regs)
+static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd)
{
u32 filter_ret, action;
int data;
@@ -621,20 +624,20 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct pt_regs *regs)
*/
rmb();
- filter_ret = seccomp_run_filters();
+ filter_ret = seccomp_run_filters(sd);
data = filter_ret & SECCOMP_RET_DATA;
action = filter_ret & SECCOMP_RET_ACTION;
switch (action) {
case SECCOMP_RET_ERRNO:
/* Set the low-order 16-bits as a errno. */
- syscall_set_return_value(current, regs,
+ syscall_set_return_value(current, task_pt_regs(current),
-data, 0);
goto skip;
case SECCOMP_RET_TRAP:
/* Show the handler the original registers. */
- syscall_rollback(current, regs);
+ syscall_rollback(current, task_pt_regs(current));
/* Let the filter pass back 16 bits of data. */
seccomp_send_sigsys(this_syscall, data);
goto skip;
@@ -661,11 +664,14 @@ skip:
/**
* seccomp_phase1() - run fast path seccomp checks on the current syscall
+ * @arg sd: The seccomp_data or NULL
*
* This only reads pt_regs via the syscall_xyz helpers. The only change
* it will make to pt_regs is via syscall_set_return_value, and it will
* only do that if it returns SECCOMP_PHASE1_SKIP.
*
+ * If sd is provided, it will not read pt_regs@all.
+ *
* It may also call do_exit or force a signal; these actions must be
* safe.
*
@@ -679,11 +685,11 @@ skip:
* If it returns anything else, then the return value should be passed
* to seccomp_phase2 from a context in which ptrace hooks are safe.
*/
-u32 seccomp_phase1(void)
+u32 seccomp_phase1(struct seccomp_data *sd)
{
int mode = current->seccomp.mode;
- struct pt_regs *regs = task_pt_regs(current);
- int this_syscall = syscall_get_nr(current, regs);
+ int this_syscall = sd ? sd->nr :
+ syscall_get_nr(current, task_pt_regs(current));
switch (mode) {
case SECCOMP_MODE_STRICT:
@@ -691,7 +697,7 @@ u32 seccomp_phase1(void)
return SECCOMP_PHASE1_OK;
#ifdef CONFIG_SECCOMP_FILTER
case SECCOMP_MODE_FILTER:
- return __seccomp_phase1_filter(this_syscall, regs);
+ return __seccomp_phase1_filter(this_syscall, sd);
#endif
default:
BUG();
--
1.9.3
^ permalink raw reply related
* [PATCH v3 2/8] seccomp: Refactor the filter callback and the API
From: Andy Lutomirski @ 2014-07-22 1:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1405992946.git.luto@amacapital.net>
The reason I did this is to add a seccomp API that will be usable
for an x86 fast path. The x86 entry code needs to use a rather
expensive slow path for a syscall that might be visible to things
like ptrace. By splitting seccomp into two phases, we can check
whether we need the slow path and then use the fast path in if the
filter allows the syscall or just returns some errno.
As a side effect, I think the new code is much easier to understand
than the old code.
This has one user-visible effect: the audit record written for
SECCOMP_RET_TRACE is now a simple indication that SECCOMP_RET_TRACE
happened. It used to depend in a complicated way on what the tracer
did. I couldn't make much sense of it.
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
include/linux/seccomp.h | 6 ++
kernel/seccomp.c | 190 +++++++++++++++++++++++++++++++-----------------
2 files changed, 130 insertions(+), 66 deletions(-)
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index aa3c040..3885108 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -35,6 +35,12 @@ static inline int secure_computing(void)
return __secure_computing();
return 0;
}
+
+#define SECCOMP_PHASE1_OK 0
+#define SECCOMP_PHASE1_SKIP 1
+
+extern u32 seccomp_phase1(void);
+int seccomp_phase2(u32 phase1_result);
#else
extern void secure_computing_strict(int this_syscall);
#endif
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 861d7ee..0088d29 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -21,8 +21,6 @@
#include <linux/slab.h>
#include <linux/syscalls.h>
-/* #define SECCOMP_DEBUG 1 */
-
#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
#include <asm/syscall.h>
#endif
@@ -601,10 +599,21 @@ void secure_computing_strict(int this_syscall)
#else
int __secure_computing(void)
{
- struct pt_regs *regs = task_pt_regs(current);
- int this_syscall = syscall_get_nr(current, regs);
- int exit_sig = 0;
- u32 ret;
+ u32 phase1_result = seccomp_phase1();
+
+ if (likely(phase1_result == SECCOMP_PHASE1_OK))
+ return 0;
+ else if (likely(phase1_result == SECCOMP_PHASE1_SKIP))
+ return -1;
+ else
+ return seccomp_phase2(phase1_result);
+}
+
+#ifdef CONFIG_SECCOMP_FILTER
+static u32 __seccomp_phase1_filter(int this_syscall, struct pt_regs *regs)
+{
+ u32 filter_ret, action;
+ int data;
/*
* Make sure that any changes to mode from another thread have
@@ -612,73 +621,122 @@ int __secure_computing(void)
*/
rmb();
- switch (current->seccomp.mode) {
+ filter_ret = seccomp_run_filters();
+ data = filter_ret & SECCOMP_RET_DATA;
+ action = filter_ret & SECCOMP_RET_ACTION;
+
+ switch (action) {
+ case SECCOMP_RET_ERRNO:
+ /* Set the low-order 16-bits as a errno. */
+ syscall_set_return_value(current, regs,
+ -data, 0);
+ goto skip;
+
+ case SECCOMP_RET_TRAP:
+ /* Show the handler the original registers. */
+ syscall_rollback(current, regs);
+ /* Let the filter pass back 16 bits of data. */
+ seccomp_send_sigsys(this_syscall, data);
+ goto skip;
+
+ case SECCOMP_RET_TRACE:
+ return filter_ret; /* Save the rest for phase 2. */
+
+ case SECCOMP_RET_ALLOW:
+ return SECCOMP_PHASE1_OK;
+
+ case SECCOMP_RET_KILL:
+ default:
+ audit_seccomp(this_syscall, SIGSYS, action);
+ do_exit(SIGSYS);
+ }
+
+ unreachable();
+
+skip:
+ audit_seccomp(this_syscall, 0, action);
+ return SECCOMP_PHASE1_SKIP;
+}
+#endif
+
+/**
+ * seccomp_phase1() - run fast path seccomp checks on the current syscall
+ *
+ * This only reads pt_regs via the syscall_xyz helpers. The only change
+ * it will make to pt_regs is via syscall_set_return_value, and it will
+ * only do that if it returns SECCOMP_PHASE1_SKIP.
+ *
+ * It may also call do_exit or force a signal; these actions must be
+ * safe.
+ *
+ * If it returns SECCOMP_PHASE1_OK, the syscall passes checks and should
+ * be processed normally.
+ *
+ * If it returns SECCOMP_PHASE1_SKIP, then the syscall should not be
+ * invoked. In this case, seccomp_phase1 will have set the return value
+ * using syscall_set_return_value.
+ *
+ * If it returns anything else, then the return value should be passed
+ * to seccomp_phase2 from a context in which ptrace hooks are safe.
+ */
+u32 seccomp_phase1(void)
+{
+ int mode = current->seccomp.mode;
+ struct pt_regs *regs = task_pt_regs(current);
+ int this_syscall = syscall_get_nr(current, regs);
+
+ switch (mode) {
case SECCOMP_MODE_STRICT:
- __secure_computing_strict(this_syscall);
- return 0;
+ __secure_computing_strict(this_syscall); /* may call do_exit */
+ return SECCOMP_PHASE1_OK;
#ifdef CONFIG_SECCOMP_FILTER
- case SECCOMP_MODE_FILTER: {
- int data;
- ret = seccomp_run_filters();
- data = ret & SECCOMP_RET_DATA;
- ret &= SECCOMP_RET_ACTION;
- switch (ret) {
- case SECCOMP_RET_ERRNO:
- /* Set the low-order 16-bits as a errno. */
- syscall_set_return_value(current, regs,
- -data, 0);
- goto skip;
- case SECCOMP_RET_TRAP:
- /* Show the handler the original registers. */
- syscall_rollback(current, regs);
- /* Let the filter pass back 16 bits of data. */
- seccomp_send_sigsys(this_syscall, data);
- goto skip;
- case SECCOMP_RET_TRACE:
- /* Skip these calls if there is no tracer. */
- if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
- syscall_set_return_value(current, regs,
- -ENOSYS, 0);
- goto skip;
- }
- /* Allow the BPF to provide the event message */
- ptrace_event(PTRACE_EVENT_SECCOMP, data);
- /*
- * The delivery of a fatal signal during event
- * notification may silently skip tracer notification.
- * Terminating the task now avoids executing a system
- * call that may not be intended.
- */
- if (fatal_signal_pending(current))
- break;
- if (syscall_get_nr(current, regs) < 0)
- goto skip; /* Explicit request to skip. */
-
- return 0;
- case SECCOMP_RET_ALLOW:
- return 0;
- case SECCOMP_RET_KILL:
- default:
- break;
- }
- exit_sig = SIGSYS;
- break;
- }
+ case SECCOMP_MODE_FILTER:
+ return __seccomp_phase1_filter(this_syscall, regs);
#endif
default:
BUG();
}
+}
-#ifdef SECCOMP_DEBUG
- dump_stack();
-#endif
- audit_seccomp(this_syscall, exit_sig, ret);
- do_exit(exit_sig);
-#ifdef CONFIG_SECCOMP_FILTER
-skip:
- audit_seccomp(this_syscall, exit_sig, ret);
- return -1;
-#endif
+/**
+ * seccomp_phase2() - finish slow path seccomp work for the current syscall
+ * @phase1_result: The return value from seccomp_phase1()
+ *
+ * This must be called from a context in which ptrace hooks can be used.
+ *
+ * Returns 0 if the syscall should be processed or -1 to skip the syscall.
+ */
+int seccomp_phase2(u32 phase1_result)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ u32 action = phase1_result & SECCOMP_RET_ACTION;
+ int data = phase1_result & SECCOMP_RET_DATA;
+
+ BUG_ON(action != SECCOMP_RET_TRACE);
+
+ audit_seccomp(syscall_get_nr(current, regs), 0, action);
+
+ /* Skip these calls if there is no tracer. */
+ if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
+ syscall_set_return_value(current, regs,
+ -ENOSYS, 0);
+ return -1;
+ }
+
+ /* Allow the BPF to provide the event message */
+ ptrace_event(PTRACE_EVENT_SECCOMP, data);
+ /*
+ * The delivery of a fatal signal during event
+ * notification may silently skip tracer notification.
+ * Terminating the task now avoids executing a system
+ * call that may not be intended.
+ */
+ if (fatal_signal_pending(current))
+ do_exit(SIGSYS);
+ if (syscall_get_nr(current, regs) < 0)
+ return -1; /* Explicit request to skip. */
+
+ return 0;
}
#endif /* CONFIG_HAVE_ARCH_SECCOMP_FILTER */
--
1.9.3
^ permalink raw reply related
* [PATCH v3 1/8] seccomp, x86, arm, mips, s390: Remove nr parameter from secure_computing
From: Andy Lutomirski @ 2014-07-22 1:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1405992946.git.luto@amacapital.net>
The secure_computing function took a syscall number parameter, but
it only paid any attention to that parameter if seccomp mode 1 was
enabled. Rather than coming up with a kludge to get the parameter
to work in mode 2, just remove the parameter.
To avoid churn in arches that don't have seccomp filters (and may
not even support syscall_get_nr right now), this leaves the
parameter in secure_computing_strict, which is now a real function.
For ARM, this is a bit ugly due to the fact that ARM conditionally
supports seccomp filters. Fixing that would probably only be a
couple of lines of code, but it should be coordinated with the audit
maintainers.
This will be a slight slowdown on some arches. The right fix is to
pass in all of seccomp_data instead of trying to make just the
syscall nr part be fast.
This is a prerequisite for making two-phase seccomp work cleanly.
Cc: Russell King <linux@arm.linux.org.uk>
Cc: linux-arm-kernel at lists.infradead.org
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips at linux-mips.org
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: linux-s390 at vger.kernel.org
Cc: x86 at kernel.org
Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
arch/arm/kernel/ptrace.c | 7 ++++-
arch/mips/kernel/ptrace.c | 2 +-
arch/s390/kernel/ptrace.c | 2 +-
arch/x86/kernel/ptrace.c | 2 +-
arch/x86/kernel/vsyscall_64.c | 2 +-
include/linux/seccomp.h | 21 +++++++-------
kernel/seccomp.c | 64 ++++++++++++++++++++++++++++++-------------
7 files changed, 66 insertions(+), 34 deletions(-)
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 0c27ed6..5e772a2 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -933,8 +933,13 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
current_thread_info()->syscall = scno;
/* Do the secure computing check first; failures should be fast. */
- if (secure_computing(scno) == -1)
+#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
+ if (secure_computing() == -1)
return -1;
+#else
+ /* XXX: remove this once OABI gets fixed */
+ secure_computing_strict(scno);
+#endif
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index f639ccd..808bafc 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -639,7 +639,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
long ret = 0;
user_exit();
- if (secure_computing(syscall) == -1)
+ if (secure_computing() == -1)
return -1;
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 2d716734..7ab8b91 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -795,7 +795,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
long ret = 0;
/* Do the secure computing check first. */
- if (secure_computing(regs->gprs[2])) {
+ if (secure_computing()) {
/* seccomp failures shouldn't expose any additional code. */
ret = -1;
goto out;
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 678c0ad..93c182a 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1471,7 +1471,7 @@ long syscall_trace_enter(struct pt_regs *regs)
regs->flags |= X86_EFLAGS_TF;
/* do the secure computing check first */
- if (secure_computing(regs->orig_ax)) {
+ if (secure_computing()) {
/* seccomp failures shouldn't expose any additional code. */
ret = -1L;
goto out;
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index ea5b570..23c0c23 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -216,7 +216,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
*/
regs->orig_ax = syscall_nr;
regs->ax = -ENOSYS;
- tmp = secure_computing(syscall_nr);
+ tmp = secure_computing();
if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
warn_bad_vsyscall(KERN_DEBUG, regs,
"seccomp tried to change syscall nr or ip");
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index 5d586a4..aa3c040 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -27,19 +27,17 @@ struct seccomp {
struct seccomp_filter *filter;
};
-extern int __secure_computing(int);
-static inline int secure_computing(int this_syscall)
+#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
+extern int __secure_computing(void);
+static inline int secure_computing(void)
{
if (unlikely(test_thread_flag(TIF_SECCOMP)))
- return __secure_computing(this_syscall);
+ return __secure_computing();
return 0;
}
-
-/* A wrapper for architectures supporting only SECCOMP_MODE_STRICT. */
-static inline void secure_computing_strict(int this_syscall)
-{
- BUG_ON(secure_computing(this_syscall) != 0);
-}
+#else
+extern void secure_computing_strict(int this_syscall);
+#endif
extern long prctl_get_seccomp(void);
extern long prctl_set_seccomp(unsigned long, char __user *);
@@ -56,8 +54,11 @@ static inline int seccomp_mode(struct seccomp *s)
struct seccomp { };
struct seccomp_filter { };
-static inline int secure_computing(int this_syscall) { return 0; }
+#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
+static inline int secure_computing(void) { return 0; }
+#else
static inline void secure_computing_strict(int this_syscall) { return; }
+#endif
static inline long prctl_get_seccomp(void)
{
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 74f4601..861d7ee 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -23,8 +23,11 @@
/* #define SECCOMP_DEBUG 1 */
-#ifdef CONFIG_SECCOMP_FILTER
+#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
#include <asm/syscall.h>
+#endif
+
+#ifdef CONFIG_SECCOMP_FILTER
#include <linux/filter.h>
#include <linux/pid.h>
#include <linux/ptrace.h>
@@ -172,7 +175,7 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
*
* Returns valid seccomp BPF response codes.
*/
-static u32 seccomp_run_filters(int syscall)
+static u32 seccomp_run_filters(void)
{
struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter);
struct seccomp_data sd;
@@ -564,10 +567,43 @@ static int mode1_syscalls_32[] = {
};
#endif
-int __secure_computing(int this_syscall)
+static void __secure_computing_strict(int this_syscall)
+{
+ int *syscall_whitelist = mode1_syscalls;
+#ifdef CONFIG_COMPAT
+ if (is_compat_task())
+ syscall_whitelist = mode1_syscalls_32;
+#endif
+ do {
+ if (*syscall_whitelist == this_syscall)
+ return;
+ } while (*++syscall_whitelist);
+
+#ifdef SECCOMP_DEBUG
+ dump_stack();
+#endif
+ audit_seccomp(this_syscall, SIGKILL, SECCOMP_RET_KILL);
+ do_exit(SIGKILL);
+}
+
+#ifndef CONFIG_HAVE_ARCH_SECCOMP_FILTER
+void secure_computing_strict(int this_syscall)
+{
+ int mode = current->seccomp.mode;
+
+ if (mode == 0)
+ return;
+ else if (mode == SECCOMP_MODE_STRICT)
+ __secure_computing_strict(this_syscall);
+ else
+ BUG();
+}
+#else
+int __secure_computing(void)
{
+ struct pt_regs *regs = task_pt_regs(current);
+ int this_syscall = syscall_get_nr(current, regs);
int exit_sig = 0;
- int *syscall;
u32 ret;
/*
@@ -578,23 +614,12 @@ int __secure_computing(int this_syscall)
switch (current->seccomp.mode) {
case SECCOMP_MODE_STRICT:
- syscall = mode1_syscalls;
-#ifdef CONFIG_COMPAT
- if (is_compat_task())
- syscall = mode1_syscalls_32;
-#endif
- do {
- if (*syscall == this_syscall)
- return 0;
- } while (*++syscall);
- exit_sig = SIGKILL;
- ret = SECCOMP_RET_KILL;
- break;
+ __secure_computing_strict(this_syscall);
+ return 0;
#ifdef CONFIG_SECCOMP_FILTER
case SECCOMP_MODE_FILTER: {
int data;
- struct pt_regs *regs = task_pt_regs(current);
- ret = seccomp_run_filters(this_syscall);
+ ret = seccomp_run_filters();
data = ret & SECCOMP_RET_DATA;
ret &= SECCOMP_RET_ACTION;
switch (ret) {
@@ -652,9 +677,10 @@ int __secure_computing(int this_syscall)
#ifdef CONFIG_SECCOMP_FILTER
skip:
audit_seccomp(this_syscall, exit_sig, ret);
-#endif
return -1;
+#endif
}
+#endif /* CONFIG_HAVE_ARCH_SECCOMP_FILTER */
long prctl_get_seccomp(void)
{
--
1.9.3
^ permalink raw reply related
* [PATCH v3 0/8] Two-phase seccomp and x86 tracing changes
From: Andy Lutomirski @ 2014-07-22 1:49 UTC (permalink / raw)
To: linux-arm-kernel
[applies on jmorris's security-next tree]
This is both a cleanup and a speedup. It reduces overhead due to
installing a trivial seccomp filter by 87%. The speedup comes from
avoiding the full syscall tracing mechanism for filters that don't
return SECCOMP_RET_TRACE.
This series works by splitting the seccomp hooks into two phases.
The first phase evaluates the filter; it can skip syscalls, allow
them, kill the calling task, or pass a u32 to the second phase. The
second phase requires a full tracing context, and it sends ptrace
events if necessary.
Once this is done, I implemented a similar split for the x86 syscall
entry work. The C callback is invoked in two phases: the first has
only a partial frame, and it can request phase 2 processing with a
full frame.
Finally, I switch the 64-bit system_call code to use the new split
entry work. This is a net deletion of assembly code: it replaces
all of the audit entry muck.
In the process, I fixed some bugs.
If this is acceptable, someone can do the same tweak for the
ia32entry and entry_32 code.
This passes all seccomp tests that I know of. Now that it's properly
rebased, even the previously expected failures are gone.
Kees, if you like this version, can you create a branch with patches
1-4? I think that the rest should go into tip/x86 once everyone's happy
with it.
Changes from v2:
- Fixed 32-bit x86 build (and the tests pass).
- Put the doc patch where it belongs.
Changes from v1:
- Rebased on top of Kees' shiny new seccomp tree (no effect on the x86
part).
- Improved patch 6 vs patch 7 split (thanks Alexei!)
- Fixed bogus -ENOSYS in patch 5 (thanks Kees!)
- Improved changelog message in patch 6.
Changes from RFC version:
- The first three patches are more or less the same
- The rest is more or less a rewrite
Andy Lutomirski (8):
seccomp,x86,arm,mips,s390: Remove nr parameter from secure_computing
seccomp: Refactor the filter callback and the API
seccomp: Allow arch code to provide seccomp_data
seccomp: Document two-phase seccomp and arch-provided seccomp_data
x86,x32,audit: Fix x32's AUDIT_ARCH wrt audit
x86: Split syscall_trace_enter into two phases
x86_64,entry: Treat regs->ax the same in fastpath and slowpath
syscalls
x86_64,entry: Use split-phase syscall_trace_enter for 64-bit syscalls
arch/Kconfig | 11 ++
arch/arm/kernel/ptrace.c | 7 +-
arch/mips/kernel/ptrace.c | 2 +-
arch/s390/kernel/ptrace.c | 2 +-
arch/x86/include/asm/calling.h | 6 +-
arch/x86/include/asm/ptrace.h | 5 +
arch/x86/kernel/entry_64.S | 51 ++++-----
arch/x86/kernel/ptrace.c | 150 +++++++++++++++++++-----
arch/x86/kernel/vsyscall_64.c | 2 +-
include/linux/seccomp.h | 25 ++--
kernel/seccomp.c | 252 ++++++++++++++++++++++++++++-------------
11 files changed, 360 insertions(+), 153 deletions(-)
--
1.9.3
^ permalink raw reply
* [PATCH 5/6] usb: phy: mxs: Add VF610 USB PHY support
From: Peter Chen @ 2014-07-22 1:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <af194168fadd80c26f94da740f1e61ce6603225a.1405702442.git.stefan@agner.ch>
On Fri, Jul 18, 2014 at 07:01:41PM +0200, Stefan Agner wrote:
> This adds support for the USB PHY in Vybrid VF610. We assume that
> the disconnection without VBUS is also needed for Vybrid. For all
> other flags, the presumption of innocence applies.
>
> Signed-off-by: Stefan Agner <stefan@agner.ch>
> ---
> drivers/usb/phy/phy-mxs-usb.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
> index c42bdf0..207946b 100644
> --- a/drivers/usb/phy/phy-mxs-usb.c
> +++ b/drivers/usb/phy/phy-mxs-usb.c
> @@ -125,10 +125,15 @@ static const struct mxs_phy_data imx6sl_phy_data = {
> MXS_PHY_NEED_IP_FIX,
> };
>
> +static const struct mxs_phy_data vf610_phy_data = {
> + .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
> +};
> +
> static const struct of_device_id mxs_phy_dt_ids[] = {
> { .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
> { .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
> { .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
> + { .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, },
> { /* sentinel */ }
> };
> MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
> --
> 2.0.1
>
Acked-by: Peter Chen <peter.chen@freescale.com>
--
Best Regards,
Peter Chen
^ permalink raw reply
* [RFC V2] devicetree: Dialog Semiconductor consolidate existing vendor prefixes to standardise on 'dlg'
From: Shawn Guo @ 2014-07-22 1:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201407151520.s6FFKcjB009745@swsrvapps-01.diasemi.com>
On Tue, Jul 15, 2014 at 04:03:31PM +0100, Opensource [Steve Twiss] wrote:
> From: Opensource [Steve Twiss] <stwiss.opensource@diasemi.com>
>
> This patch series updates the device tree vendor prefix for
> Dialog Semiconductor.
>
> Various methods are currently used throughout the kernel: 'diasemi',
> 'dialog' and 'dlg'. Others have also been suggested.
>
> This patch set aims to consolidate the usage of the vendor prefix to
> use a common standard. The prefix 'dlg' is used.
...
> Signed-off-by: Opensource [Steve Twiss] <stwiss.opensource@diasemi.com>
...
> arch/arm/boot/dts/imx53-smd.dts | 2 +-
> arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi | 2 +-
Acked-by: Shawn Guo <shawn.guo@freescale.com>
^ permalink raw reply
* 答复: [PATCH resend v2] arm64: dmi: Add SMBIOS/DMI support
From: liyi 00215672 @ 2014-07-22 1:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140721084823.GA15666@arm.com>
Hi Will,
You need to add the SMBIOS support in UEFI on JUNO ,then you will get some proper information from DMI driver.
Thanks!
Yi
-----????-----
???: Will Deacon [mailto:will.deacon at arm.com]
????: 2014?7?21? 16:48
???: Ard Biesheuvel
??: Catalin Marinas; yi.li at linaro.org; liyi 00215672; grant.likely at linaro.org; leif.lindholm at linaro.org; linux-arm-kernel at lists.infradead.org; Mark Rutland
??: Re: [PATCH resend v2] arm64: dmi: Add SMBIOS/DMI support
On Sun, Jul 20, 2014 at 11:25:34AM +0100, Ard Biesheuvel wrote:
> On 14 July 2014 15:57, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> > On 14 July 2014 15:36, Will Deacon <will.deacon@arm.com> wrote:
> >> On Fri, Jul 11, 2014 at 12:46:50PM +0100, Ard Biesheuvel wrote:
> >>> From: Yi Li <yi.li@linaro.org>
> >>>
> >>> SMbios is important for server hardware vendors. It implements a spec for
> >>> providing descriptive information about the platform. Things like serial
> >>> numbers, physical layout of the ports, build configuration data, and the like.
> >>>
> >>> This has been tested by dmidecode and lshw tools.
> >>>
> >>> Signed-off-by: Yi Li <yi.li@linaro.org>
> >>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >>> ---
> >>> Changes since previous version:
> >>> - changed double inclusion guard to arm64 flavour
> >>> - use kzalloc(GFP_KERNEL) as GFP_ATOMIC is not needed
> >>> - do a sanity check on the size of the requested mapping
> >>
> >> Technically, this patch looks fine to me:
> >>
> >> Reviewed-by: Will Deacon <will.deacon@arm.com>
> >>
>
> Hello Catalin,
>
> This has been tested by Yi on FVP and Juno.
> Are you ok to take this?
Out of interest, how did you test it on Juno? I tried but got some messages
about missing/invalid DMI data or something similar. Leif reckons I need
some tricked out firmware for the FVP to get something working, but even
then the information is apparently bogus.
Will
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox